From e2ab9215d792d07cfb725de290f416e331b87627 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Fri, 12 Dec 2008 14:36:02 -0800 Subject: gPXE: update to the "kkpxe" branch Update gPXE to the "kkpxe" branch, an experimental branch of the gPXE tree which should let us eliminate the gpxelinux-specific hacks. Specifically, this corresponds to checkin 0963c883a9402bd5846e687a100e196f7e8a2ef7 of git://git.etherboot.org/scm/people/mcb30/gpxe.git. Signed-off-by: H. Peter Anvin --- gpxe/Makefile | 6 +- gpxe/VERSION | 2 +- gpxe/src/Makefile | 190 +- gpxe/src/Makefile.housekeeping | 438 +- gpxe/src/arch/i386/Config | 148 - gpxe/src/arch/i386/Makefile | 136 +- gpxe/src/arch/i386/Makefile.efi | 24 + gpxe/src/arch/i386/Makefile.pcbios | 55 + gpxe/src/arch/i386/core/gdbidt.S | 2 +- gpxe/src/arch/i386/core/gdbmach.c | 2 +- gpxe/src/arch/i386/core/i386_timer.c | 89 - gpxe/src/arch/i386/core/nap.c | 12 - gpxe/src/arch/i386/core/pcibios.c | 106 - gpxe/src/arch/i386/core/pcidirect.c | 8 +- gpxe/src/arch/i386/core/pic8259.c | 1 + gpxe/src/arch/i386/core/rdtsc_timer.c | 87 + gpxe/src/arch/i386/core/relocate.c | 10 +- gpxe/src/arch/i386/core/start32.S | 325 - gpxe/src/arch/i386/core/timer2.c | 85 + gpxe/src/arch/i386/core/umalloc.c | 224 - gpxe/src/arch/i386/core/video_subr.c | 2 +- gpxe/src/arch/i386/core/virtaddr.S | 2 +- gpxe/src/arch/i386/core/x86_io.c | 94 + gpxe/src/arch/i386/drivers/net/undinet.c | 66 +- gpxe/src/arch/i386/drivers/net/undionly.c | 18 + gpxe/src/arch/i386/drivers/timer_bios.c | 57 - gpxe/src/arch/i386/drivers/timer_rdtsc.c | 69 - gpxe/src/arch/i386/firmware/pcbios/e820mangler.S | 12 +- gpxe/src/arch/i386/firmware/pcbios/gateA20.c | 13 +- gpxe/src/arch/i386/firmware/pcbios/hidemem.c | 32 +- gpxe/src/arch/i386/firmware/pcbios/memmap.c | 20 +- .../arch/i386/firmware/pcbios/smbios_settings.c | 23 +- gpxe/src/arch/i386/image/multiboot.c | 6 +- gpxe/src/arch/i386/image/nbi.c | 7 +- gpxe/src/arch/i386/include/bios.h | 3 - gpxe/src/arch/i386/include/biosint.h | 15 +- gpxe/src/arch/i386/include/bits/errfile.h | 2 +- gpxe/src/arch/i386/include/bits/io.h | 12 + gpxe/src/arch/i386/include/bits/nap.h | 13 + gpxe/src/arch/i386/include/bits/pci_io.h | 13 + gpxe/src/arch/i386/include/bits/timer.h | 13 + gpxe/src/arch/i386/include/bits/timer2.h | 8 - gpxe/src/arch/i386/include/bits/uaccess.h | 8 +- gpxe/src/arch/i386/include/bits/umalloc.h | 12 + gpxe/src/arch/i386/include/gpxe/bios_nap.h | 16 + gpxe/src/arch/i386/include/gpxe/bios_timer.h | 42 + gpxe/src/arch/i386/include/gpxe/efi/efix86_nap.h | 16 + gpxe/src/arch/i386/include/gpxe/memtop_umalloc.h | 16 + gpxe/src/arch/i386/include/gpxe/pcibios.h | 133 + gpxe/src/arch/i386/include/gpxe/pcidirect.h | 139 + gpxe/src/arch/i386/include/gpxe/rdtsc_timer.h | 37 + gpxe/src/arch/i386/include/gpxe/timer2.h | 12 + gpxe/src/arch/i386/include/gpxe/x86_io.h | 151 + gpxe/src/arch/i386/include/int13.h | 1 + gpxe/src/arch/i386/include/io.h | 265 - gpxe/src/arch/i386/include/librm.h | 303 +- gpxe/src/arch/i386/include/pci_io.h | 35 - gpxe/src/arch/i386/include/pcibios.h | 122 - gpxe/src/arch/i386/include/pcidirect.h | 126 - gpxe/src/arch/i386/include/pxe_addr.h | 17 - gpxe/src/arch/i386/include/realmode.h | 93 +- gpxe/src/arch/i386/include/registers.h | 13 +- gpxe/src/arch/i386/include/undi.h | 10 +- gpxe/src/arch/i386/include/virtaddr.h | 105 - gpxe/src/arch/i386/interface/efi/efix86_nap.c | 46 + gpxe/src/arch/i386/interface/pcbios/bios_nap.c | 14 + gpxe/src/arch/i386/interface/pcbios/bios_timer.c | 63 + gpxe/src/arch/i386/interface/pcbios/biosint.c | 11 - .../arch/i386/interface/pcbios/memtop_umalloc.c | 200 + gpxe/src/arch/i386/interface/pcbios/pcibios.c | 113 + gpxe/src/arch/i386/interface/pxe/pxe_entry.S | 14 +- gpxe/src/arch/i386/prefix/dskprefix.S | 10 +- gpxe/src/arch/i386/prefix/efiprefix.S | 175 + gpxe/src/arch/i386/prefix/hdprefix.S | 10 +- gpxe/src/arch/i386/prefix/kkpxeprefix.S | 8 + gpxe/src/arch/i386/prefix/libprefix.S | 168 +- gpxe/src/arch/i386/prefix/lkrnprefix.S | 10 +- gpxe/src/arch/i386/prefix/nbiprefix.S | 13 +- gpxe/src/arch/i386/prefix/pxeprefix.S | 129 +- gpxe/src/arch/i386/prefix/romprefix.S | 162 +- gpxe/src/arch/i386/scripts/efi.lds | 180 + gpxe/src/arch/i386/scripts/i386.lds | 279 +- gpxe/src/arch/i386/transitions/librm.S | 10 +- gpxe/src/arch/i386/transitions/librm_mgmt.c | 101 +- gpxe/src/config.h | 175 - gpxe/src/config/.gitignore | 1 - gpxe/src/config/console.h | 21 + gpxe/src/config/defaults.h | 8 + gpxe/src/config/defaults/efi.h | 20 + gpxe/src/config/defaults/pcbios.h | 28 + gpxe/src/config/general.h | 122 + gpxe/src/config/ioapi.h | 15 + gpxe/src/config/isa.h | 15 + gpxe/src/config/nap.h | 15 + gpxe/src/config/serial.h | 28 + gpxe/src/config/timer.h | 15 + gpxe/src/config/umalloc.h | 12 + gpxe/src/core/config.c | 40 +- gpxe/src/core/console.c | 6 +- gpxe/src/core/debug.c | 2 +- gpxe/src/core/gdbudp.c | 2 +- gpxe/src/core/main.c | 16 +- gpxe/src/core/malloc.c | 2 +- gpxe/src/core/monojob.c | 7 +- gpxe/src/core/null_nap.c | 3 + gpxe/src/core/nvo.c | 2 +- gpxe/src/core/pc_kbd.c | 2 +- gpxe/src/core/process.c | 2 + gpxe/src/core/serial.c | 2 +- gpxe/src/core/settings.c | 20 +- gpxe/src/core/timer.c | 91 +- gpxe/src/core/uri.c | 8 +- gpxe/src/crypto/cryptoLayer.h | 2 +- gpxe/src/drivers/bitbash/i2c_bit.c | 147 +- gpxe/src/drivers/bus/eisa.c | 2 +- gpxe/src/drivers/bus/isa.c | 6 +- gpxe/src/drivers/bus/isapnp.c | 2 +- gpxe/src/drivers/bus/mca.c | 2 +- gpxe/src/drivers/infiniband/arbel.c | 160 +- gpxe/src/drivers/infiniband/hermon.c | 160 +- gpxe/src/drivers/infiniband/ib_packet.c | 234 + gpxe/src/drivers/infiniband/ib_sma.c | 553 ++ gpxe/src/drivers/infiniband/ib_smc.c | 166 + gpxe/src/drivers/infiniband/linda.c | 2396 ++++++++ gpxe/src/drivers/infiniband/linda.h | 271 + gpxe/src/drivers/infiniband/linda_fw.c | 1067 ++++ gpxe/src/drivers/infiniband/qib_7220_regs.h | 1763 ++++++ gpxe/src/drivers/infiniband/qib_genbits.pl | 95 + gpxe/src/drivers/net/3c509.c | 2 +- gpxe/src/drivers/net/3c595.c | 2 +- gpxe/src/drivers/net/3c90x.c | 4 +- gpxe/src/drivers/net/cs89x0.c | 4 +- gpxe/src/drivers/net/e1000/e1000.h | 3 +- gpxe/src/drivers/net/e1000/e1000_osdep.h | 50 +- gpxe/src/drivers/net/eepro100.c | 8 +- gpxe/src/drivers/net/epic100.c | 4 +- gpxe/src/drivers/net/etherfabric.c | 6338 +++++++++++--------- gpxe/src/drivers/net/etherfabric_nic.h | 201 + gpxe/src/drivers/net/forcedeth.c | 2 +- gpxe/src/drivers/net/ipoib.c | 565 +- gpxe/src/drivers/net/natsemi.c | 3 +- gpxe/src/drivers/net/ne2k_isa.c | 373 ++ gpxe/src/drivers/net/phantom/phantom.c | 1499 ++--- gpxe/src/drivers/net/phantom/phantom.h | 155 +- gpxe/src/drivers/net/pnic.c | 2 +- gpxe/src/drivers/net/r8169.c | 3127 ++++++---- gpxe/src/drivers/net/r8169.h | 566 ++ gpxe/src/drivers/net/rtl8139.c | 3 +- gpxe/src/drivers/net/tg3.c | 1 + gpxe/src/drivers/net/via-rhine.c | 16 +- gpxe/src/drivers/net/virtio-net.c | 8 +- gpxe/src/drivers/net/w89c840.c | 4 +- gpxe/src/hci/commands/config_cmd.c | 2 +- gpxe/src/image/efi_image.c | 106 + gpxe/src/include/compiler.h | 22 +- gpxe/src/include/gpxe/api.h | 82 + gpxe/src/include/gpxe/bitops.h | 227 +- gpxe/src/include/gpxe/efi/Base.h | 305 + gpxe/src/include/gpxe/efi/Guid/PcAnsi.h | 58 + gpxe/src/include/gpxe/efi/Ia32/ProcessorBind.h | 221 + .../include/gpxe/efi/IndustryStandard/PeImage.h | 742 +++ gpxe/src/include/gpxe/efi/LICENCE | 40 + gpxe/src/include/gpxe/efi/Pi/PiBootMode.h | 43 + gpxe/src/include/gpxe/efi/Pi/PiDependency.h | 47 + gpxe/src/include/gpxe/efi/Pi/PiDxeCis.h | 642 ++ gpxe/src/include/gpxe/efi/Pi/PiFirmwareFile.h | 242 + gpxe/src/include/gpxe/efi/Pi/PiFirmwareVolume.h | 154 + gpxe/src/include/gpxe/efi/Pi/PiHob.h | 293 + gpxe/src/include/gpxe/efi/Pi/PiMultiPhase.h | 104 + gpxe/src/include/gpxe/efi/PiDxe.h | 25 + gpxe/src/include/gpxe/efi/ProcessorBind.h | 10 + gpxe/src/include/gpxe/efi/Protocol/Cpu.h | 326 + gpxe/src/include/gpxe/efi/Protocol/CpuIo.h | 128 + gpxe/src/include/gpxe/efi/Protocol/DebugSupport.h | 656 ++ gpxe/src/include/gpxe/efi/Protocol/DevicePath.h | 560 ++ gpxe/src/include/gpxe/efi/Protocol/DriverBinding.h | 166 + gpxe/src/include/gpxe/efi/Protocol/PciIo.h | 577 ++ .../include/gpxe/efi/Protocol/PciRootBridgeIo.h | 450 ++ gpxe/src/include/gpxe/efi/Protocol/SimpleNetwork.h | 645 ++ gpxe/src/include/gpxe/efi/Protocol/SimpleTextIn.h | 145 + gpxe/src/include/gpxe/efi/Protocol/SimpleTextOut.h | 437 ++ gpxe/src/include/gpxe/efi/Uefi.h | 27 + gpxe/src/include/gpxe/efi/Uefi/UefiBaseType.h | 174 + gpxe/src/include/gpxe/efi/Uefi/UefiGpt.h | 66 + .../gpxe/efi/Uefi/UefiInternalFormRepresentation.h | 1499 +++++ gpxe/src/include/gpxe/efi/Uefi/UefiMultiPhase.h | 218 + gpxe/src/include/gpxe/efi/Uefi/UefiPxe.h | 1811 ++++++ gpxe/src/include/gpxe/efi/Uefi/UefiSpec.h | 1780 ++++++ gpxe/src/include/gpxe/efi/efi.h | 89 + gpxe/src/include/gpxe/efi/efi_io.h | 178 + gpxe/src/include/gpxe/efi/efi_pci.h | 146 + gpxe/src/include/gpxe/efi/efi_timer.h | 16 + gpxe/src/include/gpxe/efi/efi_uaccess.h | 88 + gpxe/src/include/gpxe/efi/efi_umalloc.h | 16 + gpxe/src/include/gpxe/efi/import.pl | 75 + gpxe/src/include/gpxe/errfile.h | 7 + gpxe/src/include/gpxe/ethernet.h | 2 + gpxe/src/include/gpxe/features.h | 1 + gpxe/src/include/gpxe/i2c.h | 68 +- gpxe/src/include/gpxe/ib_mad.h | 364 ++ gpxe/src/include/gpxe/ib_packet.h | 147 + gpxe/src/include/gpxe/ib_sma.h | 63 + gpxe/src/include/gpxe/ib_smc.h | 18 + gpxe/src/include/gpxe/infiniband.h | 519 +- gpxe/src/include/gpxe/init.h | 1 + gpxe/src/include/gpxe/io.h | 504 ++ gpxe/src/include/gpxe/iobuf.h | 18 + gpxe/src/include/gpxe/ipoib.h | 47 +- gpxe/src/include/gpxe/nap.h | 54 + gpxe/src/include/gpxe/netdevice.h | 80 +- gpxe/src/include/gpxe/null_nap.h | 21 + gpxe/src/include/gpxe/pci.h | 2 +- gpxe/src/include/gpxe/pci_io.h | 122 + gpxe/src/include/gpxe/retry.h | 9 +- gpxe/src/include/gpxe/rotate.h | 27 + gpxe/src/include/gpxe/sanboot.h | 14 + gpxe/src/include/gpxe/settings.h | 15 +- gpxe/src/include/gpxe/timer.h | 95 +- gpxe/src/include/gpxe/tls.h | 20 +- gpxe/src/include/gpxe/uaccess.h | 317 +- gpxe/src/include/gpxe/umalloc.h | 55 +- gpxe/src/include/gpxe/xfer.h | 4 +- gpxe/src/include/nic.h | 1 + gpxe/src/include/pxe_types.h | 5 +- gpxe/src/include/stddef.h | 6 + gpxe/src/include/stdlib.h | 1 + gpxe/src/include/unistd.h | 18 +- gpxe/src/include/usr/aoeboot.h | 6 - gpxe/src/include/usr/iscsiboot.h | 6 - gpxe/src/interface/efi/efi_console.c | 273 + gpxe/src/interface/efi/efi_entry.c | 83 + gpxe/src/interface/efi/efi_io.c | 201 + gpxe/src/interface/efi/efi_pci.c | 81 + gpxe/src/interface/efi/efi_snp.c | 980 +++ gpxe/src/interface/efi/efi_timer.c | 115 + gpxe/src/interface/efi/efi_uaccess.c | 37 + gpxe/src/interface/efi/efi_umalloc.c | 96 + gpxe/src/interface/pxe/pxe_undi.c | 30 +- gpxe/src/net/aoe.c | 15 +- gpxe/src/net/ethernet.c | 60 +- gpxe/src/net/infiniband.c | 316 +- gpxe/src/net/ipv4.c | 15 +- gpxe/src/net/netdevice.c | 62 +- gpxe/src/net/retry.c | 12 +- gpxe/src/net/tcp/ftp.c | 61 +- gpxe/src/net/tls.c | 37 +- gpxe/src/net/udp/dhcp.c | 2 +- gpxe/src/net/udp/tftp.c | 23 +- gpxe/src/tests/gdbstub_test.gdb | 0 gpxe/src/usr/aoeboot.c | 16 +- gpxe/src/usr/autoboot.c | 20 +- gpxe/src/usr/ifmgmt.c | 25 +- gpxe/src/usr/iscsiboot.c | 16 +- gpxe/src/util/.gitignore | 1 + gpxe/src/util/efilink.c | 507 ++ gpxe/src/util/geniso | 2 +- gpxe/src/util/mergerom.pl | 0 gpxe/src/util/mkconfig.pl | 205 - gpxe/src/util/sortobjdump.pl | 2 +- gpxe/src/util/zbin.c | 27 + 260 files changed, 36942 insertions(+), 9137 deletions(-) delete mode 100644 gpxe/src/arch/i386/Config create mode 100644 gpxe/src/arch/i386/Makefile.efi create mode 100644 gpxe/src/arch/i386/Makefile.pcbios delete mode 100644 gpxe/src/arch/i386/core/i386_timer.c delete mode 100644 gpxe/src/arch/i386/core/nap.c delete mode 100644 gpxe/src/arch/i386/core/pcibios.c create mode 100644 gpxe/src/arch/i386/core/rdtsc_timer.c delete mode 100644 gpxe/src/arch/i386/core/start32.S create mode 100644 gpxe/src/arch/i386/core/timer2.c delete mode 100644 gpxe/src/arch/i386/core/umalloc.c create mode 100644 gpxe/src/arch/i386/core/x86_io.c delete mode 100644 gpxe/src/arch/i386/drivers/timer_bios.c delete mode 100644 gpxe/src/arch/i386/drivers/timer_rdtsc.c create mode 100644 gpxe/src/arch/i386/include/bits/io.h create mode 100644 gpxe/src/arch/i386/include/bits/nap.h create mode 100644 gpxe/src/arch/i386/include/bits/pci_io.h create mode 100644 gpxe/src/arch/i386/include/bits/timer.h delete mode 100644 gpxe/src/arch/i386/include/bits/timer2.h create mode 100644 gpxe/src/arch/i386/include/bits/umalloc.h create mode 100644 gpxe/src/arch/i386/include/gpxe/bios_nap.h create mode 100644 gpxe/src/arch/i386/include/gpxe/bios_timer.h create mode 100644 gpxe/src/arch/i386/include/gpxe/efi/efix86_nap.h create mode 100644 gpxe/src/arch/i386/include/gpxe/memtop_umalloc.h create mode 100644 gpxe/src/arch/i386/include/gpxe/pcibios.h create mode 100644 gpxe/src/arch/i386/include/gpxe/pcidirect.h create mode 100644 gpxe/src/arch/i386/include/gpxe/rdtsc_timer.h create mode 100644 gpxe/src/arch/i386/include/gpxe/timer2.h create mode 100644 gpxe/src/arch/i386/include/gpxe/x86_io.h delete mode 100644 gpxe/src/arch/i386/include/io.h mode change 100644 => 100755 gpxe/src/arch/i386/include/librm.h delete mode 100644 gpxe/src/arch/i386/include/pci_io.h delete mode 100644 gpxe/src/arch/i386/include/pcibios.h delete mode 100644 gpxe/src/arch/i386/include/pcidirect.h delete mode 100644 gpxe/src/arch/i386/include/pxe_addr.h delete mode 100644 gpxe/src/arch/i386/include/virtaddr.h create mode 100644 gpxe/src/arch/i386/interface/efi/efix86_nap.c create mode 100644 gpxe/src/arch/i386/interface/pcbios/bios_nap.c create mode 100644 gpxe/src/arch/i386/interface/pcbios/bios_timer.c create mode 100644 gpxe/src/arch/i386/interface/pcbios/memtop_umalloc.c create mode 100644 gpxe/src/arch/i386/interface/pcbios/pcibios.c create mode 100644 gpxe/src/arch/i386/prefix/efiprefix.S create mode 100644 gpxe/src/arch/i386/prefix/kkpxeprefix.S create mode 100644 gpxe/src/arch/i386/scripts/efi.lds mode change 100644 => 100755 gpxe/src/arch/i386/transitions/librm.S mode change 100644 => 100755 gpxe/src/arch/i386/transitions/librm_mgmt.c delete mode 100644 gpxe/src/config.h create mode 100644 gpxe/src/config/console.h create mode 100644 gpxe/src/config/defaults.h create mode 100644 gpxe/src/config/defaults/efi.h create mode 100644 gpxe/src/config/defaults/pcbios.h create mode 100644 gpxe/src/config/general.h create mode 100644 gpxe/src/config/ioapi.h create mode 100644 gpxe/src/config/isa.h create mode 100644 gpxe/src/config/nap.h create mode 100644 gpxe/src/config/serial.h create mode 100644 gpxe/src/config/timer.h create mode 100644 gpxe/src/config/umalloc.h create mode 100644 gpxe/src/core/null_nap.c create mode 100644 gpxe/src/drivers/infiniband/ib_packet.c create mode 100644 gpxe/src/drivers/infiniband/ib_sma.c create mode 100644 gpxe/src/drivers/infiniband/ib_smc.c create mode 100644 gpxe/src/drivers/infiniband/linda.c create mode 100644 gpxe/src/drivers/infiniband/linda.h create mode 100644 gpxe/src/drivers/infiniband/linda_fw.c create mode 100644 gpxe/src/drivers/infiniband/qib_7220_regs.h create mode 100644 gpxe/src/drivers/infiniband/qib_genbits.pl create mode 100644 gpxe/src/drivers/net/etherfabric_nic.h create mode 100644 gpxe/src/drivers/net/ne2k_isa.c create mode 100644 gpxe/src/drivers/net/r8169.h create mode 100644 gpxe/src/image/efi_image.c create mode 100644 gpxe/src/include/gpxe/api.h create mode 100644 gpxe/src/include/gpxe/efi/Base.h create mode 100644 gpxe/src/include/gpxe/efi/Guid/PcAnsi.h create mode 100644 gpxe/src/include/gpxe/efi/Ia32/ProcessorBind.h create mode 100644 gpxe/src/include/gpxe/efi/IndustryStandard/PeImage.h create mode 100644 gpxe/src/include/gpxe/efi/LICENCE create mode 100644 gpxe/src/include/gpxe/efi/Pi/PiBootMode.h create mode 100644 gpxe/src/include/gpxe/efi/Pi/PiDependency.h create mode 100644 gpxe/src/include/gpxe/efi/Pi/PiDxeCis.h create mode 100644 gpxe/src/include/gpxe/efi/Pi/PiFirmwareFile.h create mode 100644 gpxe/src/include/gpxe/efi/Pi/PiFirmwareVolume.h create mode 100644 gpxe/src/include/gpxe/efi/Pi/PiHob.h create mode 100644 gpxe/src/include/gpxe/efi/Pi/PiMultiPhase.h create mode 100644 gpxe/src/include/gpxe/efi/PiDxe.h create mode 100644 gpxe/src/include/gpxe/efi/ProcessorBind.h create mode 100644 gpxe/src/include/gpxe/efi/Protocol/Cpu.h create mode 100644 gpxe/src/include/gpxe/efi/Protocol/CpuIo.h create mode 100644 gpxe/src/include/gpxe/efi/Protocol/DebugSupport.h create mode 100644 gpxe/src/include/gpxe/efi/Protocol/DevicePath.h create mode 100644 gpxe/src/include/gpxe/efi/Protocol/DriverBinding.h create mode 100644 gpxe/src/include/gpxe/efi/Protocol/PciIo.h create mode 100644 gpxe/src/include/gpxe/efi/Protocol/PciRootBridgeIo.h create mode 100644 gpxe/src/include/gpxe/efi/Protocol/SimpleNetwork.h create mode 100644 gpxe/src/include/gpxe/efi/Protocol/SimpleTextIn.h create mode 100644 gpxe/src/include/gpxe/efi/Protocol/SimpleTextOut.h create mode 100644 gpxe/src/include/gpxe/efi/Uefi.h create mode 100644 gpxe/src/include/gpxe/efi/Uefi/UefiBaseType.h create mode 100644 gpxe/src/include/gpxe/efi/Uefi/UefiGpt.h create mode 100644 gpxe/src/include/gpxe/efi/Uefi/UefiInternalFormRepresentation.h create mode 100644 gpxe/src/include/gpxe/efi/Uefi/UefiMultiPhase.h create mode 100644 gpxe/src/include/gpxe/efi/Uefi/UefiPxe.h create mode 100644 gpxe/src/include/gpxe/efi/Uefi/UefiSpec.h create mode 100644 gpxe/src/include/gpxe/efi/efi.h create mode 100644 gpxe/src/include/gpxe/efi/efi_io.h create mode 100644 gpxe/src/include/gpxe/efi/efi_pci.h create mode 100644 gpxe/src/include/gpxe/efi/efi_timer.h create mode 100644 gpxe/src/include/gpxe/efi/efi_uaccess.h create mode 100644 gpxe/src/include/gpxe/efi/efi_umalloc.h create mode 100755 gpxe/src/include/gpxe/efi/import.pl create mode 100644 gpxe/src/include/gpxe/ib_mad.h create mode 100644 gpxe/src/include/gpxe/ib_packet.h create mode 100644 gpxe/src/include/gpxe/ib_sma.h create mode 100644 gpxe/src/include/gpxe/ib_smc.h create mode 100644 gpxe/src/include/gpxe/io.h create mode 100644 gpxe/src/include/gpxe/nap.h create mode 100644 gpxe/src/include/gpxe/null_nap.h create mode 100644 gpxe/src/include/gpxe/pci_io.h create mode 100644 gpxe/src/include/gpxe/rotate.h create mode 100644 gpxe/src/include/gpxe/sanboot.h delete mode 100644 gpxe/src/include/usr/aoeboot.h delete mode 100644 gpxe/src/include/usr/iscsiboot.h create mode 100644 gpxe/src/interface/efi/efi_console.c create mode 100644 gpxe/src/interface/efi/efi_entry.c create mode 100644 gpxe/src/interface/efi/efi_io.c create mode 100644 gpxe/src/interface/efi/efi_pci.c create mode 100644 gpxe/src/interface/efi/efi_snp.c create mode 100644 gpxe/src/interface/efi/efi_timer.c create mode 100644 gpxe/src/interface/efi/efi_uaccess.c create mode 100644 gpxe/src/interface/efi/efi_umalloc.c mode change 100644 => 100755 gpxe/src/tests/gdbstub_test.gdb create mode 100644 gpxe/src/util/efilink.c mode change 100644 => 100755 gpxe/src/util/mergerom.pl delete mode 100755 gpxe/src/util/mkconfig.pl diff --git a/gpxe/Makefile b/gpxe/Makefile index c846e939..1c06f9eb 100644 --- a/gpxe/Makefile +++ b/gpxe/Makefile @@ -32,8 +32,8 @@ spotless: clean dist installer: -src/bin/undionly.kpxe: ../core/pxelinux.0 - $(MAKE) -C src EMBEDDED_IMAGE=../$< NO_WERROR=1 bin/undionly.kpxe +src/bin/undionly.kkpxe: ../core/pxelinux.0 + $(MAKE) -C src EMBEDDED_IMAGE=../$< NO_WERROR=1 bin/undionly.kkpxe -gpxelinux.0: src/bin/undionly.kpxe +gpxelinux.0: src/bin/undionly.kkpxe cp -f $< $@ diff --git a/gpxe/VERSION b/gpxe/VERSION index 010605b1..49a7dfae 100644 --- a/gpxe/VERSION +++ b/gpxe/VERSION @@ -1 +1 @@ -0.9.5 2008-10-01 +0.9.5+ 2008-10-01 diff --git a/gpxe/src/Makefile b/gpxe/src/Makefile index 6c42da6a..01048aae 100644 --- a/gpxe/src/Makefile +++ b/gpxe/src/Makefile @@ -1,19 +1,17 @@ -# Location to place generated files +############################################################################### # -BIN := bin - -# Initialise variables that get added to throughout the various Makefiles +# Initialise various variables # -MAKEDEPS := Makefile .toolcheck .echocheck -SRCDIRS := -SRCS := -NON_AUTO_SRCS := -DRIVERS := -ROMS := -MEDIA := -NON_AUTO_MEDIA := -# Locations of utilities +CLEANUP := +CFLAGS := +ASFLAGS := +LDFLAGS := +MAKEDEPS := Makefile + +############################################################################### +# +# Locations of tools # HOST_CC := gcc RM := rm -f @@ -35,109 +33,18 @@ NM := $(CROSS_COMPILE)nm OBJDUMP := $(CROSS_COMPILE)objdump PARSEROM := $(PERL) ./util/parserom.pl MAKEROM := $(PERL) ./util/makerom.pl -MKCONFIG := $(PERL) ./util/mkconfig.pl SYMCHECK := $(PERL) ./util/symcheck.pl SORTOBJDUMP := $(PERL) ./util/sortobjdump.pl NRV2B := ./util/nrv2b ZBIN := ./util/zbin +EFILINK := ./util/efilink DOXYGEN := doxygen -# If invoked with no build target, print out a helpfully suggestive -# message. -# -noargs : blib $(BIN)/NIC $(BIN)/gpxe.dsk $(BIN)/gpxe.iso $(BIN)/gpxe.usb $(BIN)/undionly.kpxe - @$(ECHO) '===========================================================' - @$(ECHO) - @$(ECHO) 'To create a bootable floppy, type' - @$(ECHO) ' cat $(BIN)/gpxe.dsk > /dev/fd0' - @$(ECHO) 'where /dev/fd0 is your floppy drive. This will erase any' - @$(ECHO) 'data already on the disk.' - @$(ECHO) - @$(ECHO) 'To create a bootable USB key, type' - @$(ECHO) ' cat $(BIN)/gpxe.usb > /dev/sdX' - @$(ECHO) 'where /dev/sdX is your USB key, and is *not* a real hard' - @$(ECHO) 'disk on your system. This will erase any data already on' - @$(ECHO) 'the USB key.' - @$(ECHO) - @$(ECHO) 'To create a bootable CD-ROM, burn the ISO image ' - @$(ECHO) '$(BIN)/gpxe.iso to a blank CD-ROM.' - @$(ECHO) - @$(ECHO) 'These images contain drivers for all supported cards. You' - @$(ECHO) 'can build more customised images, and ROM images, using' - @$(ECHO) ' make bin/.' - @$(ECHO) - @$(ECHO) '===========================================================' - -# If no architecture is specified in Config or on the command-line, -# use that of the build machine. -# -ARCH := $(shell uname -m | sed -e 's,i[3456789]86,i386,') - -# handle x86_64 like i386, but set -m32 option for 32bit code only -ifeq ($(ARCH),x86_64) -ARCH := i386 -CFLAGS += -m32 -ASFLAGS += --32 -LDFLAGS += -m elf_i386 -endif - -# Drag in architecture-specific Config -# -MAKEDEPS += arch/$(ARCH)/Config -include arch/$(ARCH)/Config - -# Common flags -# -CFLAGS += -I include -I arch/$(ARCH)/include -I . -DARCH=$(ARCH) -CFLAGS += -Os -ffreestanding -CFLAGS += -Wall -W -CFLAGS += -g -CFLAGS += $(EXTRA_CFLAGS) -ASFLAGS += $(EXTRA_ASFLAGS) -LDFLAGS += $(EXTRA_LDFLAGS) - -# Embedded image, if present +############################################################################### # -EMBEDDED_IMAGE = /dev/null - -ifneq ($(NO_WERROR),1) -CFLAGS += -Werror -endif - -# CFLAGS for specific object types -# -CFLAGS_c += -CFLAGS_S += -DASSEMBLY - -# Base object name of the current target -# -OBJECT = $(firstword $(subst ., ,$(@F))) - -# CFLAGS for specific object files. You can define -# e.g. CFLAGS_rtl8139, and have those flags automatically used when -# compiling bin/rtl8139.o. -# -OBJ_CFLAGS = $(CFLAGS_$(OBJECT)) -DOBJECT=$(subst -,_,$(OBJECT)) -$(BIN)/%.flags : - @$(ECHO) $(OBJ_CFLAGS) - -# Rules for specific object types. -# -COMPILE_c = $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS) -RULE_c = $(Q)$(COMPILE_c) -c $< -o $@ -RULE_c_to_dbg%.o = $(Q)$(COMPILE_c) -Ddebug_$(OBJECT)=$* -c $< -o $@ -RULE_c_to_c = $(Q)$(COMPILE_c) -E -c $< > $@ -RULE_c_to_s = $(Q)$(COMPILE_c) -S -g0 -c $< -o $@ - -PREPROCESS_S = $(CPP) $(CFLAGS) $(CFLAGS_S) $(OBJ_CFLAGS) -ASSEMBLE_S = $(AS) $(ASFLAGS) -RULE_S = $(Q)$(PREPROCESS_S) $< | $(ASSEMBLE_S) -o $@ -RULE_S_to_s = $(Q)$(PREPROCESS_S) $< > $@ - -DEBUG_TARGETS += dbg%.o c s - # SRCDIRS lists all directories containing source files. # +SRCDIRS := SRCDIRS += libgcc SRCDIRS += core SRCDIRS += proto @@ -151,7 +58,7 @@ SRCDIRS += drivers/block SRCDIRS += drivers/nvs SRCDIRS += drivers/bitbash SRCDIRS += drivers/infiniband -SRCDIRS += interface/pxe +SRCDIRS += interface/pxe interface/efi SRCDIRS += tests SRCDIRS += crypto crypto/axtls crypto/matrixssl SRCDIRS += hci hci/commands hci/tui @@ -161,25 +68,68 @@ SRCDIRS += usr # NON_AUTO_SRCS lists files that are excluded from the normal # automatic build system. # -NON_AUTO_SRCS += core/elf_loader.c +NON_AUTO_SRCS := NON_AUTO_SRCS += drivers/net/prism2.c -# Rules for finalising files. TGT_MAKEROM_FLAGS is defined as part of -# the automatic build system and varies by target; it includes the -# "-p 0x1234,0x5678" string to set the PCI IDs. +############################################################################### +# +# Default build target: build the most common targets and print out a +# helpfully suggestive message # -FINALISE_rom = $(MAKEROM) $(MAKEROM_FLAGS) $(TGT_MAKEROM_FLAGS) \ - -i$(IDENT) -s 0 $@ +all : bin/blib.a bin/gpxe.dsk bin/gpxe.iso bin/gpxe.usb bin/undionly.kpxe + @$(ECHO) '===========================================================' + @$(ECHO) + @$(ECHO) 'To create a bootable floppy, type' + @$(ECHO) ' cat bin/gpxe.dsk > /dev/fd0' + @$(ECHO) 'where /dev/fd0 is your floppy drive. This will erase any' + @$(ECHO) 'data already on the disk.' + @$(ECHO) + @$(ECHO) 'To create a bootable USB key, type' + @$(ECHO) ' cat bin/gpxe.usb > /dev/sdX' + @$(ECHO) 'where /dev/sdX is your USB key, and is *not* a real hard' + @$(ECHO) 'disk on your system. This will erase any data already on' + @$(ECHO) 'the USB key.' + @$(ECHO) + @$(ECHO) 'To create a bootable CD-ROM, burn the ISO image ' + @$(ECHO) 'bin/gpxe.iso to a blank CD-ROM.' + @$(ECHO) + @$(ECHO) 'These images contain drivers for all supported cards. You' + @$(ECHO) 'can build more customised images, and ROM images, using' + @$(ECHO) ' make bin/.' + @$(ECHO) + @$(ECHO) '===========================================================' + +############################################################################### +# +# Build targets that do nothing but might be tried by users +# +configure : + @$(ECHO) "No configuration needed." + +install : + @$(ECHO) "No installation required." -# Some ROMs require specific flags to be passed to makerom.pl +############################################################################### # -MAKEROM_FLAGS_3c503 = -3 +# Version number calculations +# +VERSION_MAJOR = 0 +VERSION_MINOR = 9 +VERSION_PATCH = 5 +EXTRAVERSION = + +MM_VERSION = $(VERSION_MAJOR).$(VERSION_MINOR) +VERSION = $(MM_VERSION).$(VERSION_PATCH)$(EXTRAVERSION) +CFLAGS += -DVERSION_MAJOR=$(VERSION_MAJOR) \ + -DVERSION_MINOR=$(VERSION_MINOR) \ + -DVERSION=\"$(VERSION)\" +IDENT = '$(@F) $(VERSION) (GPL) etherboot.org' +version : + @$(ECHO) $(VERSION) -# Drag in architecture-specific Makefile +############################################################################### +# +# Drag in the bulk of the build system # -MAKEDEPS += arch/$(ARCH)/Makefile -include arch/$(ARCH)/Makefile -# Drag in the automatic build system and other housekeeping functions MAKEDEPS += Makefile.housekeeping include Makefile.housekeeping diff --git a/gpxe/src/Makefile.housekeeping b/gpxe/src/Makefile.housekeeping index 9e11ceb4..067ac826 100644 --- a/gpxe/src/Makefile.housekeeping +++ b/gpxe/src/Makefile.housekeeping @@ -1,50 +1,10 @@ # -*- makefile -*- : Force emacs to use Makefile mode - +# # This file contains various boring housekeeping functions that would # otherwise seriously clutter up the main Makefile. -# Objects to be removed by "make clean" -# -CLEANUP := $(BIN)/*.* # *.* to avoid catching the "CVS" directory - -# Version number calculations -# -VERSION_MAJOR = 0 -VERSION_MINOR = 9 -VERSION_PATCH = 5 -EXTRAVERSION = -MM_VERSION = $(VERSION_MAJOR).$(VERSION_MINOR) -VERSION = $(MM_VERSION).$(VERSION_PATCH)$(EXTRAVERSION) -CFLAGS += -DVERSION_MAJOR=$(VERSION_MAJOR) \ - -DVERSION_MINOR=$(VERSION_MINOR) \ - -DVERSION=\"$(VERSION)\" -IDENT = '$(@F) $(VERSION) (GPL) etherboot.org' -version : - @$(ECHO) $(VERSION) - -configure : - @$(ECHO) "No configuration needed." - -install : - @$(ECHO) "No installation required. Generated images will be placed in the" $(BIN) "directory." - -# Check for tools that can cause failed builds +############################################################################### # -.toolcheck : Makefile - @if $(CC) -v 2>&1 | grep -is 'gcc version 2\.96' > /dev/null; then \ - $(ECHO) 'gcc 2.96 is unsuitable for compiling Etherboot'; \ - $(ECHO) 'Use gcc 2.95 or gcc 3.x instead'; \ - exit 1; \ - fi - @if [ `perl -e 'use bytes; print chr(255)' | wc -c` = 2 ]; then \ - $(ECHO) 'Your Perl version has a Unicode handling bug'; \ - $(ECHO) 'Execute this command before compiling Etherboot:'; \ - $(ECHO) 'export LANG=$${LANG%.UTF-8}'; \ - exit 1; \ - fi - @$(TOUCH) $@ -VERYCLEANUP += .toolcheck - # Find a usable "echo -e" substitute. # TAB := $(shell $(PRINTF) '\t') @@ -86,20 +46,44 @@ else @$(ECHO) "No usable \"echo -e\" substitute found" @exit 1 endif +MAKEDEPS += .echocheck VERYCLEANUP += .echocheck echo : @$(ECHO) "Using \"$(ECHO_E)\" for \"echo -e\"" -# Build verbosity +############################################################################### +# +# Determine host OS +# +HOST_OS := $(shell uname -s) +hostos : + @$(ECHO) $(HOST_OS) + +############################################################################### +# +# Check for tools that can cause failed builds +# +.toolcheck : + @if $(CC) -v 2>&1 | grep -is 'gcc version 2\.96' > /dev/null; then \ + $(ECHO) 'gcc 2.96 is unsuitable for compiling Etherboot'; \ + $(ECHO) 'Use gcc 2.95 or gcc 3.x instead'; \ + exit 1; \ + fi + @if [ `perl -e 'use bytes; print chr(255)' | wc -c` = 2 ]; then \ + $(ECHO) 'Your Perl version has a Unicode handling bug'; \ + $(ECHO) 'Execute this command before compiling Etherboot:'; \ + $(ECHO) 'export LANG=$${LANG%.UTF-8}'; \ + exit 1; \ + fi + @$(TOUCH) $@ +MAKEDEPS += .toolcheck +VERYCLEANUP += .toolcheck + +############################################################################### +# +# Check for various tool workarounds # -ifeq ($(V),1) -Q = -QM = @\# -else -Q = @ -QM = @ -endif # Check for an old version of gas (binutils 2.9.1) # @@ -112,18 +96,154 @@ oldgas : # default, even when -ffreestanding is specified. We therefore need # to disable -fstack-protector if the compiler supports it. # -SP_TEST = $(CC) -fno-stack-protector -x c -E - < /dev/null >/dev/null 2>&1 +SP_TEST = $(CC) -fno-stack-protector -x c -c /dev/null \ + -o /dev/null >/dev/null 2>&1 SP_FLAGS := $(shell $(SP_TEST) && $(ECHO) '-fno-stack-protector') CFLAGS += $(SP_FLAGS) -# compiler.h is needed for our linking and debugging system +############################################################################### +# +# Build verbosity +# +ifeq ($(V),1) +Q := +QM := @\# +else +Q := @ +QM := @ +endif + +############################################################################### +# +# Set BIN according to whatever was specified on the command line as +# the build target. +# + +# Determine how many different BIN directories are mentioned in the +# make goals. +# +BIN_GOALS := $(filter bin/% bin-%,$(MAKECMDGOALS)) +BIN_GOAL_BINS := $(foreach BG,$(BIN_GOALS),$(firstword $(subst /, ,$(BG)))) +NUM_BINS := $(words $(sort $(BIN_GOAL_BINS))) + +ifeq ($(NUM_BINS),0) + +# No BIN directory was specified. Set BIN to "bin" as a sensible +# default. + +BIN := bin + +else # NUM_BINS == 0 + +ifeq ($(NUM_BINS),1) + +# If exactly one BIN directory was specified, set BIN to match this +# directory. +# +BIN := $(firstword $(BIN_GOAL_BINS)) + +else # NUM_BINS == 1 + +# More than one BIN directory was specified. We cannot handle the +# latter case within a single make invocation, so set up recursive +# targets for each BIN directory. +# +# Leave $(BIN) undefined. This has implications for any target that +# depends on $(BIN); such targets should be made conditional upon the +# existence of $(BIN). +# +$(BIN_GOALS) : % : BIN_RECURSE + $(Q)$(MAKE) --no-print-directory BIN=$(firstword $(subst /, ,$@)) $@ +.PHONY : BIN_RECURSE + +endif # NUM_BINS == 1 +endif # NUM_BINS == 0 + +ifdef BIN + +# Create $(BIN) directory if it doesn't exist yet +# +ifeq ($(wildcard $(BIN)),) +$(shell $(MKDIR) -p $(BIN)) +endif + +# Target to allow e.g. "make bin-efi arch" +# +$(BIN) : + @# Do nothing, silently +.PHONY : $(BIN) + +# Remove everything in $(BIN) for a "make clean" +# +CLEANUP += $(BIN)/*.* # Avoid picking up directories + +endif # defined(BIN) + +# Determine whether or not we need to include the dependency files # -CFLAGS += -include compiler.h +NO_DEP_TARGETS := $(BIN) clean veryclean +ifeq ($(MAKECMDGOALS),) +NEED_DEPS := 1 +endif +ifneq ($(strip $(filter-out $(NO_DEP_TARGETS),$(MAKECMDGOALS))),) +NEED_DEPS := 1 +endif -# config/%.h files are generated from config.h using mkconfig.pl -config/%.h : config*.h - $(MKCONFIG) config.h -CLEANUP += config/*.h +############################################################################### +# +# Select build architecture and platform based on $(BIN) +# +# BIN has the form bin[-[arch-]platform] + +ARCHS := $(patsubst arch/%,%,$(wildcard arch/*)) +PLATFORMS := $(patsubst config/defaults/%.h,%,\ + $(wildcard config/defaults/*.h)) +archs : + @$(ECHO) $(ARCHS) + +platforms : + @$(ECHO) $(PLATFORMS) + +ifdef BIN + +# Determine architecture portion of $(BIN), if present +BIN_ARCH := $(strip $(foreach A,$(ARCHS),\ + $(patsubst bin-$(A)-%,$(A),\ + $(filter bin-$(A)-%,$(BIN))))) + +# Determine platform portion of $(BIN), if present +ifeq ($(BIN_ARCH),) +BIN_PLATFORM := $(patsubst bin-%,%,$(filter bin-%,$(BIN))) +else +BIN_PLATFORM := $(patsubst bin-$(BIN_ARCH)-%,%,$(BIN)) +endif + +# Determine build architecture +DEFAULT_ARCH := i386 +ARCH := $(firstword $(BIN_ARCH) $(DEFAULT_ARCH)) +CFLAGS += -DARCH=$(ARCH) +arch : + @$(ECHO) $(ARCH) +.PHONY : arch + +# Determine build platform +DEFAULT_PLATFORM := pcbios +PLATFORM := $(firstword $(BIN_PLATFORM) $(DEFAULT_PLATFORM)) +CFLAGS += -DPLATFORM=$(PLATFORM) +platform : + @$(ECHO) $(PLATFORM) + +endif # defined(BIN) + +# Include architecture-specific Makefile +ifdef ARCH +MAKEDEPS += arch/$(ARCH)/Makefile +include arch/$(ARCH)/Makefile +endif + +############################################################################### +# +# Source file handling # SRCDIRS lists all directories containing source files. srcdirs : @@ -144,6 +264,67 @@ AUTO_SRCS = $(filter-out $(NON_AUTO_SRCS),$(SRCS)) autosrcs : @$(ECHO) $(AUTO_SRCS) +# Just about everything else in this section depends upon having +# $(BIN) set + +ifdef BIN + +# Common flags +# +CFLAGS += -I include -I arch/$(ARCH)/include -I . +CFLAGS += -Os -ffreestanding +CFLAGS += -Wall -W -Wformat-nonliteral +CFLAGS += -g +CFLAGS += $(EXTRA_CFLAGS) +ASFLAGS += $(EXTRA_ASFLAGS) +LDFLAGS += $(EXTRA_LDFLAGS) + +# Embedded image, if present +# +EMBEDDED_IMAGE = /dev/null + +# Inhibit -Werror if NO_WERROR is specified on make command line +# +ifneq ($(NO_WERROR),1) +CFLAGS += -Werror +endif + +# compiler.h is needed for our linking and debugging system +# +CFLAGS += -include compiler.h + +# CFLAGS for specific object types +# +CFLAGS_c += +CFLAGS_S += -DASSEMBLY + +# Base object name of the current target +# +OBJECT = $(firstword $(subst ., ,$(@F))) + +# CFLAGS for specific object files. You can define +# e.g. CFLAGS_rtl8139, and have those flags automatically used when +# compiling bin/rtl8139.o. +# +OBJ_CFLAGS = $(CFLAGS_$(OBJECT)) -DOBJECT=$(subst -,_,$(OBJECT)) +$(BIN)/%.flags : + @$(ECHO) $(OBJ_CFLAGS) + +# Rules for specific object types. +# +COMPILE_c = $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS) +RULE_c = $(Q)$(COMPILE_c) -c $< -o $@ +RULE_c_to_dbg%.o = $(Q)$(COMPILE_c) -Ddebug_$(OBJECT)=$* -c $< -o $@ +RULE_c_to_c = $(Q)$(COMPILE_c) -E -c $< > $@ +RULE_c_to_s = $(Q)$(COMPILE_c) -S -g0 -c $< -o $@ + +PREPROCESS_S = $(CPP) $(CFLAGS) $(CFLAGS_S) $(OBJ_CFLAGS) +ASSEMBLE_S = $(AS) $(ASFLAGS) +RULE_S = $(Q)$(PREPROCESS_S) $< | $(ASSEMBLE_S) -o $@ +RULE_S_to_s = $(Q)$(PREPROCESS_S) $< > $@ + +DEBUG_TARGETS += dbg%.o c s + # We automatically generate rules for any file mentioned in AUTO_SRCS # using the following set of templates. It would be cleaner to use # $(eval ...), but this function exists only in GNU make >= 3.80. @@ -157,7 +338,7 @@ autosrcs : # define src_template - @$(ECHO) "Generating Makefile rules for $(1)" + @$(ECHO) " [DEPS] $(1)" @$(MKDIR) -p $(dir $(2)) @$(RM) $(2) @$(TOUCH) $(2) @@ -182,13 +363,13 @@ define obj_template -Wno-error -MM $(1) -MT "$(4)_DEPS" -MG -MP | \ sed 's/_DEPS\s*:/_DEPS =/' >> $(2) @$(ECHO_E) '\n$$(BIN)/$(4).o : $(1) $$(MAKEDEPS) $$($(4)_DEPS)' \ - '\n\t$$(QM)$(ECHO) " [BUILD] $$@"\n' \ + '\n\t$$(QM)$(ECHO) " [BUILD] $$@"' \ '\n\t$$(RULE_$(3))\n' \ '\nBOBJS += $$(BIN)/$(4).o\n' \ $(foreach TGT,$(DEBUG_TARGETS), \ $(if $(RULE_$(3)_to_$(TGT)), \ '\n$$(BIN)/$(4).$(TGT) : $(1) $$(MAKEDEPS) $$($(4)_DEPS)' \ - '\n\t$$(QM)$(ECHO) " [BUILD] $$@"\n' \ + '\n\t$$(QM)$(ECHO) " [BUILD] $$@"' \ '\n\t$$(RULE_$(3)_to_$(TGT))\n' \ '\n$(TGT)_OBJS += $$(BIN)/$(4).$(TGT)\n' ) ) \ '\n$(2) : $$($(4)_DEPS)\n' \ @@ -205,7 +386,11 @@ $(BIN)/deps/%.d : % $(MAKEDEPS) $(PARSEROM) # Calculate and include the list of Makefile rules files # AUTO_DEPS = $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS)) +ifdef NEED_DEPS +ifneq ($(AUTO_DEPS),) -include $(AUTO_DEPS) +endif +endif autodeps : @$(ECHO) $(AUTO_DEPS) VERYCLEANUP += $(BIN)/deps @@ -237,7 +422,7 @@ $(BIN)/NIC : $(AUTO_DEPS) 'it is only for rom-o-matic' >> $@ @$(ECHO) >> $@ @perl -ne 'chomp; print "$$1\n" if /\# NIC\t(.*)$$/' $^ >> $@ -CLEANUP += $(BIN)/NIC +CLEANUP += $(BIN)/NIC # Doesn't match the $(BIN)/*.* pattern # Analyse a target name (e.g. "bin/dfe538--prism2_pci.zrom.tmp") and # derive the variables: @@ -342,8 +527,13 @@ $(BIN)/%.info : # in order to correctly rebuild blib whenever the list of objects # changes. # -BLIB_LIST = $(BIN)/.blib.list -ifneq ($(shell cat $(BLIB_LIST)),$(BLIB_OBJS)) +BLIB_LIST := $(BIN)/.blib.list +ifeq ($(wildcard $(BLIB_LIST)),) +BLIB_LIST_OBJS := +else +BLIB_LIST_OBJS := $(shell cat $(BLIB_LIST)) +endif +ifneq ($(BLIB_LIST_OBJS),$(BLIB_OBJS)) $(shell $(ECHO) "$(BLIB_OBJS)" > $(BLIB_LIST)) endif @@ -396,10 +586,6 @@ $(BIN)/%.zbin : $(BIN)/%.bin $(BIN)/%.zinfo $(ZBIN) $(QM)$(ECHO) " [ZBIN] $@" $(Q)$(ZBIN) $(BIN)/$*.bin $(BIN)/$*.zinfo > $@ -# Build bochs symbol table -$(BIN)/%.bxs : $(BIN)/%.tmp - $(NM) $< | cut -d" " -f1,3 > $@ - # Rules for each media format. These are generated and placed in an # external Makefile fragment. We could do this via $(eval ...), but # that would require make >= 3.80. @@ -435,7 +621,7 @@ automedia : # define media_template - @$(ECHO) "Generating Makefile rules for $(1) media" + @$(ECHO) " [MEDIADEPS] $(1)" @$(MKDIR) -p $(dir $(2)) @$(RM) $(2) @$(TOUCH) $(2) @@ -459,7 +645,20 @@ $(BIN)/deps/%.media.d : $(MAKEDEPS) MEDIA_DEPS = $(patsubst %,$(BIN)/deps/%.media.d,$(AUTO_MEDIA)) mediadeps : @$(ECHO) $(MEDIA_DEPS) +ifdef NEED_DEPS +ifneq ($(MEDIA_DEPS),) -include $(MEDIA_DEPS) +endif +endif + +# Wrap up binary blobs (for embedded images) +# +$(BIN)/%.o : payload/%.img + $(QM)echo " [WRAP] $@" + $(Q)$(LD) -b binary -r -o $@ $< --undefined obj_payload \ + --defsym obj_$*=0 + +BOBJS += $(patsubst payload/%.img,$(BIN)/%.o,$(wildcard payload/*.img)) # The "allXXXs" targets for each suffix # @@ -472,15 +671,23 @@ allpxes allisos alldsks : all%s : $(foreach DRIVER,$(DRIVERS),$(BIN)/$(DRIVER).% $(BIN)/etherboot.% : $(BIN)/gpxe.% ln -sf $(notdir $<) $@ -# Wrap up binary blobs +endif # defined(BIN) + +############################################################################### # -$(BIN)/%.o : payload/%.img - $(QM)echo " [WRAP] $@" - $(Q)$(LD) -b binary -r -o $@ $< --undefined obj_payload \ - --defsym obj_$*=0 +# Rules for finalising files. TGT_MAKEROM_FLAGS is defined as part of +# the automatic build system and varies by target; it includes the +# "-p 0x1234,0x5678" string to set the PCI IDs. +# +FINALISE_rom = $(MAKEROM) $(MAKEROM_FLAGS) $(TGT_MAKEROM_FLAGS) \ + -i$(IDENT) -s 0 $@ -BOBJS += $(patsubst payload/%.img,$(BIN)/%.o,$(wildcard payload/*.img)) +# Some ROMs require specific flags to be passed to makerom.pl +# +MAKEROM_FLAGS_3c503 = -3 +############################################################################### +# # The compression utilities # $(NRV2B) : util/nrv2b.c $(MAKEDEPS) @@ -494,6 +701,17 @@ $(ZBIN) : util/zbin.c util/nrv2b.c $(MAKEDEPS) $(Q)$(HOST_CC) -O2 -o $@ $< CLEANUP += $(ZBIN) +############################################################################### +# +# The EFI custom linker +# +$(EFILINK) : util/efilink.c $(MAKEDEPS) + $(QM)$(ECHO) " [HOSTCC] $@" + $(Q)$(HOST_CC) -O2 -o $@ $< -lbfd +CLEANUP += $(EFILINK) + +############################################################################### +# # Auto-incrementing build serial number. Append "bs" to your list of # build targets to get a serial number printed at the end of the # build. Enable -DBUILD_SERIAL in order to see it when the code runs. @@ -517,27 +735,30 @@ bs : $(BUILDSERIAL_NOW) @$(ECHO) $$(( $(shell cat $<) + 1 )) > $(BUILDSERIAL_NEXT) @$(ECHO) "Build serial number is $(shell cat $<)" -# List of available architectures +############################################################################### # -ARCHS = $(filter-out CVS,$(patsubst arch/%,%,$(wildcard arch/*))) -archs : - @$(ECHO) $(ARCHS) +# Build the TAGS file(s) for emacs +# +TAGS : + ctags -e -R -f $@ --exclude=bin -OTHER_ARCHS = $(filter-out $(ARCH),$(ARCHS)) -otherarchs : - @$(ECHO) $(OTHER_ARCHS) +CLEANUP += TAGS -# Build the TAGS file for emacs +############################################################################### # -TAGS : TAGS.$(ARCH) - -TAGS.$(ARCH) : - ctags -e -R -f $@ --exclude=bin \ - $(foreach ARCH,$(OTHER_ARCHS),--exclude=arch/$(ARCH)) -CLEANUP += TAGS* +# Force rebuild for any given target +# +%.rebuild : + rm -f $* + $(Q)$(MAKE) $* +############################################################################### +# # Symbol table checks # + +ifdef BIN + SYMTAB = $(BIN)/symtab $(SYMTAB) : $(BLIB) $(OBJDUMP) -w -t $< > $@ @@ -547,14 +768,27 @@ CLEANUP += $(BIN)/symtab symcheck : $(SYMTAB) $(SYMCHECK) $< -# Force rebuild for any given target +endif # defined(BIN) + +############################################################################### +# +# Build bochs symbol table # -$(BIN)/%.rebuild : - rm -f $(BIN)/$* - $(MAKE) $(MAKEFLAGS) $(BIN)/$* +ifdef BIN + +$(BIN)/%.bxs : $(BIN)/%.tmp + $(NM) $< | cut -d" " -f1,3 > $@ + +endif # defined(BIN) + +############################################################################### +# # Documentation # + +ifdef BIN + $(BIN)/doxygen.cfg : doxygen.cfg $(MAKEDEPS) $(PERL) -pe 's{\@SRCDIRS\@}{$(SRCDIRS)}; ' \ -e 's{\@BIN\@}{$(BIN)}; ' \ @@ -578,6 +812,10 @@ docview : $(ECHO) "Documentation index in $(BIN)/doc/html/index.html" ; \ fi +endif # defined(BIN) + +############################################################################### +# # Clean-up # clean : @@ -585,19 +823,3 @@ clean : veryclean : clean $(RM) -r $(VERYCLEANUP) - -# Make clean tarballs for release - -tarball : ../VERSION - ($(ECHO) -n $(VERSION) ''; date -u +'%Y-%m-%d') > ../VERSION - $(RM) -r /tmp/$(USER)/gpxe-$(VERSION) - mkdir -p /tmp/$(USER)/gpxe-$(VERSION) - cp -rP .. /tmp/$(USER)/gpxe-$(VERSION) - ( cd /tmp/$(USER)/gpxe-$(VERSION)/src ; $(MAKE) veryclean ; $(RM) -r bin/deps ) - ( cd /tmp/$(USER); tar cf /tmp/$(USER)/gpxe-$(VERSION).tar --exclude ".git*" --exclude "#*" \ - --exclude "*~" gpxe-$(VERSION) ) - bzip2 -9 < /tmp/$(USER)/gpxe-$(VERSION).tar > /tmp/$(USER)/gpxe-$(VERSION).tar.bz2 - gzip -9 < /tmp/$(USER)/gpxe-$(VERSION).tar > /tmp/$(USER)/gpxe-$(VERSION).tar.gz - $(RM) -r /tmp/$(USER)/gpxe-$(VERSION) - $(RM) /tmp/$(USER)/gpxe-$(VERSION).tar - ( cd /tmp/$(USER) ; tar -zxf /tmp/$(USER)/gpxe-$(VERSION).tar.gz ) diff --git a/gpxe/src/arch/i386/Config b/gpxe/src/arch/i386/Config deleted file mode 100644 index 1c086ecc..00000000 --- a/gpxe/src/arch/i386/Config +++ /dev/null @@ -1,148 +0,0 @@ -# -*- makefile -*- - -############################################################################## -############################################################################## -# -# IMPORTANT! -# -# The use of this file to set options that affect only single object -# files is deprecated, because changing anything in this file results -# in a complete rebuild, which is slow. All options are gradually -# being migrated to config.h, which does not suffer from this problem. -# -# Only options that affect the entire build (e.g. overriding the $(CC) -# Makefile variable) should be placed in here. -# -############################################################################## -############################################################################## - - -# Config for i386 Etherboot -# -# Do not delete the tag OptionDescription and /OptionDescription -# It is used to automatically generate the documentation. -# -# @OptionDescrition@ -# -# BIOS interface options: -# -# -DPCBIOS -# Compile in support for the normal pcbios -# -DLINUXBIOS -# Compile in support for LinuxBIOS -# -DBBS_BUT_NOT_PNP_COMPLIANT -# Some BIOSes claim to be PNP but they don't conform -# to the BBS spec which specifies that ES:DI must -# point to the string $PnP on entry. This option -# works around those. This option must be added to -# LCONFIG. -# -DNO_DELAYED_INT -# Take control as soon as BIOS detects the ROM. -# Normally hooks onto INT18H or INT19H. Use only if you -# have a very non-conformant BIOS as it bypasses -# BIOS initialisation of devices. This only works for -# legacy ROMs, i.e. PCI_PNP_HEADER not defined. -# This option was formerly called NOINT19H. -# -DBOOT_INT18H -# Etherboot normally hooks onto INT19H for legacy ROMs. -# You can choose to hook onto INT18H (BASIC interpreter -# entry point) instead. This entry point is used when -# all boot devices have been exhausted. This option must -# be added to LCONFIG. -# -DCONFIG_PCI_DIRECT -# Define this for PCI BIOSes that do not implement -# BIOS32 or not correctly. Normally not needed. -# Only works for BIOSes of a certain era. -# -DCONFIG_TSC_CURRTICKS -# Uses the processor time stamp counter instead of reading -# the BIOS time counter. This allows Etherboot to work -# even without a BIOS. This only works on late model -# 486s and above. -# -DCONFIG_NO_TIMER2 -# Some systems do not have timer2 implemented. -# If you have a RTC this will allow you to roughly calibrate -# it using outb instructions. -# -# Extended cpu options - -# -DCONFIG_X86_64 -# Compile in support for booting x86_64 64bit binaries. -# -# PXE loader options: -# -# -DPXELOADER_KEEP_ALL -# Prevent PXE loader (prefix) from unloading the -# PXE stack. You will want to use this if, for -# example, you are booting via PXE-on-floppy. -# You may want to use it under certain -# circumstances when using the Etherboot UNDI -# driver; these are complex and best practice is -# not yet established. -# -# Obscure options you probably don't need to touch: -# -# -DIGNORE_E820_MAP -# Ignore the memory map returned by the E820 BIOS -# call. May be necessary on some buggy BIOSes. -# -DT503_AUI -# Use AUI by default on 3c503 cards. -# -DFLATTEN_REAL_MODE -# Use 4GB segment limits when calling out to or -# returning to real-mode code. This is necessary to -# work around some buggy code (e.g. OpenBSD's pxeboot) -# that uses flat real-mode without being sufficiently -# paranoid about the volatility of its segment limits. - -# -# @/OptionDescription@ - -# BIOS select don't change unless you know what you are doing -# CFLAGS+= -DPCBIOS - -# Compile in k8/hammer support -# CFLAGS+= -DCONFIG_X86_64 - -# Options to make a version of Etherboot that will work under linuxBIOS. -# CFLAGS+= -DLINUXBIOS -DCONFIG_TSC_CURRTICKS -DCONSOLE_SERIAL -DCOMCONSOLE=0x3f8 -DCOMPRESERVE -DCONFIG_PCI_DIRECT -DELF_IMAGE - -# These options affect the loader that is prepended to the Etherboot image -# LCONFIG+= -DBBS_BUT_NOT_PNP_COMPLIANT -# LCONFIG+= -DBOOT_INT18H - -# Produce code that will work with OpenBSD's pxeboot -# CFLAGS+= -DFLATTEN_REAL_MODE - -CFLAGS+= -fstrength-reduce -fomit-frame-pointer -march=i386 -# Squeeze the code in as little space as possible. -# gcc3 needs a different syntax to gcc2 if you want to avoid spurious warnings. -GCC_VERSION = $(subst ., ,$(shell $(CC) -dumpversion)) -GCC_MAJORVERSION = $(firstword $(GCC_VERSION)) -ifeq ($(GCC_MAJORVERSION),2) -CFLAGS+= -malign-jumps=1 -malign-loops=1 -malign-functions=1 -else -CFLAGS+= -falign-jumps=1 -falign-loops=1 -falign-functions=1 -endif - -# this is almost always a win. the kernel uses it, too. -CFLAGS+= -mpreferred-stack-boundary=2 - -# use regparm for all functions - C functions called from assembly (or -# vice versa) need __cdecl now -CFLAGS+= -mregparm=3 - -# use -mrtd (same __cdecl requirements as above) -CFLAGS+= -mrtd - -# this is the logical complement to -mregparm=3. -# it doesn't currently buy us anything, but if anything ever tries -# to return small structures, let's be prepared -CFLAGS+= -freg-struct-return - -LDFLAGS+= -N --no-check-sections - -ifeq "$(shell uname -s)" "FreeBSD" -CFLAGS+= -DIMAGE_FREEBSD -DELF_IMAGE -DAOUT_IMAGE -endif - -# An alternate location for isolinux.bin can be set here -# ISOLINUX_BIN=/path/to/isolinux.bin diff --git a/gpxe/src/arch/i386/Makefile b/gpxe/src/arch/i386/Makefile index 97ca0774..7d3e7639 100644 --- a/gpxe/src/arch/i386/Makefile +++ b/gpxe/src/arch/i386/Makefile @@ -1,3 +1,59 @@ +# Force i386-only instructions +# +CFLAGS += -march=i386 + +# Code size reduction. +# +CFLAGS += -fstrength-reduce -fomit-frame-pointer + +# Code size reduction. gcc3 needs a different syntax to gcc2 if you +# want to avoid spurious warnings. +# +GCC_VERSION := $(subst ., ,$(shell $(CC) -dumpversion)) +GCC_MAJOR := $(firstword $(GCC_VERSION)) +ifeq ($(GCC_MAJOR),2) +CFLAGS += -malign-jumps=1 -malign-loops=1 -malign-functions=1 +else +CFLAGS += -falign-jumps=1 -falign-loops=1 -falign-functions=1 +endif + +# Code size reduction. This is almost always a win. The kernel uses it, too. +# +CFLAGS += -mpreferred-stack-boundary=2 + +# Code size reduction. Use regparm for all functions - C functions +# called from assembly (or vice versa) need __cdecl now +# +CFLAGS += -mregparm=3 + +# Code size reduction. Use -mrtd (same __cdecl requirements as above) +CFLAGS += -mrtd + +# Code size reduction. This is the logical complement to -mregparm=3. +# It doesn't currently buy us anything, but if anything ever tries to +# return small structures, let's be prepared +# +CFLAGS += -freg-struct-return + +# Force 32-bit code even on an x86-64 machine +# +CFLAGS += -m32 +ASFLAGS += --32 +ifeq ($(HOST_OS),FreeBSD) +LDFLAGS += -m elf_i386_fbsd +else +LDFLAGS += -m elf_i386 +endif + +# EFI requires -fshort-wchar, and nothing else currently uses wchar_t +# +CFLAGS += -fshort-wchar + +# We need to undefine the default macro "i386" when compiling .S +# files, otherwise ".arch i386" translates to ".arch 1"... +# +CFLAGS += -Ui386 + # Locations of utilities # ISOLINUX_BIN = /usr/lib/syslinux/isolinux.bin @@ -12,6 +68,7 @@ SRCDIRS += arch/i386/drivers/net SRCDIRS += arch/i386/interface/pcbios SRCDIRS += arch/i386/interface/pxe SRCDIRS += arch/i386/interface/syslinux +SRCDIRS += arch/i386/interface/efi # The various xxx_loader.c files are #included into core/loader.c and # should not be compiled directly. @@ -22,85 +79,32 @@ NON_AUTO_SRCS += arch/i386/core/wince_loader.c # unnrv2b.S is used to generate a 16-bit as well as a 32-bit object. # -OBJS_unnrv2b = unnrv2b unnrv2b16 -CFLAGS_unnrv2b16 = -DCODE16 - -# We need to undefine the default macro "i386" when compiling .S -# files, otherwise ".arch i386" translates to ".arch 1"... -# -CFLAGS_S += -Ui386 +OBJS_unnrv2b = unnrv2b unnrv2b16 +CFLAGS_unnrv2b16 = -DCODE16 -# The i386 linker script +# Include platform-specific Makefile # -LDSCRIPT = arch/i386/scripts/i386.lds - -# Media types. -# -MEDIA += rom -MEDIA += pxe -MEDIA += kpxe -MEDIA += elf -MEDIA += elfd -MEDIA += lmelf -MEDIA += lmelfd -MEDIA += lkrn -MEDIA += bImage -MEDIA += dsk -MEDIA += nbi -MEDIA += hd -MEDIA += raw -MEDIA += com -MEDIA += exe - -# Special target for building Master Boot Record binary -$(BIN)/mbr.bin : $(BIN)/mbr.o - $(OBJCOPY) -O binary $< $@ +MAKEDEPS += arch/i386/Makefile.$(PLATFORM) +include arch/i386/Makefile.$(PLATFORM) # Some suffixes (e.g. %.fd0) are generated directly from other # finished files (e.g. %.dsk), rather than having their own prefix. # rule to write disk images to /dev/fd0 -NON_AUTO_MEDIA += fd0 +NON_AUTO_MEDIA += fd0 %fd0 : %dsk - dd if=$< bs=512 conv=sync of=/dev/fd0 - sync + $(QM)$(ECHO) " [DD] $@" + $(Q)dd if=$< bs=512 conv=sync of=/dev/fd0 + $(Q)sync # rule to create padded disk images -NON_AUTO_MEDIA += pdsk +NON_AUTO_MEDIA += pdsk %pdsk : %dsk - cp $< $@ - $(PERL) ./util/dskpad.pl $@ - -# rule to make a non-emulation ISO boot image -NON_AUTO_MEDIA += iso -%iso: %lkrn util/geniso - ISOLINUX_BIN=$(ISOLINUX_BIN) bash util/geniso $@ $< - -# rule to make a floppy emulation ISO boot image -NON_AUTO_MEDIA += liso -%liso: %lkrn util/genliso - bash util/genliso $@ $< - -# rule to make a USB disk image -$(BIN)/usbdisk.bin : $(BIN)/usbdisk.o - $(OBJCOPY) -O binary $< $@ - -NON_AUTO_MEDIA += usb -%usb: $(BIN)/usbdisk.bin %hd - cat $^ > $@ + $(QM)$(ECHO) " [DSKPAD] $@" + $(Q)cp $< $@ + $(Q)$(PERL) ./util/dskpad.pl $@ # Add NON_AUTO_MEDIA to the media list, so that they show up in the # output of "make" # MEDIA += $(NON_AUTO_MEDIA) - -# Shortcut to allow typing just -# make bin-kir/% -# rather than -# make -f arch/i386/kir-Makefile bin-kir/% -# for building a KEEP_IT_REAL flavour. -# -$(BIN)-kir/% : kir-target - $(MAKE) -f arch/i386/kir-Makefile $(MAKECMDGOALS) - -.PHONY : kir-target diff --git a/gpxe/src/arch/i386/Makefile.efi b/gpxe/src/arch/i386/Makefile.efi new file mode 100644 index 00000000..f1eb6fdf --- /dev/null +++ b/gpxe/src/arch/i386/Makefile.efi @@ -0,0 +1,24 @@ +# -*- makefile -*- : Force emacs to use Makefile mode + +# The EFI linker script +# +LDSCRIPT = arch/i386/scripts/efi.lds + +# Use a relocatable link; we perform final relocations in the efilink utility. +# +LDFLAGS += -r -d -S + +# Media types. +# +NON_AUTO_MEDIA += efi + +# Rule for building EFI files +# +$(BIN)/%.efi.tmp-reloc : $(BIN)/%.efi.tmp $(EFILINK) + $(QM)$(ECHO) " [EFILINK] $@" + $(Q)$(LD) -e 0 -o /dev/null $< # Check for unresolved symbols + $(Q)$(EFILINK) $< $@ + +$(BIN)/%.efi : $(BIN)/%.efi.tmp-reloc + $(QM)$(ECHO) " [FINISH] $@" + $(Q)$(OBJCOPY) -Obinary $< $@ diff --git a/gpxe/src/arch/i386/Makefile.pcbios b/gpxe/src/arch/i386/Makefile.pcbios new file mode 100644 index 00000000..64b3dac2 --- /dev/null +++ b/gpxe/src/arch/i386/Makefile.pcbios @@ -0,0 +1,55 @@ +# -*- makefile -*- : Force emacs to use Makefile mode + +# The i386 linker script +# +LDSCRIPT = arch/i386/scripts/i386.lds + +# Stop ld from complaining about our customised linker script +# +LDFLAGS += -N --no-check-sections + +# Media types. +# +MEDIA += rom +MEDIA += pxe +MEDIA += kpxe +MEDIA += kkpxe +MEDIA += elf +MEDIA += elfd +MEDIA += lmelf +MEDIA += lmelfd +MEDIA += lkrn +MEDIA += bImage +MEDIA += dsk +MEDIA += nbi +MEDIA += hd +MEDIA += raw +MEDIA += com +MEDIA += exe + +# rule to make a non-emulation ISO boot image +NON_AUTO_MEDIA += iso +%iso: %lkrn util/geniso + $(QM)$(ECHO) " [GENISO] $@" + $(Q)ISOLINUX_BIN=$(ISOLINUX_BIN) bash util/geniso $@ $< + +# rule to make a floppy emulation ISO boot image +NON_AUTO_MEDIA += liso +%liso: %lkrn util/genliso + $(QM)$(ECHO) " [GENLISO] $@" + $(Q)bash util/genliso $@ $< + +# Special target for building Master Boot Record binary +$(BIN)/mbr.bin : $(BIN)/mbr.o + $(QM)$(ECHO) " [OBJCOPY] $@" + $(Q)$(OBJCOPY) -O binary $< $@ + +# rule to make a USB disk image +$(BIN)/usbdisk.bin : $(BIN)/usbdisk.o + $(QM)$(ECHO) " [OBJCOPY] $@" + $(Q)$(OBJCOPY) -O binary $< $@ + +NON_AUTO_MEDIA += usb +%usb: $(BIN)/usbdisk.bin %hd + $(QM)$(ECHO) " [FINISH] $@" + $(Q)cat $^ > $@ diff --git a/gpxe/src/arch/i386/core/gdbidt.S b/gpxe/src/arch/i386/core/gdbidt.S index 860f7b01..64c29e4b 100644 --- a/gpxe/src/arch/i386/core/gdbidt.S +++ b/gpxe/src/arch/i386/core/gdbidt.S @@ -2,7 +2,7 @@ * Interrupt Descriptor Table (IDT) setup and interrupt handlers for GDB stub. */ -#include +#include #define SIZEOF_I386_REGS 32 #define SIZEOF_I386_FLAGS 4 diff --git a/gpxe/src/arch/i386/core/gdbmach.c b/gpxe/src/arch/i386/core/gdbmach.c index 5e72e4d0..d07663c4 100644 --- a/gpxe/src/arch/i386/core/gdbmach.c +++ b/gpxe/src/arch/i386/core/gdbmach.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include diff --git a/gpxe/src/arch/i386/core/i386_timer.c b/gpxe/src/arch/i386/core/i386_timer.c deleted file mode 100644 index 8f90ae05..00000000 --- a/gpxe/src/arch/i386/core/i386_timer.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * arch/i386/core/i386_timer.c - * - * Use the "System Timer 2" to implement the udelay callback in - * the BIOS timer driver. Also used to calibrate the clock rate - * in the RTDSC timer driver. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2, or (at - * your option) any later version. - */ - -#include -#include -#include -#include - -/* Timers tick over at this rate */ -#define TIMER2_TICK_RATE 1193180U - -/* Parallel Peripheral Controller Port B */ -#define PPC_PORTB 0x61 - -/* Meaning of the port bits */ -#define PPCB_T2OUT 0x20 /* Bit 5 */ -#define PPCB_SPKR 0x02 /* Bit 1 */ -#define PPCB_T2GATE 0x01 /* Bit 0 */ - -/* Ports for the 8254 timer chip */ -#define TIMER2_PORT 0x42 -#define TIMER_MODE_PORT 0x43 - -/* Meaning of the mode bits */ -#define TIMER0_SEL 0x00 -#define TIMER1_SEL 0x40 -#define TIMER2_SEL 0x80 -#define READBACK_SEL 0xC0 - -#define LATCH_COUNT 0x00 -#define LOBYTE_ACCESS 0x10 -#define HIBYTE_ACCESS 0x20 -#define WORD_ACCESS 0x30 - -#define MODE0 0x00 -#define MODE1 0x02 -#define MODE2 0x04 -#define MODE3 0x06 -#define MODE4 0x08 -#define MODE5 0x0A - -#define BINARY_COUNT 0x00 -#define BCD_COUNT 0x01 - -static void load_timer2(unsigned int ticks) -{ - /* - * Now let's take care of PPC channel 2 - * - * Set the Gate high, program PPC channel 2 for mode 0, - * (interrupt on terminal count mode), binary count, - * load 5 * LATCH count, (LSB and MSB) to begin countdown. - * - * Note some implementations have a bug where the high bits byte - * of channel 2 is ignored. - */ - /* Set up the timer gate, turn off the speaker */ - /* Set the Gate high, disable speaker */ - outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB); - /* binary, mode 0, LSB/MSB, Ch 2 */ - outb(TIMER2_SEL|WORD_ACCESS|MODE0|BINARY_COUNT, TIMER_MODE_PORT); - /* LSB of ticks */ - outb(ticks & 0xFF, TIMER2_PORT); - /* MSB of ticks */ - outb(ticks >> 8, TIMER2_PORT); -} - -static int timer2_running(void) -{ - return ((inb(PPC_PORTB) & PPCB_T2OUT) == 0); -} - -void i386_timer2_udelay(unsigned int usecs) -{ - load_timer2((usecs * TIMER2_TICK_RATE)/USECS_IN_SEC); - while (timer2_running()) - ; -} - diff --git a/gpxe/src/arch/i386/core/nap.c b/gpxe/src/arch/i386/core/nap.c deleted file mode 100644 index 12bb5699..00000000 --- a/gpxe/src/arch/i386/core/nap.c +++ /dev/null @@ -1,12 +0,0 @@ - -#include -#include - -/************************************************************************** - * Save power by halting the CPU until the next interrupt - **************************************************************************/ -void cpu_nap ( void ) { - __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" - "hlt\n\t" - "cli\n\t" ) : : ); -} diff --git a/gpxe/src/arch/i386/core/pcibios.c b/gpxe/src/arch/i386/core/pcibios.c deleted file mode 100644 index 1c93e4be..00000000 --- a/gpxe/src/arch/i386/core/pcibios.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2006 Michael Brown . - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -/** @file - * - * PCI configuration space access via PCI BIOS - * - */ - -/** - * Determine maximum PCI bus number within system - * - * @ret max_bus Maximum bus number - */ -int pcibios_max_bus ( void ) { - int discard_a, discard_D; - uint8_t max_bus; - - __asm__ __volatile__ ( REAL_CODE ( "stc\n\t" - "int $0x1a\n\t" - "jnc 1f\n\t" - "xorw %%cx, %%cx\n\t" - "\n1:\n\t" ) - : "=c" ( max_bus ), "=a" ( discard_a ), - "=D" ( discard_D ) - : "a" ( PCIBIOS_INSTALLATION_CHECK >> 16 ), - "D" ( 0 ) - : "ebx", "edx" ); - - return max_bus; -} - -/** - * Read configuration space via PCI BIOS - * - * @v pci PCI device - * @v command PCI BIOS command - * @v value Value read - * @ret rc Return status code - */ -int pcibios_read ( struct pci_device *pci, uint32_t command, uint32_t *value ){ - int discard_b, discard_D; - int status; - - __asm__ __volatile__ ( REAL_CODE ( "stc\n\t" - "int $0x1a\n\t" - "jnc 1f\n\t" - "xorl %%eax, %%eax\n\t" - "decl %%eax\n\t" - "movl %%eax, %%ecx\n\t" - "\n1:\n\t" ) - : "=a" ( status ), "=b" ( discard_b ), - "=c" ( *value ), "=D" ( discard_D ) - : "a" ( command >> 16 ), "D" ( command ), - "b" ( PCI_BUSDEVFN ( pci->bus, pci->devfn ) ) - : "edx" ); - - return ( ( status >> 8 ) & 0xff ); -} - -/** - * Write configuration space via PCI BIOS - * - * @v pci PCI device - * @v command PCI BIOS command - * @v value Value to be written - * @ret rc Return status code - */ -int pcibios_write ( struct pci_device *pci, uint32_t command, uint32_t value ){ - int discard_b, discard_c, discard_D; - int status; - - __asm__ __volatile__ ( REAL_CODE ( "stc\n\t" - "int $0x1a\n\t" - "jnc 1f\n\t" - "movb $0xff, %%ah\n\t" - "\n1:\n\t" ) - : "=a" ( status ), "=b" ( discard_b ), - "=c" ( discard_c ), "=D" ( discard_D ) - : "a" ( command >> 16 ), "D" ( command ), - "b" ( PCI_BUSDEVFN ( pci->bus, pci->devfn ) ), - "c" ( value ) - : "edx" ); - - return ( ( status >> 8 ) & 0xff ); -} diff --git a/gpxe/src/arch/i386/core/pcidirect.c b/gpxe/src/arch/i386/core/pcidirect.c index 2ed8c2ad..fec2e3c1 100644 --- a/gpxe/src/arch/i386/core/pcidirect.c +++ b/gpxe/src/arch/i386/core/pcidirect.c @@ -17,7 +17,6 @@ */ #include -#include /** @file * @@ -36,3 +35,10 @@ void pcidirect_prepare ( struct pci_device *pci, int where ) { ( where & ~3 ) ), PCIDIRECT_CONFIG_ADDRESS ); } +PROVIDE_PCIAPI_INLINE ( direct, pci_max_bus ); +PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_byte ); +PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_word ); +PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_dword ); +PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_byte ); +PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_word ); +PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_dword ); diff --git a/gpxe/src/arch/i386/core/pic8259.c b/gpxe/src/arch/i386/core/pic8259.c index defe2e7d..8a0433dd 100644 --- a/gpxe/src/arch/i386/core/pic8259.c +++ b/gpxe/src/arch/i386/core/pic8259.c @@ -16,6 +16,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include /** @file diff --git a/gpxe/src/arch/i386/core/rdtsc_timer.c b/gpxe/src/arch/i386/core/rdtsc_timer.c new file mode 100644 index 00000000..443c8ada --- /dev/null +++ b/gpxe/src/arch/i386/core/rdtsc_timer.c @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2008 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/** @file + * + * RDTSC timer + * + */ + +#include +#include +#include + +/** + * Number of TSC ticks per microsecond + * + * This is calibrated on the first use of the timer. + */ +static unsigned long rdtsc_ticks_per_usec; + +/** + * Delay for a fixed number of microseconds + * + * @v usecs Number of microseconds for which to delay + */ +static void rdtsc_udelay ( unsigned long usecs ) { + unsigned long start; + unsigned long elapsed; + + /* Sanity guard, since we may divide by this */ + if ( ! usecs ) + usecs = 1; + + start = currticks(); + if ( rdtsc_ticks_per_usec ) { + /* Already calibrated; busy-wait until done */ + do { + elapsed = ( currticks() - start ); + } while ( elapsed < ( usecs * rdtsc_ticks_per_usec ) ); + } else { + /* Not yet calibrated; use timer2 and calibrate + * based on result. + */ + timer2_udelay ( usecs ); + elapsed = ( currticks() - start ); + rdtsc_ticks_per_usec = ( elapsed / usecs ); + DBG ( "RDTSC timer calibrated: %ld ticks in %ld usecs " + "(%ld MHz)\n", elapsed, usecs, + ( rdtsc_ticks_per_usec << TSC_SHIFT ) ); + } +} + +/** + * Get number of ticks per second + * + * @ret ticks_per_sec Number of ticks per second + */ +static unsigned long rdtsc_ticks_per_sec ( void ) { + + /* Calibrate timer, if not already done */ + if ( ! rdtsc_ticks_per_usec ) + udelay ( 1 ); + + /* Sanity check */ + assert ( rdtsc_ticks_per_usec != 0 ); + + return ( rdtsc_ticks_per_usec * 1000 * 1000 ); +} + +PROVIDE_TIMER ( rdtsc, udelay, rdtsc_udelay ); +PROVIDE_TIMER_INLINE ( rdtsc, currticks ); +PROVIDE_TIMER ( rdtsc, ticks_per_sec, rdtsc_ticks_per_sec ); diff --git a/gpxe/src/arch/i386/core/relocate.c b/gpxe/src/arch/i386/core/relocate.c index aa58ad65..fd8df087 100644 --- a/gpxe/src/arch/i386/core/relocate.c +++ b/gpxe/src/arch/i386/core/relocate.c @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -18,8 +18,8 @@ extern char _max_align[]; #define max_align ( ( unsigned int ) _max_align ) /* Linker symbols */ -extern char _text[]; -extern char _end[]; +extern char _textdata[]; +extern char _etextdata[]; /* within 1MB of 4GB is too close. * MAX_ADDR is the maximum address we can easily do DMA to. @@ -47,8 +47,8 @@ __cdecl void relocate ( struct i386_all_regs *ix86 ) { /* Get memory map and current location */ get_memmap ( &memmap ); - start = virt_to_phys ( _text ); - end = virt_to_phys ( _end ); + start = virt_to_phys ( _textdata ); + end = virt_to_phys ( _etextdata ); size = ( end - start ); padded_size = ( size + max_align - 1 ); diff --git a/gpxe/src/arch/i386/core/start32.S b/gpxe/src/arch/i386/core/start32.S deleted file mode 100644 index 37ef5eb9..00000000 --- a/gpxe/src/arch/i386/core/start32.S +++ /dev/null @@ -1,325 +0,0 @@ -#include "virtaddr.h" - - .equ MSR_K6_EFER, 0xC0000080 - .equ EFER_LME, 0x00000100 - .equ X86_CR4_PAE, 0x00000020 - .equ CR0_PG, 0x80000000 - -#ifdef GAS291 -#define DATA32 data32; -#define ADDR32 addr32; -#define LJMPI(x) ljmp x -#else -#define DATA32 data32 -#define ADDR32 addr32 -/* newer GAS295 require #define LJMPI(x) ljmp *x */ -#define LJMPI(x) ljmp x -#endif - -/* - * NOTE: if you write a subroutine that is called from C code (gcc/egcs), - * then you only have to take care of %ebx, %esi, %edi and %ebp. These - * registers must not be altered under any circumstance. All other registers - * may be clobbered without any negative side effects. If you don't follow - * this rule then you'll run into strange effects that only occur on some - * gcc versions (because the register allocator may use different registers). - * - * All the data32 prefixes for the ljmp instructions are necessary, because - * the assembler emits code with a relocation address of 0. This means that - * all destinations are initially negative, which the assembler doesn't grok, - * because for some reason negative numbers don't fit into 16 bits. The addr32 - * prefixes are there for the same reasons, because otherwise the memory - * references are only 16 bit wide. Theoretically they are all superfluous. - * One last note about prefixes: the data32 prefixes on all call _real_to_prot - * instructions could be removed if the _real_to_prot function is changed to - * deal correctly with 16 bit return addresses. I tried it, but failed. - */ - - .text - .arch i386 - .code32 - - /* This is a struct os_entry_regs */ - .globl os_regs -os_regs: .space 56 - -/************************************************************************** -XSTART32 - Transfer control to the kernel just loaded -**************************************************************************/ - .globl xstart32 -xstart32: - /* Save the callee save registers */ - movl %ebp, os_regs + 32 - movl %esi, os_regs + 36 - movl %edi, os_regs + 40 - movl %ebx, os_regs + 44 - - /* save the return address */ - popl %eax - movl %eax, os_regs + 48 - - /* save the stack pointer */ - movl %esp, os_regs + 52 - - /* Get the new destination address */ - popl %ecx - - /* Store the physical address of xend on the stack */ - movl $xend32, %ebx - addl virt_offset, %ebx - pushl %ebx - - /* Store the destination address on the stack */ - pushl $PHYSICAL_CS - pushl %ecx - - /* Cache virt_offset */ - movl virt_offset, %ebp - - /* Switch to using physical addresses */ - call _virt_to_phys - - /* Save the target stack pointer */ - movl %esp, os_regs + 12(%ebp) - leal os_regs(%ebp), %esp - - /* Store the pointer to os_regs */ - movl %esp, os_regs_ptr(%ebp) - - /* Load my new registers */ - popal - movl (-32 + 12)(%esp), %esp - - /* Jump to the new kernel - * The lret switches to a flat code segment - */ - lret - - .balign 4 - .globl xend32 -xend32: - /* Fixup %eflags */ - nop - cli - cld - - /* Load %esp with &os_regs + virt_offset */ - .byte 0xbc /* movl $0, %esp */ -os_regs_ptr: - .long 0 - - /* Save the result registers */ - addl $32, %esp - pushal - - /* Compute virt_offset */ - movl %esp, %ebp - subl $os_regs, %ebp - - /* Load the stack pointer and convert it to physical address */ - movl 52(%esp), %esp - addl %ebp, %esp - - /* Enable the virtual addresses */ - leal _phys_to_virt(%ebp), %eax - call *%eax - - /* Restore the callee save registers */ - movl os_regs + 32, %ebp - movl os_regs + 36, %esi - movl os_regs + 40, %edi - movl os_regs + 44, %ebx - movl os_regs + 48, %edx - movl os_regs + 52, %esp - - /* Get the C return value */ - movl os_regs + 28, %eax - - jmpl *%edx - -#ifdef CONFIG_X86_64 - .arch sledgehammer -/************************************************************************** -XSTART_lm - Transfer control to the kernel just loaded in long mode -**************************************************************************/ - .globl xstart_lm -xstart_lm: - /* Save the callee save registers */ - pushl %ebp - pushl %esi - pushl %edi - pushl %ebx - - /* Cache virt_offset && (virt_offset & 0xfffff000) */ - movl virt_offset, %ebp - movl %ebp, %ebx - andl $0xfffff000, %ebx - - /* Switch to using physical addresses */ - call _virt_to_phys - - /* Initialize the page tables */ - /* Level 4 */ - leal 0x23 + pgt_level3(%ebx), %eax - leal pgt_level4(%ebx), %edi - movl %eax, (%edi) - - /* Level 3 */ - leal 0x23 + pgt_level2(%ebx), %eax - leal pgt_level3(%ebx), %edi - movl %eax, 0x00(%edi) - addl $4096, %eax - movl %eax, 0x08(%edi) - addl $4096, %eax - movl %eax, 0x10(%edi) - addl $4096, %eax - movl %eax, 0x18(%edi) - - /* Level 2 */ - movl $0xe3, %eax - leal pgt_level2(%ebx), %edi - leal 16384(%edi), %esi -pgt_level2_loop: - movl %eax, (%edi) - addl $8, %edi - addl $0x200000, %eax - cmp %esi, %edi - jne pgt_level2_loop - - /* Point at the x86_64 page tables */ - leal pgt_level4(%ebx), %edi - movl %edi, %cr3 - - - /* Setup for the return from 64bit mode */ - /* 64bit align the stack */ - movl %esp, %ebx /* original stack pointer + 16 */ - andl $0xfffffff8, %esp - - /* Save original stack pointer + 16 */ - pushl %ebx - - /* Save virt_offset */ - pushl %ebp - - /* Setup for the jmp to 64bit long mode */ - leal start_lm(%ebp), %eax - movl %eax, 0x00 + start_lm_addr(%ebp) - movl $LM_CODE_SEG, %eax - movl %eax, 0x04 + start_lm_addr(%ebp) - - /* Setup for the jump out of 64bit long mode */ - leal end_lm(%ebp), %eax - movl %eax, 0x00 + end_lm_addr(%ebp) - movl $FLAT_CODE_SEG, %eax - movl %eax, 0x04 + end_lm_addr(%ebp) - - /* Enable PAE mode */ - movl %cr4, %eax - orl $X86_CR4_PAE, %eax - movl %eax, %cr4 - - /* Enable long mode */ - movl $MSR_K6_EFER, %ecx - rdmsr - orl $EFER_LME, %eax - wrmsr - - /* Start paging, entering 32bit compatiblity mode */ - movl %cr0, %eax - orl $CR0_PG, %eax - movl %eax, %cr0 - - /* Enter 64bit long mode */ - ljmp *start_lm_addr(%ebp) - .code64 -start_lm: - /* Load 64bit data segments */ - movl $LM_DATA_SEG, %eax - movl %eax, %ds - movl %eax, %es - movl %eax, %ss - - andq $0xffffffff, %rbx - /* Get the address to jump to */ - movl 20(%rbx), %edx - andq $0xffffffff, %rdx - - /* Get the argument pointer */ - movl 24(%rbx), %ebx - andq $0xffffffff, %rbx - - /* Jump to the 64bit code */ - call *%rdx - - /* Preserve the result */ - movl %eax, %edx - - /* Fixup %eflags */ - cli - cld - - /* Switch to 32bit compatibility mode */ - ljmp *end_lm_addr(%rip) - - .code32 -end_lm: - /* Disable paging */ - movl %cr0, %eax - andl $~CR0_PG, %eax - movl %eax, %cr0 - - /* Disable long mode */ - movl $MSR_K6_EFER, %ecx - rdmsr - andl $~EFER_LME, %eax - wrmsr - - /* Disable PAE */ - movl %cr4, %eax - andl $~X86_CR4_PAE, %eax - movl %eax, %cr4 - - /* Compute virt_offset */ - popl %ebp - - /* Compute the original stack pointer + 16 */ - popl %ebx - movl %ebx, %esp - - /* Enable the virtual addresses */ - leal _phys_to_virt(%ebp), %eax - call *%eax - - /* Restore the callee save registers */ - popl %ebx - popl %esi - popl %edi - popl %ebp - - /* Get the C return value */ - movl %edx, %eax - - /* Return */ - ret - - .arch i386 -#endif /* CONFIG_X86_64 */ - -#ifdef CONFIG_X86_64 - .section ".bss" - .p2align 12 - /* Include a dummy space in case we are loaded badly aligned */ - .space 4096 - /* Reserve enough space for a page table convering 4GB with 2MB pages */ -pgt_level4: - .space 4096 -pgt_level3: - .space 4096 -pgt_level2: - .space 16384 -start_lm_addr: - .space 8 -end_lm_addr: - .space 8 -#endif diff --git a/gpxe/src/arch/i386/core/timer2.c b/gpxe/src/arch/i386/core/timer2.c new file mode 100644 index 00000000..bb589ecc --- /dev/null +++ b/gpxe/src/arch/i386/core/timer2.c @@ -0,0 +1,85 @@ +/* + * arch/i386/core/i386_timer.c + * + * Use the "System Timer 2" to implement the udelay callback in + * the BIOS timer driver. Also used to calibrate the clock rate + * in the RTDSC timer driver. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2, or (at + * your option) any later version. + */ + +#include +#include +#include + +/* Timers tick over at this rate */ +#define TIMER2_TICKS_PER_SEC 1193180U + +/* Parallel Peripheral Controller Port B */ +#define PPC_PORTB 0x61 + +/* Meaning of the port bits */ +#define PPCB_T2OUT 0x20 /* Bit 5 */ +#define PPCB_SPKR 0x02 /* Bit 1 */ +#define PPCB_T2GATE 0x01 /* Bit 0 */ + +/* Ports for the 8254 timer chip */ +#define TIMER2_PORT 0x42 +#define TIMER_MODE_PORT 0x43 + +/* Meaning of the mode bits */ +#define TIMER0_SEL 0x00 +#define TIMER1_SEL 0x40 +#define TIMER2_SEL 0x80 +#define READBACK_SEL 0xC0 + +#define LATCH_COUNT 0x00 +#define LOBYTE_ACCESS 0x10 +#define HIBYTE_ACCESS 0x20 +#define WORD_ACCESS 0x30 + +#define MODE0 0x00 +#define MODE1 0x02 +#define MODE2 0x04 +#define MODE3 0x06 +#define MODE4 0x08 +#define MODE5 0x0A + +#define BINARY_COUNT 0x00 +#define BCD_COUNT 0x01 + +static void load_timer2 ( unsigned int ticks ) { + /* + * Now let's take care of PPC channel 2 + * + * Set the Gate high, program PPC channel 2 for mode 0, + * (interrupt on terminal count mode), binary count, + * load 5 * LATCH count, (LSB and MSB) to begin countdown. + * + * Note some implementations have a bug where the high bits byte + * of channel 2 is ignored. + */ + /* Set up the timer gate, turn off the speaker */ + /* Set the Gate high, disable speaker */ + outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB); + /* binary, mode 0, LSB/MSB, Ch 2 */ + outb(TIMER2_SEL|WORD_ACCESS|MODE0|BINARY_COUNT, TIMER_MODE_PORT); + /* LSB of ticks */ + outb(ticks & 0xFF, TIMER2_PORT); + /* MSB of ticks */ + outb(ticks >> 8, TIMER2_PORT); +} + +static int timer2_running ( void ) { + return ((inb(PPC_PORTB) & PPCB_T2OUT) == 0); +} + +void timer2_udelay ( unsigned long usecs ) { + load_timer2 ( ( usecs * TIMER2_TICKS_PER_SEC ) / ( 1000 * 1000 ) ); + while (timer2_running()) { + /* Do nothing */ + } +} diff --git a/gpxe/src/arch/i386/core/umalloc.c b/gpxe/src/arch/i386/core/umalloc.c deleted file mode 100644 index 3990488c..00000000 --- a/gpxe/src/arch/i386/core/umalloc.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (C) 2007 Michael Brown . - * - * 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 - * - * External memory allocation - * - */ - -#include -#include -#include -#include -#include -#include - -/** Alignment of external allocated memory */ -#define EM_ALIGN ( 4 * 1024 ) - -/** Equivalent of NOWHERE for user pointers */ -#define UNOWHERE ( ~UNULL ) - -/** Start of Etherboot text, as defined by the linker */ -extern char _text[]; - -/** An external memory block */ -struct external_memory { - /** Size of this memory block (excluding this header) */ - size_t size; - /** Block is currently in use */ - int used; -}; - -/** Top of heap */ -static userptr_t top = UNULL; - -/** Bottom of heap (current lowest allocated block) */ -static userptr_t bottom = UNULL; - -/** - * 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; - } - } - - if ( ! top ) { - DBG ( "No external heap available\n" ); - return -ENOMEM; - } - - DBG ( "External heap grows downwards from %lx\n", - user_to_phys ( top, 0 ) ); - return 0; -} - -/** - * Collect free blocks - * - */ -static void ecollect_free ( void ) { - struct external_memory extmem; - - /* Walk the free list and collect empty blocks */ - while ( bottom != top ) { - copy_from_user ( &extmem, bottom, -sizeof ( extmem ), - sizeof ( extmem ) ); - if ( extmem.used ) - 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 ) ) ); - } -} - -/** - * Reallocate external memory - * - * @v old_ptr Memory previously allocated by umalloc(), or UNULL - * @v new_size Requested size - * @ret new_ptr Allocated memory, or UNULL - * - * Calling realloc() with a new size of zero is a valid way to free a - * memory block. - */ -userptr_t 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 ( ! top ) { - if ( ( rc = init_eheap() ) != 0 ) - return rc; - } - - /* Get block properties into extmem */ - if ( ptr && ( ptr != UNOWHERE ) ) { - /* Determine old size */ - copy_from_user ( &extmem, ptr, -sizeof ( extmem ), - sizeof ( extmem ) ); - } else { - /* Create a zero-length block */ - ptr = bottom = userptr_add ( bottom, -sizeof ( extmem ) ); - DBG ( "EXTMEM allocating [%lx,%lx)\n", - user_to_phys ( ptr, 0 ), user_to_phys ( ptr, 0 ) ); - extmem.size = 0; - } - extmem.used = ( new_size > 0 ); - - /* Expand/shrink block if possible */ - if ( ptr == bottom ) { - /* Update block */ - new = userptr_add ( ptr, - ( new_size - extmem.size ) ); - align = ( user_to_phys ( new, 0 ) & ( EM_ALIGN - 1 ) ); - new_size += align; - new = userptr_add ( new, -align ); - DBG ( "EXTMEM expanding [%lx,%lx) to [%lx,%lx)\n", - user_to_phys ( ptr, 0 ), - user_to_phys ( ptr, extmem.size ), - user_to_phys ( new, 0 ), - 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; - } else { - /* Cannot expand; can only pretend to shrink */ - if ( new_size > extmem.size ) { - /* Refuse to expand */ - DBG ( "EXTMEM cannot expand [%lx,%lx)\n", - user_to_phys ( ptr, 0 ), - user_to_phys ( ptr, extmem.size ) ); - return UNULL; - } - } - - /* Write back block properties */ - copy_to_user ( new, -sizeof ( extmem ), &extmem, - sizeof ( extmem ) ); - - /* Collect any free blocks and update hidden memory region */ - ecollect_free(); - hide_umalloc ( user_to_phys ( bottom, -sizeof ( extmem ) ), - user_to_phys ( top, 0 ) ); - - return ( new_size ? new : UNOWHERE ); -} - -/** - * Allocate external memory - * - * @v size Requested size - * @ret ptr Memory, or UNULL - * - * Memory is guaranteed to be aligned to a page boundary. - */ -userptr_t umalloc ( size_t size ) { - return urealloc ( UNULL, size ); -} - -/** - * Free external memory - * - * @v ptr Memory allocated by umalloc(), or UNULL - * - * If @c ptr is UNULL, no action is taken. - */ -void ufree ( userptr_t ptr ) { - urealloc ( ptr, 0 ); -} diff --git a/gpxe/src/arch/i386/core/video_subr.c b/gpxe/src/arch/i386/core/video_subr.c index bf82cc61..c821cd02 100644 --- a/gpxe/src/arch/i386/core/video_subr.c +++ b/gpxe/src/arch/i386/core/video_subr.c @@ -7,7 +7,7 @@ #include "stddef.h" #include "string.h" -#include "io.h" +#include #include "console.h" #include #include "vga.h" diff --git a/gpxe/src/arch/i386/core/virtaddr.S b/gpxe/src/arch/i386/core/virtaddr.S index 5d762375..cf6da4f6 100644 --- a/gpxe/src/arch/i386/core/virtaddr.S +++ b/gpxe/src/arch/i386/core/virtaddr.S @@ -4,7 +4,7 @@ * */ -#include "virtaddr.h" +#include "librm.h" .arch i386 .text diff --git a/gpxe/src/arch/i386/core/x86_io.c b/gpxe/src/arch/i386/core/x86_io.c new file mode 100644 index 00000000..424a96cc --- /dev/null +++ b/gpxe/src/arch/i386/core/x86_io.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2008 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +/** @file + * + * gPXE I/O API for x86 + * + */ + +/** + * Read 64-bit qword from memory-mapped device + * + * @v io_addr I/O address + * @ret data Value read + * + * This routine uses MMX instructions. + */ +static uint64_t x86_readq ( volatile uint64_t *io_addr ) { + uint64_t data; + __asm__ __volatile__ ( "pushl %%edx\n\t" + "pushl %%eax\n\t" + "movq (%1), %%mm0\n\t" + "movq %%mm0, (%%esp)\n\t" + "popl %%eax\n\t" + "popl %%edx\n\t" + "emms\n\t" + : "=A" ( data ) : "r" ( io_addr ) ); + return data; +} + +/** + * Write 64-bit qword to memory-mapped device + * + * @v data Value to write + * @v io_addr I/O address + * + * This routine uses MMX instructions. + */ +static void x86_writeq ( uint64_t data, volatile uint64_t *io_addr ) { + __asm__ __volatile__ ( "pushl %%edx\n\t" + "pushl %%eax\n\t" + "movq (%%esp), %%mm0\n\t" + "movq %%mm0, (%1)\n\t" + "popl %%eax\n\t" + "popl %%edx\n\t" + "emms\n\t" + : : "A" ( data ), "r" ( io_addr ) ); +} + +PROVIDE_IOAPI_INLINE ( x86, phys_to_bus ); +PROVIDE_IOAPI_INLINE ( x86, bus_to_phys ); +PROVIDE_IOAPI_INLINE ( x86, ioremap ); +PROVIDE_IOAPI_INLINE ( x86, iounmap ); +PROVIDE_IOAPI_INLINE ( x86, io_to_bus ); +PROVIDE_IOAPI_INLINE ( x86, readb ); +PROVIDE_IOAPI_INLINE ( x86, readw ); +PROVIDE_IOAPI_INLINE ( x86, readl ); +PROVIDE_IOAPI ( x86, readq, x86_readq ); +PROVIDE_IOAPI_INLINE ( x86, writeb ); +PROVIDE_IOAPI_INLINE ( x86, writew ); +PROVIDE_IOAPI_INLINE ( x86, writel ); +PROVIDE_IOAPI ( x86, writeq, x86_writeq ); +PROVIDE_IOAPI_INLINE ( x86, inb ); +PROVIDE_IOAPI_INLINE ( x86, inw ); +PROVIDE_IOAPI_INLINE ( x86, inl ); +PROVIDE_IOAPI_INLINE ( x86, outb ); +PROVIDE_IOAPI_INLINE ( x86, outw ); +PROVIDE_IOAPI_INLINE ( x86, outl ); +PROVIDE_IOAPI_INLINE ( x86, insb ); +PROVIDE_IOAPI_INLINE ( x86, insw ); +PROVIDE_IOAPI_INLINE ( x86, insl ); +PROVIDE_IOAPI_INLINE ( x86, outsb ); +PROVIDE_IOAPI_INLINE ( x86, outsw ); +PROVIDE_IOAPI_INLINE ( x86, outsl ); +PROVIDE_IOAPI_INLINE ( x86, iodelay ); +PROVIDE_IOAPI_INLINE ( x86, mb ); diff --git a/gpxe/src/arch/i386/drivers/net/undinet.c b/gpxe/src/arch/i386/drivers/net/undinet.c index 9576ad60..6ce4d924 100644 --- a/gpxe/src/arch/i386/drivers/net/undinet.c +++ b/gpxe/src/arch/i386/drivers/net/undinet.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -554,7 +555,7 @@ static int undinet_open ( struct net_device *netdev ) { DBGC ( undinic, "UNDINIC %p opened\n", undinic ); return 0; -err: + err: undinet_close ( netdev ); return rc; } @@ -595,10 +596,6 @@ static void undinet_close ( struct net_device *netdev ) { /* Disable interrupt and unhook ISR */ disable_irq ( undinic->irq ); undinet_unhook_isr ( undinic->irq ); -#if 0 - enable_irq ( undinic->irq ); - send_eoi ( undinic->irq ); -#endif DBGC ( undinic, "UNDINIC %p closed\n", undinic ); } @@ -642,9 +639,7 @@ int undinet_probe ( struct undi_device *undi ) { struct s_PXENV_UNDI_GET_IFACE_INFO undi_iface; struct s_PXENV_UNDI_SHUTDOWN undi_shutdown; struct s_PXENV_UNDI_CLEANUP undi_cleanup; -#if 0 struct s_PXENV_STOP_UNDI stop_undi; -#endif int rc; /* Allocate net device */ @@ -671,20 +666,23 @@ int undinet_probe ( struct undi_device *undi ) { &start_undi, sizeof ( start_undi ) ) ) != 0 ) goto err_start_undi; - /* Bring up UNDI stack */ + } + undi->flags |= UNDI_FL_STARTED; + + /* Bring up UNDI stack */ + if ( ! ( undi->flags & UNDI_FL_INITIALIZED ) ) { memset ( &undi_startup, 0, sizeof ( undi_startup ) ); if ( ( rc = undinet_call ( undinic, PXENV_UNDI_STARTUP, &undi_startup, sizeof ( undi_startup ) ) ) != 0 ) - goto err_undi_startup; - + goto err_undi_startup; memset ( &undi_initialize, 0, sizeof ( undi_initialize ) ); if ( ( rc = undinet_call ( undinic, PXENV_UNDI_INITIALIZE, &undi_initialize, - sizeof ( undi_initialize ) ) ) != 0 ) - goto err_undi_initialize; + sizeof ( undi_initialize ))) != 0 ) + goto err_undi_initialize; } - undi->flags |= UNDI_FL_STARTED; + undi->flags |= UNDI_FL_INITIALIZED; /* Get device information */ memset ( &undi_info, 0, sizeof ( undi_info ) ); @@ -731,7 +729,6 @@ int undinet_probe ( struct undi_device *undi ) { err_bad_irq: err_undi_get_information: err_undi_initialize: - /* Shut down UNDI stack */ memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) ); undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown, @@ -739,13 +736,13 @@ int undinet_probe ( struct undi_device *undi ) { memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) ); undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup, sizeof ( undi_cleanup ) ); + undi->flags &= ~UNDI_FL_INITIALIZED; err_undi_startup: -#if 0 /* Unhook UNDI stack */ memset ( &stop_undi, 0, sizeof ( stop_undi ) ); undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi, sizeof ( stop_undi ) ); -#endif + undi->flags &= ~UNDI_FL_STARTED; err_start_undi: netdev_nullify ( netdev ); netdev_put ( netdev ); @@ -761,30 +758,33 @@ int undinet_probe ( struct undi_device *undi ) { void undinet_remove ( struct undi_device *undi ) { struct net_device *netdev = undi_get_drvdata ( undi ); struct undi_nic *undinic = netdev->priv; -#if 0 struct s_PXENV_UNDI_SHUTDOWN undi_shutdown; struct s_PXENV_UNDI_CLEANUP undi_cleanup; struct s_PXENV_STOP_UNDI stop_undi; -#endif /* Unregister net device */ unregister_netdev ( netdev ); - /* Shut down UNDI stack */ -#if 0 - memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) ); - undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown, - sizeof ( undi_shutdown ) ); - memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) ); - undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup, - sizeof ( undi_cleanup ) ); - - /* Unhook UNDI stack */ - memset ( &stop_undi, 0, sizeof ( stop_undi ) ); - undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi, - sizeof ( stop_undi ) ); - undi->flags &= ~UNDI_FL_STARTED; -#endif + /* If we are preparing for an OS boot, or if we cannot exit + * via the PXE stack, then shut down the PXE stack. + */ + if ( ! ( undi->flags & UNDI_FL_KEEP_ALL ) ) { + + /* Shut down UNDI stack */ + memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) ); + undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown, + sizeof ( undi_shutdown ) ); + memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) ); + undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup, + sizeof ( undi_cleanup ) ); + undi->flags &= ~UNDI_FL_INITIALIZED; + + /* Unhook UNDI stack */ + memset ( &stop_undi, 0, sizeof ( stop_undi ) ); + undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi, + sizeof ( stop_undi ) ); + undi->flags &= ~UNDI_FL_STARTED; + } /* Clear entry point */ memset ( &undinet_entry_point, 0, sizeof ( undinet_entry_point ) ); diff --git a/gpxe/src/arch/i386/drivers/net/undionly.c b/gpxe/src/arch/i386/drivers/net/undionly.c index ee361493..4cdce677 100644 --- a/gpxe/src/arch/i386/drivers/net/undionly.c +++ b/gpxe/src/arch/i386/drivers/net/undionly.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -107,3 +108,20 @@ struct root_device undi_root_device __root_device = { .dev = { .name = "UNDI" }, .driver = &undi_root_driver, }; + +/** + * Prepare for exit + * + * @v flags Shutdown flags + */ +static void undionly_shutdown ( int flags ) { + /* If we are shutting down to boot an OS, clear the "keep PXE + * stack" flag. + */ + if ( flags & SHUTDOWN_BOOT ) + preloaded_undi.flags &= ~UNDI_FL_KEEP_ALL; +} + +struct startup_fn startup_undionly __startup_fn ( STARTUP_LATE ) = { + .shutdown = undionly_shutdown, +}; diff --git a/gpxe/src/arch/i386/drivers/timer_bios.c b/gpxe/src/arch/i386/drivers/timer_bios.c deleted file mode 100644 index f9caf8d9..00000000 --- a/gpxe/src/arch/i386/drivers/timer_bios.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Etherboot routines for PCBIOS firmware. - * - * Body of routines taken from old pcbios.S - */ - -#include -#include -#include -#include -#include -#include - -/* A bit faster actually, but we don't care. */ -#define TIMER2_TICKS_PER_SEC 18 - -/* - * Use direct memory access to BIOS variables, longword 0040:006C (ticks - * today) and byte 0040:0070 (midnight crossover flag) instead of calling - * timeofday BIOS interrupt. - */ - -static tick_t bios_currticks ( void ) { - static int days = 0; - uint32_t ticks; - uint8_t midnight; - - /* Re-enable interrupts so that the timer interrupt can occur */ - __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" - "nop\n\t" - "nop\n\t" - "cli\n\t" ) : : ); - - get_real ( ticks, BDA_SEG, 0x006c ); - get_real ( midnight, BDA_SEG, 0x0070 ); - - if ( midnight ) { - midnight = 0; - put_real ( midnight, BDA_SEG, 0x0070 ); - days += 0x1800b0; - } - - return ( (days + ticks) * (USECS_IN_SEC / TIMER2_TICKS_PER_SEC) ); -} - -static int bios_ts_init(void) -{ - DBG("BIOS timer installed\n"); - return 0; -} - -struct timer bios_ts __timer ( 02 ) = { - .init = bios_ts_init, - .udelay = i386_timer2_udelay, - .currticks = bios_currticks, -}; - diff --git a/gpxe/src/arch/i386/drivers/timer_rdtsc.c b/gpxe/src/arch/i386/drivers/timer_rdtsc.c deleted file mode 100644 index 09b7df2f..00000000 --- a/gpxe/src/arch/i386/drivers/timer_rdtsc.c +++ /dev/null @@ -1,69 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include - - -#define rdtsc(low,high) \ - __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) - -#define rdtscll(val) \ - __asm__ __volatile__ ("rdtsc" : "=A" (val)) - - -/* Measure how many clocks we get in one microsecond */ -static inline uint64_t calibrate_tsc(void) -{ - - uint64_t rdtsc_start; - uint64_t rdtsc_end; - - rdtscll(rdtsc_start); - i386_timer2_udelay(USECS_IN_MSEC); - rdtscll(rdtsc_end); - - return (rdtsc_end - rdtsc_start) / USECS_IN_MSEC; -} - -static uint32_t clocks_per_usec = 0; - -/* We measure time in microseconds. */ -static tick_t rdtsc_currticks(void) -{ - uint64_t clocks; - - /* Read the Time Stamp Counter */ - rdtscll(clocks); - - return clocks / clocks_per_usec; -} - -static int rdtsc_ts_init(void) -{ - - struct cpuinfo_x86 cpu_info; - - get_cpuinfo(&cpu_info); - if (cpu_info.features & X86_FEATURE_TSC) { - clocks_per_usec= calibrate_tsc(); - if (clocks_per_usec) { - DBG("RDTSC ticksource installed. CPU running at %ld Mhz\n", - clocks_per_usec); - return 0; - } - } - - DBG("RDTSC ticksource not available on this machine.\n"); - return -ENODEV; -} - -struct timer rdtsc_ts __timer (01) = { - .init = rdtsc_ts_init, - .udelay = generic_currticks_udelay, - .currticks = rdtsc_currticks, -}; - diff --git a/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S b/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S index 4fbd6563..53e2d7c5 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S +++ b/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S @@ -66,7 +66,7 @@ .align 16 .globl hidemem_base .globl hidemem_umalloc - .globl hidemem_text + .globl hidemem_textdata memory_windows: base_memory_window: .long 0x00000000, 0x00000000 /* Start of memory */ @@ -76,7 +76,7 @@ ext_memory_window: .long 0x000a0000, 0x00000000 /* 640kB mark */ hidemem_umalloc: .long 0xffffffff, 0xffffffff /* Changes at runtime */ .long 0xffffffff, 0xffffffff /* Changes at runtime */ -hidemem_text: .long 0xffffffff, 0xffffffff /* Changes at runtime */ +hidemem_textdata: .long 0xffffffff, 0xffffffff /* Changes at runtime */ .long 0xffffffff, 0xffffffff /* Changes at runtime */ .long 0xffffffff, 0xffffffff /* End of memory */ @@ -268,8 +268,10 @@ get_underlying_e820: pushl %ebx pushl %ecx pushl %edx + pushl %esi /* Some implementations corrupt %esi, so we */ + pushl %edi /* preserve %esi, %edi and %ebp to be paranoid */ + pushl %ebp pushw %es - pushw %di pushw %ds popw %es movw $underlying_e820_cache, %di @@ -280,8 +282,10 @@ get_underlying_e820: stc pushfw lcall *%cs:int15_vector - popw %di popw %es + popl %ebp + popl %edi + popl %esi /* Check for error return from underlying e820 call */ jc 2f /* CF set: error */ cmpl $SMAP, %eax diff --git a/gpxe/src/arch/i386/firmware/pcbios/gateA20.c b/gpxe/src/arch/i386/firmware/pcbios/gateA20.c index a14e3416..34e3ac52 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/gateA20.c +++ b/gpxe/src/arch/i386/firmware/pcbios/gateA20.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #define K_RDWR 0x60 /* keyboard data & cmds (read/write) */ @@ -48,9 +49,9 @@ static void empty_8042 ( void ) { time = currticks() + TICKS_PER_SEC; /* max wait of 1 second */ while ( ( inb ( K_CMD ) & ( K_IBUF_FUL | K_OBUF_FUL ) ) && currticks() < time ) { - SLOW_DOWN_IO; - ( void ) inb ( K_RDWR ); - SLOW_DOWN_IO; + iodelay(); + ( void ) inb_p ( K_RDWR ); + iodelay(); } } @@ -77,7 +78,7 @@ static int gateA20_is_set ( int retries ) { /* Avoid false negatives */ test_pattern++; - SLOW_DOWN_IO; + iodelay(); /* Always retry at least once, to avoid false negatives */ } while ( retries-- >= 0 ); @@ -145,9 +146,9 @@ void gateA20_set ( void ) { scp_a = inb ( SCP_A ); scp_a &= ~0x01; /* Avoid triggering a reset */ scp_a |= 0x02; /* Enable A20 */ - SLOW_DOWN_IO; + iodelay(); outb ( scp_a, SCP_A ); - SLOW_DOWN_IO; + iodelay(); if ( gateA20_is_set ( A20_SCPA_RETRIES ) ) { DBG ( "Enabled gate A20 using " "Fast Gate A20\n" ); diff --git a/gpxe/src/arch/i386/firmware/pcbios/hidemem.c b/gpxe/src/arch/i386/firmware/pcbios/hidemem.c index c9df7bd0..620b62e0 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/hidemem.c +++ b/gpxe/src/arch/i386/firmware/pcbios/hidemem.c @@ -55,8 +55,8 @@ extern struct hidden_region __data16 ( hidemem_umalloc ); #define hidemem_umalloc __use_data16 ( hidemem_umalloc ) /** Hidden text memory */ -extern struct hidden_region __data16 ( hidemem_text ); -#define hidemem_text __use_data16 ( hidemem_text ) +extern struct hidden_region __data16 ( hidemem_textdata ); +#define hidemem_textdata __use_data16 ( hidemem_textdata ) /** Assembly routine in e820mangler.S */ extern void int15(); @@ -66,12 +66,12 @@ extern struct segoff __text16 ( int15_vector ); #define int15_vector __use_text16 ( int15_vector ) /* The linker defines these symbols for us */ -extern char _text[]; -extern char _end[]; -extern char _text16_size[]; -#define _text16_size ( ( unsigned int ) _text16_size ) -extern char _data16_size[]; -#define _data16_size ( ( unsigned int ) _data16_size ) +extern char _textdata[]; +extern char _etextdata[]; +extern char _text16_memsz[]; +#define _text16_memsz ( ( unsigned int ) _text16_memsz ) +extern char _data16_memsz[]; +#define _data16_memsz ( ( unsigned int ) _data16_memsz ) /** * Hide region of memory from system memory map @@ -110,7 +110,7 @@ void hide_basemem ( void ) { * */ void hide_umalloc ( physaddr_t start, physaddr_t end ) { - assert ( end <= virt_to_phys ( _text ) ); + assert ( end <= virt_to_phys ( _textdata ) ); hide_region ( &hidemem_umalloc, start, end ); } @@ -118,9 +118,9 @@ void hide_umalloc ( physaddr_t start, physaddr_t end ) { * Hide .text and .data * */ -void hide_text ( void ) { - hide_region ( &hidemem_text, virt_to_phys ( _text ), - virt_to_phys ( _end ) ); +void hide_textdata ( void ) { + hide_region ( &hidemem_textdata, virt_to_phys ( _textdata ), + virt_to_phys ( _etextdata ) ); } /** @@ -148,8 +148,8 @@ static void hide_etherboot ( void ) { /* Initialise the hidden regions */ hide_basemem(); - hide_umalloc ( virt_to_phys ( _text ), virt_to_phys ( _text ) ); - hide_text(); + hide_umalloc ( virt_to_phys ( _textdata ), virt_to_phys ( _textdata ) ); + hide_textdata(); /* Some really moronic BIOSes bring up the PXE stack via the * UNDI loader entry point and then don't bother to unload it @@ -161,8 +161,8 @@ static void hide_etherboot ( void ) { * We use a heuristic to guess whether or not we are being * loaded sensibly. */ - rm_cs_top = ( ( ( rm_cs << 4 ) + _text16_size + 1024 - 1 ) >> 10 ); - rm_ds_top = ( ( ( rm_ds << 4 ) + _data16_size + 1024 - 1 ) >> 10 ); + rm_cs_top = ( ( ( rm_cs << 4 ) + _text16_memsz + 1024 - 1 ) >> 10 ); + rm_ds_top = ( ( ( rm_ds << 4 ) + _data16_memsz + 1024 - 1 ) >> 10 ); fbms = get_fbms(); if ( ( rm_cs_top < fbms ) && ( rm_ds_top < fbms ) ) { DBG ( "Detected potentially unsafe UNDI load at CS=%04x " diff --git a/gpxe/src/arch/i386/firmware/pcbios/memmap.c b/gpxe/src/arch/i386/firmware/pcbios/memmap.c index 9de10a7a..2e9627c0 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/memmap.c +++ b/gpxe/src/arch/i386/firmware/pcbios/memmap.c @@ -158,7 +158,7 @@ static int meme820 ( struct memory_map *memmap ) { uint32_t smap; size_t size; unsigned int flags; - unsigned int discard_d, discard_D; + unsigned int discard_D; /* Clear the E820 buffer. Do this once before starting, * rather than on each call; some BIOSes rely on the contents @@ -167,18 +167,24 @@ static int meme820 ( struct memory_map *memmap ) { memset ( &e820buf, 0, sizeof ( e820buf ) ); do { - __asm__ __volatile__ ( REAL_CODE ( "stc\n\t" + /* Some BIOSes corrupt %esi for fun. Guard against + * this by telling gcc that all non-output registers + * may be corrupted. + */ + __asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t" + "stc\n\t" "int $0x15\n\t" "pushfw\n\t" - "popw %w0\n\t" ) - : "=r" ( flags ), "=a" ( smap ), - "=b" ( next ), "=D" ( discard_D ), - "=c" ( size ), "=d" ( discard_d ) + "popw %%dx\n\t" + "popl %%ebp\n\t" ) + : "=a" ( smap ), "=b" ( next ), + "=c" ( size ), "=d" ( flags ), + "=D" ( discard_D ) : "a" ( 0xe820 ), "b" ( next ), "D" ( __from_data16 ( &e820buf ) ), "c" ( sizeof ( e820buf ) ), "d" ( SMAP ) - : "memory" ); + : "esi", "memory" ); if ( smap != SMAP ) { DBG ( "INT 15,e820 failed SMAP signature check\n" ); diff --git a/gpxe/src/arch/i386/firmware/pcbios/smbios_settings.c b/gpxe/src/arch/i386/firmware/pcbios/smbios_settings.c index b088e51d..3238fb19 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/smbios_settings.c +++ b/gpxe/src/arch/i386/firmware/pcbios/smbios_settings.c @@ -24,6 +24,16 @@ #include #include +/** SMBIOS settings tag magic number */ +#define SMBIOS_TAG_MAGIC 0x5B /* "SmBios" */ + +/** + * Construct SMBIOS empty tag + * + * @ret tag SMBIOS setting tag + */ +#define SMBIOS_EMPTY_TAG ( SMBIOS_TAG_MAGIC << 24 ) + /** * Construct SMBIOS raw-data tag * @@ -33,7 +43,8 @@ * @ret tag SMBIOS setting tag */ #define SMBIOS_RAW_TAG( _type, _structure, _field ) \ - ( ( (_type) << 16 ) | \ + ( ( SMBIOS_TAG_MAGIC << 24 ) | \ + ( (_type) << 16 ) | \ ( offsetof ( _structure, _field ) << 8 ) | \ ( sizeof ( ( ( _structure * ) 0 )->_field ) ) ) @@ -46,7 +57,8 @@ * @ret tag SMBIOS setting tag */ #define SMBIOS_STRING_TAG( _type, _structure, _field ) \ - ( ( (_type) << 16 ) | \ + ( ( SMBIOS_TAG_MAGIC << 24 ) | \ + ( (_type) << 16 ) | \ ( offsetof ( _structure, _field ) << 8 ) ) /** @@ -78,16 +90,18 @@ static int smbios_fetch ( struct settings *settings __unused, struct setting *setting, void *data, size_t len ) { struct smbios_structure structure; + unsigned int tag_magic; unsigned int tag_type; unsigned int tag_offset; unsigned int tag_len; int rc; /* Split tag into type, offset and length */ - tag_type = ( setting->tag >> 16 ); + tag_magic = ( setting->tag >> 24 ); + tag_type = ( ( setting->tag >> 16 ) & 0xff ); tag_offset = ( ( setting->tag >> 8 ) & 0xff ); tag_len = ( setting->tag & 0xff ); - if ( ! tag_type ) + if ( tag_magic != SMBIOS_TAG_MAGIC ) return -ENOENT; /* Find SMBIOS structure */ @@ -127,6 +141,7 @@ static struct settings_operations smbios_settings_operations = { static struct settings smbios_settings = { .refcnt = NULL, .name = "smbios", + .tag_magic = SMBIOS_EMPTY_TAG, .siblings = LIST_HEAD_INIT ( smbios_settings.siblings ), .children = LIST_HEAD_INIT ( smbios_settings.children ), .op = &smbios_settings_operations, diff --git a/gpxe/src/arch/i386/image/multiboot.c b/gpxe/src/arch/i386/image/multiboot.c index a4a340fd..49adf951 100644 --- a/gpxe/src/arch/i386/image/multiboot.c +++ b/gpxe/src/arch/i386/image/multiboot.c @@ -282,11 +282,13 @@ static int multiboot_exec ( struct image *image ) { /* Jump to OS with flat physical addressing */ DBGC ( image, "MULTIBOOT %p starting execution at %lx\n", image, entry ); - __asm__ __volatile__ ( PHYS_CODE ( "call *%%edi\n\t" ) + __asm__ __volatile__ ( PHYS_CODE ( "pushl %%ebp\n\t" + "call *%%edi\n\t" + "popl %%ebp\n\t" ) : : "a" ( MULTIBOOT_BOOTLOADER_MAGIC ), "b" ( virt_to_phys ( &mbinfo ) ), "D" ( entry ) - : "ecx", "edx", "esi", "ebp", "memory" ); + : "ecx", "edx", "esi", "memory" ); DBGC ( image, "MULTIBOOT %p returned\n", image ); diff --git a/gpxe/src/arch/i386/image/nbi.c b/gpxe/src/arch/i386/image/nbi.c index e6a0ab0f..ea8375cb 100644 --- a/gpxe/src/arch/i386/image/nbi.c +++ b/gpxe/src/arch/i386/image/nbi.c @@ -372,11 +372,12 @@ static int nbi_boot32 ( struct image *image, struct imgheader *imgheader ) { * @ret netdev Boot network device */ static struct net_device * guess_boot_netdev ( void ) { - struct net_device *boot_netdev; + struct net_device *netdev; /* Just use the first network device */ - for_each_netdev ( boot_netdev ) { - return boot_netdev; + for_each_netdev ( netdev ) { + if ( netdev->state & NETDEV_OPEN ) + return netdev; } return NULL; diff --git a/gpxe/src/arch/i386/include/bios.h b/gpxe/src/arch/i386/include/bios.h index 630a898b..979a092c 100644 --- a/gpxe/src/arch/i386/include/bios.h +++ b/gpxe/src/arch/i386/include/bios.h @@ -5,7 +5,4 @@ #define BDA_FBMS 0x0013 #define BDA_NUM_DRIVES 0x0075 -extern unsigned long currticks ( void ); -extern void cpu_nap ( void ); - #endif /* BIOS_H */ diff --git a/gpxe/src/arch/i386/include/biosint.h b/gpxe/src/arch/i386/include/biosint.h index d4e34963..d365cf01 100644 --- a/gpxe/src/arch/i386/include/biosint.h +++ b/gpxe/src/arch/i386/include/biosint.h @@ -6,9 +6,22 @@ * */ +#include + struct segoff; -extern int hooked_bios_interrupts; +/** + * Hooked interrupt count + * + * At exit, after unhooking all possible interrupts, this counter + * should be examined. If it is non-zero, it means that we failed to + * unhook at least one interrupt vector, and so must not free up the + * memory we are using. (Note that this also implies that we should + * re-hook INT 15 in order to hide ourselves from the memory map). + */ +extern uint16_t __text16 ( hooked_bios_interrupts ); +#define hooked_bios_interrupts __use_text16 ( hooked_bios_interrupts ) + extern void hook_bios_interrupt ( unsigned int interrupt, unsigned int handler, struct segoff *chain_vector ); extern int unhook_bios_interrupt ( unsigned int interrupt, diff --git a/gpxe/src/arch/i386/include/bits/errfile.h b/gpxe/src/arch/i386/include/bits/errfile.h index 99927c28..70c78eaf 100644 --- a/gpxe/src/arch/i386/include/bits/errfile.h +++ b/gpxe/src/arch/i386/include/bits/errfile.h @@ -6,7 +6,7 @@ * @{ */ -#define ERRFILE_umalloc ( ERRFILE_ARCH | ERRFILE_CORE | 0x00000000 ) +#define ERRFILE_memtop_umalloc ( ERRFILE_ARCH | ERRFILE_CORE | 0x00000000 ) #define ERRFILE_memmap ( ERRFILE_ARCH | ERRFILE_CORE | 0x00010000 ) #define ERRFILE_pnpbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00020000 ) #define ERRFILE_smbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00030000 ) diff --git a/gpxe/src/arch/i386/include/bits/io.h b/gpxe/src/arch/i386/include/bits/io.h new file mode 100644 index 00000000..dd0ee444 --- /dev/null +++ b/gpxe/src/arch/i386/include/bits/io.h @@ -0,0 +1,12 @@ +#ifndef _BITS_IO_H +#define _BITS_IO_H + +/** @file + * + * i386-specific I/O API implementations + * + */ + +#include + +#endif /* _BITS_IO_H */ diff --git a/gpxe/src/arch/i386/include/bits/nap.h b/gpxe/src/arch/i386/include/bits/nap.h new file mode 100644 index 00000000..f8ba7a7c --- /dev/null +++ b/gpxe/src/arch/i386/include/bits/nap.h @@ -0,0 +1,13 @@ +#ifndef _BITS_NAP_H +#define _BITS_NAP_H + +/** @file + * + * i386-specific CPU sleeping API implementations + * + */ + +#include +#include + +#endif /* _BITS_MAP_H */ diff --git a/gpxe/src/arch/i386/include/bits/pci_io.h b/gpxe/src/arch/i386/include/bits/pci_io.h new file mode 100644 index 00000000..0fbb439d --- /dev/null +++ b/gpxe/src/arch/i386/include/bits/pci_io.h @@ -0,0 +1,13 @@ +#ifndef _BITS_PCI_IO_H +#define _BITS_PCI_IO_H + +/** @file + * + * i386-specific PCI I/O API implementations + * + */ + +#include +#include + +#endif /* _BITS_PCI_IO_H */ diff --git a/gpxe/src/arch/i386/include/bits/timer.h b/gpxe/src/arch/i386/include/bits/timer.h new file mode 100644 index 00000000..99666d84 --- /dev/null +++ b/gpxe/src/arch/i386/include/bits/timer.h @@ -0,0 +1,13 @@ +#ifndef _BITS_TIMER_H +#define _BITS_TIMER_H + +/** @file + * + * i386-specific timer API implementations + * + */ + +#include +#include + +#endif /* _BITS_TIMER_H */ diff --git a/gpxe/src/arch/i386/include/bits/timer2.h b/gpxe/src/arch/i386/include/bits/timer2.h deleted file mode 100644 index 83923b29..00000000 --- a/gpxe/src/arch/i386/include/bits/timer2.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef BITS_TIMER2_H -#define BITS_TIMER2_H - -#include - -void i386_timer2_udelay(unsigned int usecs); - -#endif diff --git a/gpxe/src/arch/i386/include/bits/uaccess.h b/gpxe/src/arch/i386/include/bits/uaccess.h index 9c6d0c21..0ecc5028 100644 --- a/gpxe/src/arch/i386/include/bits/uaccess.h +++ b/gpxe/src/arch/i386/include/bits/uaccess.h @@ -1,6 +1,12 @@ #ifndef _BITS_UACCESS_H #define _BITS_UACCESS_H -#include +/** @file + * + * i386-specific user access API implementations + * + */ + +#include #endif /* _BITS_UACCESS_H */ diff --git a/gpxe/src/arch/i386/include/bits/umalloc.h b/gpxe/src/arch/i386/include/bits/umalloc.h new file mode 100644 index 00000000..dcbd0a6b --- /dev/null +++ b/gpxe/src/arch/i386/include/bits/umalloc.h @@ -0,0 +1,12 @@ +#ifndef _BITS_UMALLOC_H +#define _BITS_UMALLOC_H + +/** @file + * + * i386-specific user memory allocation API implementations + * + */ + +#include + +#endif /* _BITS_UMALLOC_H */ diff --git a/gpxe/src/arch/i386/include/gpxe/bios_nap.h b/gpxe/src/arch/i386/include/gpxe/bios_nap.h new file mode 100644 index 00000000..f1c721e9 --- /dev/null +++ b/gpxe/src/arch/i386/include/gpxe/bios_nap.h @@ -0,0 +1,16 @@ +#ifndef _GPXE_BIOS_NAP_H +#define _GPXE_BIOS_NAP_H + +/** @file + * + * BIOS CPU sleeping + * + */ + +#ifdef NAP_PCBIOS +#define NAP_PREFIX_pcbios +#else +#define NAP_PREFIX_pcbios __pcbios_ +#endif + +#endif /* _GPXE_BIOS_NAP_H */ diff --git a/gpxe/src/arch/i386/include/gpxe/bios_timer.h b/gpxe/src/arch/i386/include/gpxe/bios_timer.h new file mode 100644 index 00000000..7e3caa3c --- /dev/null +++ b/gpxe/src/arch/i386/include/gpxe/bios_timer.h @@ -0,0 +1,42 @@ +#ifndef _GPXE_BIOS_TIMER_H +#define _GPXE_BIOS_TIMER_H + +/** @file + * + * BIOS timer + * + */ + +#ifdef TIMER_PCBIOS +#define TIMER_PREFIX_pcbios +#else +#define TIMER_PREFIX_pcbios __pcbios_ +#endif + +#include + +/** + * Delay for a fixed number of microseconds + * + * @v usecs Number of microseconds for which to delay + */ +static inline __always_inline void +TIMER_INLINE ( pcbios, udelay ) ( unsigned long usecs ) { + /* BIOS timer is not high-resolution enough for udelay(), so + * we use timer2 + */ + timer2_udelay ( usecs ); +} + +/** + * Get number of ticks per second + * + * @ret ticks_per_sec Number of ticks per second + */ +static inline __always_inline unsigned long +TIMER_INLINE ( pcbios, ticks_per_sec ) ( void ) { + /* BIOS timer ticks over at 18.2 ticks per second */ + return 18; +} + +#endif /* _GPXE_BIOS_TIMER_H */ diff --git a/gpxe/src/arch/i386/include/gpxe/efi/efix86_nap.h b/gpxe/src/arch/i386/include/gpxe/efi/efix86_nap.h new file mode 100644 index 00000000..91424c54 --- /dev/null +++ b/gpxe/src/arch/i386/include/gpxe/efi/efix86_nap.h @@ -0,0 +1,16 @@ +#ifndef _GPXE_EFIX86_NAP_H +#define _GPXE_EFIX86_NAP_H + +/** @file + * + * EFI CPU sleeping + * + */ + +#ifdef NAP_EFIX86 +#define NAP_PREFIX_efix86 +#else +#define NAP_PREFIX_efix86 __efix86_ +#endif + +#endif /* _GPXE_EFIX86_NAP_H */ diff --git a/gpxe/src/arch/i386/include/gpxe/memtop_umalloc.h b/gpxe/src/arch/i386/include/gpxe/memtop_umalloc.h new file mode 100644 index 00000000..a3cd2c01 --- /dev/null +++ b/gpxe/src/arch/i386/include/gpxe/memtop_umalloc.h @@ -0,0 +1,16 @@ +#ifndef _GPXE_MEMTOP_UMALLOC_H +#define _GPXE_MEMTOP_UMALLOC_H + +/** @file + * + * External memory allocation + * + */ + +#ifdef UMALLOC_MEMTOP +#define UMALLOC_PREFIX_memtop +#else +#define UMALLOC_PREFIX_memtop __memtop_ +#endif + +#endif /* _GPXE_MEMTOP_UMALLOC_H */ diff --git a/gpxe/src/arch/i386/include/gpxe/pcibios.h b/gpxe/src/arch/i386/include/gpxe/pcibios.h new file mode 100644 index 00000000..b86f5abd --- /dev/null +++ b/gpxe/src/arch/i386/include/gpxe/pcibios.h @@ -0,0 +1,133 @@ +#ifndef _GPXE_PCIBIOS_H +#define _GPXE_PCIBIOS_H + +#include + +/** @file + * + * PCI configuration space access via PCI BIOS + * + */ + +#ifdef PCIAPI_PCBIOS +#define PCIAPI_PREFIX_pcbios +#else +#define PCIAPI_PREFIX_pcbios __pcbios_ +#endif + +struct pci_device; + +#define PCIBIOS_INSTALLATION_CHECK 0xb1010000 +#define PCIBIOS_READ_CONFIG_BYTE 0xb1080000 +#define PCIBIOS_READ_CONFIG_WORD 0xb1090000 +#define PCIBIOS_READ_CONFIG_DWORD 0xb10a0000 +#define PCIBIOS_WRITE_CONFIG_BYTE 0xb10b0000 +#define PCIBIOS_WRITE_CONFIG_WORD 0xb10c0000 +#define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d0000 + +extern int pcibios_read ( struct pci_device *pci, uint32_t command, + uint32_t *value ); +extern int pcibios_write ( struct pci_device *pci, uint32_t command, + uint32_t value ); + +/** + * Read byte from PCI configuration space via PCI BIOS + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( pcbios, pci_read_config_byte ) ( struct pci_device *pci, + unsigned int where, + uint8_t *value ) { + uint32_t tmp; + int rc; + + rc = pcibios_read ( pci, PCIBIOS_READ_CONFIG_BYTE | where, &tmp ); + *value = tmp; + return rc; +} + +/** + * Read word from PCI configuration space via PCI BIOS + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( pcbios, pci_read_config_word ) ( struct pci_device *pci, + unsigned int where, + uint16_t *value ) { + uint32_t tmp; + int rc; + + rc = pcibios_read ( pci, PCIBIOS_READ_CONFIG_WORD | where, &tmp ); + *value = tmp; + return rc; +} + +/** + * Read dword from PCI configuration space via PCI BIOS + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( pcbios, pci_read_config_dword ) ( struct pci_device *pci, + unsigned int where, + uint32_t *value ) { + return pcibios_read ( pci, PCIBIOS_READ_CONFIG_DWORD | where, value ); +} + +/** + * Write byte to PCI configuration space via PCI BIOS + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( pcbios, pci_write_config_byte ) ( struct pci_device *pci, + unsigned int where, + uint8_t value ) { + return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_BYTE | where, value ); +} + +/** + * Write word to PCI configuration space via PCI BIOS + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( pcbios, pci_write_config_word ) ( struct pci_device *pci, + unsigned int where, + uint16_t value ) { + return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_WORD | where, value ); +} + +/** + * Write dword to PCI configuration space via PCI BIOS + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( pcbios, pci_write_config_dword ) ( struct pci_device *pci, + unsigned int where, + uint32_t value ) { + return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_DWORD | where, value); +} + +#endif /* _GPXE_PCIBIOS_H */ diff --git a/gpxe/src/arch/i386/include/gpxe/pcidirect.h b/gpxe/src/arch/i386/include/gpxe/pcidirect.h new file mode 100644 index 00000000..fe433c6f --- /dev/null +++ b/gpxe/src/arch/i386/include/gpxe/pcidirect.h @@ -0,0 +1,139 @@ +#ifndef _PCIDIRECT_H +#define _PCIDIRECT_H + +#include +#include + +#ifdef PCIAPI_DIRECT +#define PCIAPI_PREFIX_direct +#else +#define PCIAPI_PREFIX_direct __direct_ +#endif + +/** @file + * + * PCI configuration space access via Type 1 accesses + * + */ + +#define PCIDIRECT_CONFIG_ADDRESS 0xcf8 +#define PCIDIRECT_CONFIG_DATA 0xcfc + +struct pci_device; + +extern void pcidirect_prepare ( struct pci_device *pci, int where ); + +/** + * Determine maximum PCI bus number within system + * + * @ret max_bus Maximum bus number + */ +static inline __always_inline int +PCIAPI_INLINE ( direct, pci_max_bus ) ( void ) { + /* No way to work this out via Type 1 accesses */ + return 0xff; +} + +/** + * Read byte from PCI configuration space via Type 1 access + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( direct, pci_read_config_byte ) ( struct pci_device *pci, + unsigned int where, + uint8_t *value ) { + pcidirect_prepare ( pci, where ); + *value = inb ( PCIDIRECT_CONFIG_DATA + ( where & 3 ) ); + return 0; +} + +/** + * Read word from PCI configuration space via Type 1 access + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( direct, pci_read_config_word ) ( struct pci_device *pci, + unsigned int where, + uint16_t *value ) { + pcidirect_prepare ( pci, where ); + *value = inw ( PCIDIRECT_CONFIG_DATA + ( where & 2 ) ); + return 0; +} + +/** + * Read dword from PCI configuration space via Type 1 access + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( direct, pci_read_config_dword ) ( struct pci_device *pci, + unsigned int where, + uint32_t *value ) { + pcidirect_prepare ( pci, where ); + *value = inl ( PCIDIRECT_CONFIG_DATA ); + return 0; +} + +/** + * Write byte to PCI configuration space via Type 1 access + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( direct, pci_write_config_byte ) ( struct pci_device *pci, + unsigned int where, + uint8_t value ) { + pcidirect_prepare ( pci, where ); + outb ( value, PCIDIRECT_CONFIG_DATA + ( where & 3 ) ); + return 0; +} + +/** + * Write word to PCI configuration space via Type 1 access + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( direct, pci_write_config_word ) ( struct pci_device *pci, + unsigned int where, + uint16_t value ) { + pcidirect_prepare ( pci, where ); + outw ( value, PCIDIRECT_CONFIG_DATA + ( where & 2 ) ); + return 0; +} + +/** + * Write dword to PCI configuration space via Type 1 access + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( direct, pci_write_config_dword ) ( struct pci_device *pci, + unsigned int where, + uint32_t value ) { + pcidirect_prepare ( pci, where ); + outl ( value, PCIDIRECT_CONFIG_DATA ); + return 0; +} + +#endif /* _PCIDIRECT_H */ diff --git a/gpxe/src/arch/i386/include/gpxe/rdtsc_timer.h b/gpxe/src/arch/i386/include/gpxe/rdtsc_timer.h new file mode 100644 index 00000000..0e03d707 --- /dev/null +++ b/gpxe/src/arch/i386/include/gpxe/rdtsc_timer.h @@ -0,0 +1,37 @@ +#ifndef _GPXE_RDTSC_TIMER_H +#define _GPXE_RDTSC_TIMER_H + +/** @file + * + * RDTSC timer + * + */ + +#ifdef TIMER_RDTSC +#define TIMER_PREFIX_rdtsc +#else +#define TIMER_PREFIX_rdtsc __rdtsc_ +#endif + +/** + * RDTSC values can easily overflow an unsigned long. We discard the + * low-order bits in order to obtain sensibly-scaled values. + */ +#define TSC_SHIFT 8 + +/** + * Get current system time in ticks + * + * @ret ticks Current time, in ticks + */ +static inline __always_inline unsigned long +TIMER_INLINE ( rdtsc, currticks ) ( void ) { + unsigned long ticks; + + __asm__ __volatile__ ( "rdtsc\n\t" + "shrdl %1, %%edx, %%eax\n\t" + : "=a" ( ticks ) : "i" ( TSC_SHIFT ) : "edx" ); + return ticks; +} + +#endif /* _GPXE_RDTSC_TIMER_H */ diff --git a/gpxe/src/arch/i386/include/gpxe/timer2.h b/gpxe/src/arch/i386/include/gpxe/timer2.h new file mode 100644 index 00000000..59705fa2 --- /dev/null +++ b/gpxe/src/arch/i386/include/gpxe/timer2.h @@ -0,0 +1,12 @@ +#ifndef _GPXE_TIMER2_H +#define _GPXE_TIMER2_H + +/** @file + * + * Timer chip control + * + */ + +extern void timer2_udelay ( unsigned long usecs ); + +#endif /* _GPXE_TIMER2_H */ diff --git a/gpxe/src/arch/i386/include/gpxe/x86_io.h b/gpxe/src/arch/i386/include/gpxe/x86_io.h new file mode 100644 index 00000000..b1ae3bac --- /dev/null +++ b/gpxe/src/arch/i386/include/gpxe/x86_io.h @@ -0,0 +1,151 @@ +#ifndef _GPXE_X86_IO_H +#define _GPXE_X86_IO_H + +/** @file + * + * gPXE I/O API for x86 + * + * i386 uses direct pointer dereferences for accesses to memory-mapped + * I/O space, and the inX/outX instructions for accesses to + * port-mapped I/O space. + * + * 64-bit atomic accesses (readq() and writeq()) use MMX instructions, + * and will crash original Pentium and earlier CPUs. Fortunately, no + * hardware that requires atomic 64-bit accesses will physically fit + * into a machine with such an old CPU anyway. + */ + +#ifdef IOAPI_X86 +#define IOAPI_PREFIX_x86 +#else +#define IOAPI_PREFIX_x86 __x86_ +#endif + +/* + * Memory space mappings + * + */ + +/* + * Physical<->Bus and Bus<->I/O address mappings + * + */ + +static inline __always_inline unsigned long +IOAPI_INLINE ( x86, phys_to_bus ) ( unsigned long phys_addr ) { + return phys_addr; +} + +static inline __always_inline unsigned long +IOAPI_INLINE ( x86, bus_to_phys ) ( unsigned long bus_addr ) { + return bus_addr; +} + +static inline __always_inline void * +IOAPI_INLINE ( x86, ioremap ) ( unsigned long bus_addr, size_t len __unused ) { + return phys_to_virt ( bus_addr ); +} + +static inline __always_inline void +IOAPI_INLINE ( x86, iounmap ) ( volatile const void *io_addr __unused ) { + /* Nothing to do */ +} + +static inline __always_inline unsigned long +IOAPI_INLINE ( x86, io_to_bus ) ( volatile const void *io_addr ) { + return virt_to_phys ( io_addr ); +} + +/* + * MMIO reads and writes up to 32 bits + * + */ + +#define X86_READX( _api_func, _type ) \ +static inline __always_inline _type \ +IOAPI_INLINE ( x86, _api_func ) ( volatile _type *io_addr ) { \ + return *io_addr; \ +} +X86_READX ( readb, uint8_t ); +X86_READX ( readw, uint16_t ); +X86_READX ( readl, uint32_t ); + +#define X86_WRITEX( _api_func, _type ) \ +static inline __always_inline void \ +IOAPI_INLINE ( x86, _api_func ) ( _type data, \ + volatile _type *io_addr ) { \ + *io_addr = data; \ +} +X86_WRITEX ( writeb, uint8_t ); +X86_WRITEX ( writew, uint16_t ); +X86_WRITEX ( writel, uint32_t ); + +/* + * PIO reads and writes up to 32 bits + * + */ + +#define X86_INX( _insn_suffix, _type, _reg_prefix ) \ +static inline __always_inline _type \ +IOAPI_INLINE ( x86, in ## _insn_suffix ) ( volatile _type *io_addr ) { \ + _type data; \ + __asm__ __volatile__ ( "in" #_insn_suffix " %w1, %" _reg_prefix "0" \ + : "=a" ( data ) : "Nd" ( io_addr ) ); \ + return data; \ +} \ +static inline __always_inline void \ +IOAPI_INLINE ( x86, ins ## _insn_suffix ) ( volatile _type *io_addr, \ + _type *data, \ + unsigned int count ) { \ + unsigned int discard_D; \ + __asm__ __volatile__ ( "rep ins" #_insn_suffix \ + : "=D" ( discard_D ) \ + : "d" ( io_addr ), "c" ( count ), \ + "0" ( data ) ); \ +} +X86_INX ( b, uint8_t, "b" ); +X86_INX ( w, uint16_t, "w" ); +X86_INX ( l, uint32_t, "k" ); + +#define X86_OUTX( _insn_suffix, _type, _reg_prefix ) \ +static inline __always_inline void \ +IOAPI_INLINE ( x86, out ## _insn_suffix ) ( _type data, \ + volatile _type *io_addr ) { \ + __asm__ __volatile__ ( "out" #_insn_suffix " %" _reg_prefix "0, %w1" \ + : : "a" ( data ), "Nd" ( io_addr ) ); \ +} \ +static inline __always_inline void \ +IOAPI_INLINE ( x86, outs ## _insn_suffix ) ( volatile _type *io_addr, \ + const _type *data, \ + unsigned int count ) { \ + unsigned int discard_S; \ + __asm__ __volatile__ ( "rep outs" #_insn_suffix \ + : "=S" ( discard_S ) \ + : "d" ( io_addr ), "c" ( count ), \ + "0" ( data ) ); \ +} +X86_OUTX ( b, uint8_t, "b" ); +X86_OUTX ( w, uint16_t, "w" ); +X86_OUTX ( l, uint32_t, "k" ); + +/* + * Slow down I/O + * + */ + +static inline __always_inline void +IOAPI_INLINE ( x86, iodelay ) ( void ) { + __asm__ __volatile__ ( "outb %al, $0x80" ); +} + +/* + * Memory barrier + * + */ + +static inline __always_inline void +IOAPI_INLINE ( x86, mb ) ( void ) { + __asm__ __volatile__ ( "lock; addl $0, 0(%%esp)" : : : "memory" ); +} + +#endif /* _GPXE_X86_IO_H */ diff --git a/gpxe/src/arch/i386/include/int13.h b/gpxe/src/arch/i386/include/int13.h index 72ca97d7..bf6d0318 100644 --- a/gpxe/src/arch/i386/include/int13.h +++ b/gpxe/src/arch/i386/include/int13.h @@ -9,6 +9,7 @@ #include #include +#include struct block_device; diff --git a/gpxe/src/arch/i386/include/io.h b/gpxe/src/arch/i386/include/io.h deleted file mode 100644 index c26fdf7e..00000000 --- a/gpxe/src/arch/i386/include/io.h +++ /dev/null @@ -1,265 +0,0 @@ -#ifndef ETHERBOOT_IO_H -#define ETHERBOOT_IO_H - -#include -#include "virtaddr.h" - -/* virt_to_bus converts an addresss inside of etherboot [_start, _end] - * into a memory access cards can use. - */ -#define virt_to_bus virt_to_phys - - -/* bus_to_virt reverses virt_to_bus, the address must be output - * from virt_to_bus to be valid. This function does not work on - * all bus addresses. - */ -#define bus_to_virt phys_to_virt - -/* ioremap converts a random 32bit bus address into something - * etherboot can access. - */ -static inline void *ioremap(unsigned long bus_addr, unsigned long length __unused) -{ - return bus_to_virt(bus_addr); -} - -/* iounmap cleans up anything ioremap had to setup */ -static inline void iounmap(void *virt_addr __unused) -{ - return; -} - -/* - * This file contains the definitions for the x86 IO instructions - * inb/inw/inl/outb/outw/outl and the "string versions" of the same - * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing" - * versions of the single-IO instructions (inb_p/inw_p/..). - * - * This file is not meant to be obfuscating: it's just complicated - * to (a) handle it all in a way that makes gcc able to optimize it - * as well as possible and (b) trying to avoid writing the same thing - * over and over again with slight variations and possibly making a - * mistake somewhere. - */ - -/* - * Thanks to James van Artsdalen for a better timing-fix than - * the two short jumps: using outb's to a nonexistent port seems - * to guarantee better timings even on fast machines. - * - * On the other hand, I'd like to be sure of a non-existent port: - * I feel a bit unsafe about using 0x80 (should be safe, though) - * - * Linus - */ - -#ifdef SLOW_IO_BY_JUMPING -#define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:") -#else -#define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80") -#endif - -#ifdef REALLY_SLOW_IO -#define SLOW_DOWN_IO { __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; } -#else -#define SLOW_DOWN_IO __SLOW_DOWN_IO -#endif - -/* - * readX/writeX() are used to access memory mapped devices. On some - * architectures the memory mapped IO stuff needs to be accessed - * differently. On the x86 architecture, we just read/write the - * memory location directly. - */ -static inline __attribute__ (( always_inline )) unsigned long -_readb ( volatile uint8_t *addr ) { - unsigned long data = *addr; - DBGIO ( "[%08lx] => %02lx\n", virt_to_phys ( addr ), data ); - return data; -} -static inline __attribute__ (( always_inline )) unsigned long -_readw ( volatile uint16_t *addr ) { - unsigned long data = *addr; - DBGIO ( "[%08lx] => %04lx\n", virt_to_phys ( addr ), data ); - return data; -} -static inline __attribute__ (( always_inline )) unsigned long -_readl ( volatile uint32_t *addr ) { - unsigned long data = *addr; - DBGIO ( "[%08lx] => %08lx\n", virt_to_phys ( addr ), data ); - return data; -} -#define readb( addr ) _readb ( ( volatile uint8_t * ) (addr) ) -#define readw( addr ) _readw ( ( volatile uint16_t * ) (addr) ) -#define readl( addr ) _readl ( ( volatile uint32_t * ) (addr) ) - -static inline __attribute__ (( always_inline )) void -_writeb ( unsigned long data, volatile uint8_t *addr ) { - DBGIO ( "[%08lx] <= %02lx\n", virt_to_phys ( addr ), data ); - *addr = data; -} -static inline __attribute__ (( always_inline )) void -_writew ( unsigned long data, volatile uint16_t *addr ) { - DBGIO ( "[%08lx] <= %04lx\n", virt_to_phys ( addr ), data ); - *addr = data; -} -static inline __attribute__ (( always_inline )) void -_writel ( unsigned long data, volatile uint32_t *addr ) { - DBGIO ( "[%08lx] <= %08lx\n", virt_to_phys ( addr ), data ); - *addr = data; -} -#define writeb( b, addr ) _writeb ( (b), ( volatile uint8_t * ) (addr) ) -#define writew( b, addr ) _writew ( (b), ( volatile uint16_t * ) (addr) ) -#define writel( b, addr ) _writel ( (b), ( volatile uint32_t * ) (addr) ) - -#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c)) -#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c)) - -/* - * Force strict CPU ordering. - * And yes, this is required on UP too when we're talking - * to devices. - * - * For now, "wmb()" doesn't actually do anything, as all - * Intel CPU's follow what Intel calls a *Processor Order*, - * in which all writes are seen in the program order even - * outside the CPU. - * - * I expect future Intel CPU's to have a weaker ordering, - * but I'd also expect them to finally get their act together - * and add some real memory barriers if so. - * - * Some non intel clones support out of order store. wmb() ceases to be a - * nop for these. - */ - -#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory") -#define rmb() mb() -#define wmb() mb(); - - -/* - * Talk about misusing macros.. - */ - -#define __OUT1(s,x) \ -extern void __out##s(unsigned x value, unsigned short port); \ -extern inline void __out##s(unsigned x value, unsigned short port) { - -#define __OUT2(s,s1,s2) \ -__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" - -#define __OUT(s,s1,x) \ -__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); } \ -__OUT1(s##c,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); } \ -__OUT1(s##_p,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); SLOW_DOWN_IO; } \ -__OUT1(s##c_p,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); SLOW_DOWN_IO; } - -#define __IN1(s,x) \ -extern unsigned x __in##s(unsigned short port); \ -extern inline unsigned x __in##s(unsigned short port) { unsigned x _v; - -#define __IN2(s,s1,s2) \ -__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" - -#define __IN(s,s1,x,i...) \ -__IN1(s,x) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); return _v; } \ -__IN1(s##c,x) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); return _v; } \ -__IN1(s##_p,x) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); SLOW_DOWN_IO; return _v; } \ -__IN1(s##c_p,x) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); SLOW_DOWN_IO; return _v; } - -#define __INS(s) \ -extern void ins##s(unsigned short port, void * addr, unsigned long count); \ -extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \ -{ __asm__ __volatile__ ("cld ; rep ; ins" #s \ -: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } - -#define __OUTS(s) \ -extern void outs##s(unsigned short port, const void * addr, unsigned long count); \ -extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \ -{ __asm__ __volatile__ ("cld ; rep ; outs" #s \ -: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } - -__IN(b,"", char) -__IN(w,"",short) -__IN(l,"", long) - -__OUT(b,"b",char) -__OUT(w,"w",short) -__OUT(l,,int) - -__INS(b) -__INS(w) -__INS(l) - -__OUTS(b) -__OUTS(w) -__OUTS(l) - -/* - * Note that due to the way __builtin_constant_p() works, you - * - can't use it inside a inline function (it will never be true) - * - you don't have to worry about side effects within the __builtin.. - */ -#define outb(val,port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __outbc((val),(port)) : \ - __outb((val),(port))) - -#define inb(port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __inbc(port) : \ - __inb(port)) - -#define outb_p(val,port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __outbc_p((val),(port)) : \ - __outb_p((val),(port))) - -#define inb_p(port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __inbc_p(port) : \ - __inb_p(port)) - -#define outw(val,port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __outwc((val),(port)) : \ - __outw((val),(port))) - -#define inw(port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __inwc(port) : \ - __inw(port)) - -#define outw_p(val,port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __outwc_p((val),(port)) : \ - __outw_p((val),(port))) - -#define inw_p(port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __inwc_p(port) : \ - __inw_p(port)) - -#define outl(val,port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __outlc((val),(port)) : \ - __outl((val),(port))) - -#define inl(port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __inlc(port) : \ - __inl(port)) - -#define outl_p(val,port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __outlc_p((val),(port)) : \ - __outl_p((val),(port))) - -#define inl_p(port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __inlc_p(port) : \ - __inl_p(port)) - -#endif /* ETHERBOOT_IO_H */ diff --git a/gpxe/src/arch/i386/include/librm.h b/gpxe/src/arch/i386/include/librm.h old mode 100644 new mode 100755 index 07a85c59..9eb2767a --- a/gpxe/src/arch/i386/include/librm.h +++ b/gpxe/src/arch/i386/include/librm.h @@ -1,21 +1,109 @@ #ifndef LIBRM_H #define LIBRM_H -/* Drag in protected-mode segment selector values */ -#include "virtaddr.h" -#include "realmode.h" +/* Segment selectors as used in our protected-mode GDTs. + * + * Don't change these unless you really know what you're doing. + */ + +#define VIRTUAL_CS 0x08 +#define VIRTUAL_DS 0x10 +#define PHYSICAL_CS 0x18 +#define PHYSICAL_DS 0x20 +#define REAL_CS 0x28 +#define REAL_DS 0x30 +#if 0 +#define LONG_CS 0x38 +#define LONG_DS 0x40 +#endif #ifndef ASSEMBLY -#include "stddef.h" -#include "string.h" +#ifdef UACCESS_LIBRM +#define UACCESS_PREFIX_librm +#else +#define UACCESS_PREFIX_librm __librm_ +#endif + +/* Variables in librm.S */ +extern unsigned long virt_offset; + +/** + * Convert physical address to user pointer + * + * @v phys_addr Physical address + * @ret userptr User pointer + */ +static inline __always_inline userptr_t +UACCESS_INLINE ( librm, phys_to_user ) ( unsigned long phys_addr ) { + return ( phys_addr - virt_offset ); +} -/* - * Data structures and type definitions +/** + * Convert user buffer to physical address + * + * @v userptr User pointer + * @v offset Offset from user pointer + * @ret phys_addr Physical address + */ +static inline __always_inline unsigned long +UACCESS_INLINE ( librm, user_to_phys ) ( userptr_t userptr, off_t offset ) { + return ( userptr + offset + virt_offset ); +} + +static inline __always_inline userptr_t +UACCESS_INLINE ( librm, virt_to_user ) ( volatile const void *addr ) { + return trivial_virt_to_user ( addr ); +} + +static inline __always_inline void * +UACCESS_INLINE ( librm, user_to_virt ) ( userptr_t userptr, off_t offset ) { + return trivial_user_to_virt ( userptr, offset ); +} + +static inline __always_inline userptr_t +UACCESS_INLINE ( librm, userptr_add ) ( userptr_t userptr, off_t offset ) { + return trivial_userptr_add ( userptr, offset ); +} + +static inline __always_inline void +UACCESS_INLINE ( librm, memcpy_user ) ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, + size_t len ) { + trivial_memcpy_user ( dest, dest_off, src, src_off, len ); +} + +static inline __always_inline void +UACCESS_INLINE ( librm, memmove_user ) ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, + size_t len ) { + trivial_memmove_user ( dest, dest_off, src, src_off, len ); +} + +static inline __always_inline void +UACCESS_INLINE ( librm, memset_user ) ( userptr_t buffer, off_t offset, + int c, size_t len ) { + trivial_memset_user ( buffer, offset, c, len ); +} + +static inline __always_inline size_t +UACCESS_INLINE ( librm, strlen_user ) ( userptr_t buffer, off_t offset ) { + return trivial_strlen_user ( buffer, offset ); +} + +static inline __always_inline off_t +UACCESS_INLINE ( librm, memchr_user ) ( userptr_t buffer, off_t offset, + int c, size_t len ) { + return trivial_memchr_user ( buffer, offset, c, len ); +} + + +/****************************************************************************** + * + * Access to variables in .data16 and .text16 * */ -/* Access to variables in .data16 and .text16 */ extern char *data16; extern char *text16; @@ -72,178 +160,6 @@ extern uint16_t __text16 ( rm_ds ); */ extern void gateA20_set ( void ); -/* - * librm_mgmt: functions for manipulating base memory and executing - * real-mode code. - * - * Full API documentation for these functions is in realmode.h. - * - */ - -/* Macro for obtaining a physical address from a segment:offset pair. */ -#define VIRTUAL(x,y) ( phys_to_virt ( ( ( x ) << 4 ) + ( y ) ) ) - -/* Copy to/from base memory */ -static inline __attribute__ (( always_inline )) void -copy_to_real_librm ( unsigned int dest_seg, unsigned int dest_off, - void *src, size_t n ) { - memcpy ( VIRTUAL ( dest_seg, dest_off ), src, n ); -} -static inline __attribute__ (( always_inline )) void -copy_from_real_librm ( void *dest, unsigned int src_seg, - unsigned int src_off, size_t n ) { - memcpy ( dest, VIRTUAL ( src_seg, src_off ), n ); -} -#define put_real_librm( var, dest_seg, dest_off ) \ - do { \ - * ( ( typeof(var) * ) VIRTUAL ( dest_seg, dest_off ) ) = var; \ - } while ( 0 ) -#define get_real_librm( var, src_seg, src_off ) \ - do { \ - var = * ( ( typeof(var) * ) VIRTUAL ( src_seg, src_off ) ); \ - } while ( 0 ) -#define copy_to_real copy_to_real_librm -#define copy_from_real copy_from_real_librm -#define put_real put_real_librm -#define get_real get_real_librm - -/** - * A pointer to a user buffer - * - * Even though we could just use a void *, we use an intptr_t so that - * attempts to use normal pointers show up as compiler warnings. Such - * code is actually valid for librm, but not for libkir (i.e. under - * KEEP_IT_REAL), so it's good to have the warnings even under librm. - */ -typedef intptr_t userptr_t; - -/** - * Add offset to user pointer - * - * @v ptr User pointer - * @v offset Offset - * @ret new_ptr New pointer value - */ -static inline __attribute__ (( always_inline )) userptr_t -userptr_add ( userptr_t ptr, off_t offset ) { - return ( ptr + offset ); -} - -/** - * Copy data to user buffer - * - * @v buffer User buffer - * @v offset Offset within user buffer - * @v src Source - * @v len Length - */ -static inline __attribute__ (( always_inline )) void -copy_to_user ( userptr_t buffer, off_t offset, const void *src, size_t len ) { - memcpy ( ( ( void * ) buffer + offset ), src, len ); -} - -/** - * Copy data from user buffer - * - * @v dest Destination - * @v buffer User buffer - * @v offset Offset within user buffer - * @v len Length - */ -static inline __attribute__ (( always_inline )) void -copy_from_user ( void *dest, userptr_t buffer, off_t offset, size_t len ) { - memcpy ( dest, ( ( void * ) buffer + offset ), len ); -} - -/** - * Copy data between user buffers - * - * @v dest Destination user buffer - * @v dest_off Offset within destination buffer - * @v src Source user buffer - * @v src_off Offset within source buffer - * @v len Length - */ -static inline __attribute__ (( always_inline )) void -memcpy_user ( userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, - size_t len ) { - memcpy ( ( ( void * ) dest + dest_off ), ( ( void * ) src + src_off ), - len ); -} - -/** - * Copy data between user buffers, allowing for overlap - * - * @v dest Destination user buffer - * @v dest_off Offset within destination buffer - * @v src Source user buffer - * @v src_off Offset within source buffer - * @v len Length - */ -static inline __attribute__ (( always_inline )) void -memmove_user ( userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, - size_t len ) { - memmove ( ( ( void * ) dest + dest_off ), ( ( void * ) src + src_off ), - len ); -} - -/** - * Fill user buffer with a constant byte - * - * @v buffer User buffer - * @v offset Offset within buffer - * @v c Constant byte with which to fill - * @v len Length - */ -static inline __attribute__ (( always_inline )) void -memset_user ( userptr_t buffer, off_t offset, int c, size_t len ) { - memset ( ( ( void * ) buffer + offset ), c, len ); -} - -/** - * Find length of NUL-terminated string in user buffer - * - * @v buffer User buffer - * @v offset Offset within buffer - * @ret len Length of string (excluding NUL) - */ -static inline __attribute__ (( always_inline )) size_t -strlen_user ( userptr_t buffer, off_t offset ) { - return strlen ( ( void * ) buffer + offset ); -} - -/** - * Find character in user buffer - * - * @v buffer User buffer - * @v offset Starting offset within buffer - * @v c Character to search for - * @v len Length of user buffer - * @ret offset Offset of character, or <0 if not found - */ -static inline __attribute__ (( always_inline )) off_t -memchr_user ( userptr_t buffer, off_t offset, int c, size_t len ) { - void *found; - - found = memchr ( ( ( void * ) buffer + offset ), c, len ); - return ( found ? ( found - ( void * ) buffer ) : -1 ); -} - -/** - * Convert virtual address to user buffer - * - * @v virtual Virtual address - * @ret buffer User buffer - * - * This constructs a user buffer from an ordinary pointer. Use it - * when you need to pass a pointer to an internal buffer to a function - * that expects a @c userptr_t. - */ -static inline __attribute__ (( always_inline )) userptr_t -virt_to_user ( void * virtual ) { - return ( ( intptr_t ) virtual ); -} - /** * Convert segment:offset address to user buffer * @@ -251,32 +167,9 @@ virt_to_user ( void * virtual ) { * @v offset Real-mode offset * @ret buffer User buffer */ -static inline __attribute__ (( always_inline )) userptr_t +static inline __always_inline userptr_t real_to_user ( unsigned int segment, unsigned int offset ) { - return virt_to_user ( VIRTUAL ( segment, offset ) ); -} - -/** - * Convert physical address to user buffer - * - * @v physical Physical address - * @ret buffer User buffer - */ -static inline __attribute__ (( always_inline )) userptr_t -phys_to_user ( physaddr_t physical ) { - return virt_to_user ( phys_to_virt ( physical ) ); -} - -/** - * Convert user buffer to physical address - * - * @v buffer User buffer - * @v offset Offset within user buffer - * @ret physical Physical address - */ -static inline __attribute__ (( always_inline )) physaddr_t -user_to_phys ( userptr_t buffer, off_t offset ) { - return virt_to_phys ( ( void * ) buffer + offset ); + return ( phys_to_user ( ( segment << 4 ) + offset ) ); } extern uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ); diff --git a/gpxe/src/arch/i386/include/pci_io.h b/gpxe/src/arch/i386/include/pci_io.h deleted file mode 100644 index 4888d557..00000000 --- a/gpxe/src/arch/i386/include/pci_io.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _PCI_IO_H -#define _PCI_IO_H - -#include -#include - -/** @file - * - * i386 PCI configuration space access - * - * We have two methods of PCI configuration space access: the PCI BIOS - * and direct Type 1 accesses. Selecting between them is via the - * compile-time switch -DCONFIG_PCI_DIRECT. - * - */ - -#if CONFIG_PCI_DIRECT -#define pci_max_bus pcidirect_max_bus -#define pci_read_config_byte pcidirect_read_config_byte -#define pci_read_config_word pcidirect_read_config_word -#define pci_read_config_dword pcidirect_read_config_dword -#define pci_write_config_byte pcidirect_write_config_byte -#define pci_write_config_word pcidirect_write_config_word -#define pci_write_config_dword pcidirect_write_config_dword -#else /* CONFIG_PCI_DIRECT */ -#define pci_max_bus pcibios_max_bus -#define pci_read_config_byte pcibios_read_config_byte -#define pci_read_config_word pcibios_read_config_word -#define pci_read_config_dword pcibios_read_config_dword -#define pci_write_config_byte pcibios_write_config_byte -#define pci_write_config_word pcibios_write_config_word -#define pci_write_config_dword pcibios_write_config_dword -#endif /* CONFIG_PCI_DIRECT */ - -#endif /* _PCI_IO_H */ diff --git a/gpxe/src/arch/i386/include/pcibios.h b/gpxe/src/arch/i386/include/pcibios.h deleted file mode 100644 index 3d08d135..00000000 --- a/gpxe/src/arch/i386/include/pcibios.h +++ /dev/null @@ -1,122 +0,0 @@ -#ifndef _PCIBIOS_H -#define _PCIBIOS_H - -#include - -/** @file - * - * PCI configuration space access via PCI BIOS - * - */ - -struct pci_device; - -#define PCIBIOS_INSTALLATION_CHECK 0xb1010000 -#define PCIBIOS_READ_CONFIG_BYTE 0xb1080000 -#define PCIBIOS_READ_CONFIG_WORD 0xb1090000 -#define PCIBIOS_READ_CONFIG_DWORD 0xb10a0000 -#define PCIBIOS_WRITE_CONFIG_BYTE 0xb10b0000 -#define PCIBIOS_WRITE_CONFIG_WORD 0xb10c0000 -#define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d0000 - -extern int pcibios_max_bus ( void ); -extern int pcibios_read ( struct pci_device *pci, uint32_t command, - uint32_t *value ); -extern int pcibios_write ( struct pci_device *pci, uint32_t command, - uint32_t value ); - -/** - * Read byte from PCI configuration space via PCI BIOS - * - * @v pci PCI device - * @v where Location within PCI configuration space - * @v value Value read - * @ret rc Return status code - */ -static inline __attribute__ (( always_inline )) int -pcibios_read_config_byte ( struct pci_device *pci, unsigned int where, - uint8_t *value ) { - uint32_t tmp; - int rc; - - rc = pcibios_read ( pci, PCIBIOS_READ_CONFIG_BYTE | where, &tmp ); - *value = tmp; - return rc; -} - -/** - * Read word from PCI configuration space via PCI BIOS - * - * @v pci PCI device - * @v where Location within PCI configuration space - * @v value Value read - * @ret rc Return status code - */ -static inline __attribute__ (( always_inline )) int -pcibios_read_config_word ( struct pci_device *pci, unsigned int where, - uint16_t *value ) { - uint32_t tmp; - int rc; - - rc = pcibios_read ( pci, PCIBIOS_READ_CONFIG_WORD | where, &tmp ); - *value = tmp; - return rc; -} - -/** - * Read dword from PCI configuration space via PCI BIOS - * - * @v pci PCI device - * @v where Location within PCI configuration space - * @v value Value read - * @ret rc Return status code - */ -static inline __attribute__ (( always_inline )) int -pcibios_read_config_dword ( struct pci_device *pci, unsigned int where, - uint32_t *value ) { - return pcibios_read ( pci, PCIBIOS_READ_CONFIG_DWORD | where, value ); -} - -/** - * Write byte to PCI configuration space via PCI BIOS - * - * @v pci PCI device - * @v where Location within PCI configuration space - * @v value Value to be written - * @ret rc Return status code - */ -static inline __attribute__ (( always_inline )) int -pcibios_write_config_byte ( struct pci_device *pci, unsigned int where, - uint8_t value ) { - return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_BYTE | where, value ); -} - -/** - * Write word to PCI configuration space via PCI BIOS - * - * @v pci PCI device - * @v where Location within PCI configuration space - * @v value Value to be written - * @ret rc Return status code - */ -static inline __attribute__ (( always_inline )) int -pcibios_write_config_word ( struct pci_device *pci, unsigned int where, - uint16_t value ) { - return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_WORD | where, value ); -} - -/** - * Write dword to PCI configuration space via PCI BIOS - * - * @v pci PCI device - * @v where Location within PCI configuration space - * @v value Value to be written - * @ret rc Return status code - */ -static inline __attribute__ (( always_inline )) int -pcibios_write_config_dword ( struct pci_device *pci, unsigned int where, - uint32_t value ) { - return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_DWORD | where, value); -} - -#endif /* _PCIBIOS_H */ diff --git a/gpxe/src/arch/i386/include/pcidirect.h b/gpxe/src/arch/i386/include/pcidirect.h deleted file mode 100644 index 4e2e9d12..00000000 --- a/gpxe/src/arch/i386/include/pcidirect.h +++ /dev/null @@ -1,126 +0,0 @@ -#ifndef _PCIDIRECT_H -#define _PCIDIRECT_H - -#include -#include - -/** @file - * - * PCI configuration space access via Type 1 accesses - * - */ - -#define PCIDIRECT_CONFIG_ADDRESS 0xcf8 -#define PCIDIRECT_CONFIG_DATA 0xcfc - -struct pci_device; - -extern void pcidirect_prepare ( struct pci_device *pci, int where ); - -/** - * Determine maximum PCI bus number within system - * - * @ret max_bus Maximum bus number - */ -static inline int pcidirect_max_bus ( void ) { - /* No way to work this out via Type 1 accesses */ - return 0xff; -} - -/** - * Read byte from PCI configuration space via Type 1 access - * - * @v pci PCI device - * @v where Location within PCI configuration space - * @v value Value read - * @ret rc Return status code - */ -static inline __attribute__ (( always_inline )) int -pcidirect_read_config_byte ( struct pci_device *pci, unsigned int where, - uint8_t *value ) { - pcidirect_prepare ( pci, where ); - *value = inb ( PCIDIRECT_CONFIG_DATA + ( where & 3 ) ); - return 0; -} - -/** - * Read word from PCI configuration space via Type 1 access - * - * @v pci PCI device - * @v where Location within PCI configuration space - * @v value Value read - * @ret rc Return status code - */ -static inline __attribute__ (( always_inline )) int -pcidirect_read_config_word ( struct pci_device *pci, unsigned int where, - uint16_t *value ) { - pcidirect_prepare ( pci, where ); - *value = inw ( PCIDIRECT_CONFIG_DATA + ( where & 2 ) ); - return 0; -} - -/** - * Read dword from PCI configuration space via Type 1 access - * - * @v pci PCI device - * @v where Location within PCI configuration space - * @v value Value read - * @ret rc Return status code - */ -static inline __attribute__ (( always_inline )) int -pcidirect_read_config_dword ( struct pci_device *pci, unsigned int where, - uint32_t *value ) { - pcidirect_prepare ( pci, where ); - *value = inl ( PCIDIRECT_CONFIG_DATA ); - return 0; -} - -/** - * Write byte to PCI configuration space via Type 1 access - * - * @v pci PCI device - * @v where Location within PCI configuration space - * @v value Value to be written - * @ret rc Return status code - */ -static inline __attribute__ (( always_inline )) int -pcidirect_write_config_byte ( struct pci_device *pci, unsigned int where, - uint8_t value ) { - pcidirect_prepare ( pci, where ); - outb ( value, PCIDIRECT_CONFIG_DATA + ( where & 3 ) ); - return 0; -} - -/** - * Write word to PCI configuration space via Type 1 access - * - * @v pci PCI device - * @v where Location within PCI configuration space - * @v value Value to be written - * @ret rc Return status code - */ -static inline __attribute__ (( always_inline )) int -pcidirect_write_config_word ( struct pci_device *pci, unsigned int where, - uint16_t value ) { - pcidirect_prepare ( pci, where ); - outw ( value, PCIDIRECT_CONFIG_DATA + ( where & 2 ) ); - return 0; -} - -/** - * Write dword to PCI configuration space via Type 1 access - * - * @v pci PCI device - * @v where Location within PCI configuration space - * @v value Value to be written - * @ret rc Return status code - */ -static inline __attribute__ (( always_inline )) int -pcidirect_write_config_dword ( struct pci_device *pci, unsigned int where, - uint32_t value ) { - pcidirect_prepare ( pci, where ); - outl ( value, PCIDIRECT_CONFIG_DATA ); - return 0; -} - -#endif /* _PCIDIRECT_H */ diff --git a/gpxe/src/arch/i386/include/pxe_addr.h b/gpxe/src/arch/i386/include/pxe_addr.h deleted file mode 100644 index 954551e8..00000000 --- a/gpxe/src/arch/i386/include/pxe_addr.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Architecture-specific portion of pxe.h for Etherboot - * - * This file has to define the types SEGOFF16_t, SEGDESC_t and - * SEGSEL_t for use in other PXE structures. See pxe.h for details. - */ - -#ifndef PXE_ADDR_H -#define PXE_ADDR_H - -#define IS_NULL_SEGOFF16(x) ( ( (x).segment == 0 ) && ( (x).offset == 0 ) ) -#define SEGOFF16_TO_PTR(x) ( VIRTUAL( (x).segment, (x).offset ) ) -#define PTR_TO_SEGOFF16(ptr,segoff16) \ - (segoff16).segment = SEGMENT(ptr); \ - (segoff16).offset = OFFSET(ptr); - -#endif /* PXE_ADDR_H */ diff --git a/gpxe/src/arch/i386/include/realmode.h b/gpxe/src/arch/i386/include/realmode.h index 5d3ddf50..26e6dd77 100644 --- a/gpxe/src/arch/i386/include/realmode.h +++ b/gpxe/src/arch/i386/include/realmode.h @@ -1,45 +1,15 @@ #ifndef REALMODE_H #define REALMODE_H -#ifndef ASSEMBLY - -#include "stdint.h" -#include "registers.h" -#include "io.h" +#include +#include +#include /* * Data structures and type definitions * */ -/* Segment:offset structure. Note that the order within the structure - * is offset:segment. - */ -struct segoff { - uint16_t offset; - uint16_t segment; -} __attribute__ (( packed )); - -typedef struct segoff segoff_t; - -/* Macro hackery needed to stringify bits of inline assembly */ -#define RM_XSTR(x) #x -#define RM_STR(x) RM_XSTR(x) - -/* Drag in the selected real-mode transition library header */ -#ifdef KEEP_IT_REAL -#include "libkir.h" -#else -#include "librm.h" -#endif - -/* - * The API to some functions is identical between librm and libkir, so - * they are documented here, even though the prototypes are in librm.h - * and libkir.h. - * - */ - /* * Declaration of variables in .data16 * @@ -92,24 +62,53 @@ typedef struct segoff segoff_t; * assembler output to make sure that it's doing the right thing. */ -/* - * void copy_to_real ( uint16_t dest_seg, uint16_t dest_off, - * void *src, size_t n ) - * void copy_from_real ( void *dest, uint16_t src_seg, uint16_t src_off, - * size_t n ) +/** + * Copy data to base memory * - * These functions can be used to copy data to and from arbitrary - * locations in base memory. + * @v dest_seg Destination segment + * @v dest_off Destination offset + * @v src Source + * @v len Length */ +static inline __always_inline void +copy_to_real ( unsigned int dest_seg, unsigned int dest_off, + void *src, size_t n ) { + copy_to_user ( real_to_user ( dest_seg, dest_off ), 0, src, n ); +} -/* - * put_real ( variable, uint16_t dest_seg, uint16_t dest_off ) - * get_real ( variable, uint16_t src_seg, uint16_t src_off ) +/** + * Copy data to base memory + * + * @v dest Destination + * @v src_seg Source segment + * @v src_off Source offset + * @v len Length + */ +static inline __always_inline void +copy_from_real ( void *dest, unsigned int src_seg, + unsigned int src_off, size_t n ) { + copy_from_user ( dest, real_to_user ( src_seg, src_off ), 0, n ); +} + +/** + * Write a single variable to base memory * - * These macros can be used to read or write single variables to and - * from arbitrary locations in base memory. "variable" must be a - * variable of either 1, 2 or 4 bytes in length. + * @v var Variable to write + * @v dest_seg Destination segment + * @v dest_off Destination offset */ +#define put_real( var, dest_seg, dest_off ) \ + copy_to_real ( (dest_seg), (dest_off), &(var), sizeof (var) ) + +/** + * Read a single variable from base memory + * + * @v var Variable to read + * @v src_seg Source segment + * @v src_off Source offset + */ +#define get_real( var, src_seg, src_off ) \ + copy_from_real ( &(var), (src_seg), (src_off), sizeof (var) ) /* * REAL_CODE ( asm_code_str ) @@ -123,6 +122,4 @@ typedef struct segoff segoff_t; * */ -#endif /* ASSEMBLY */ - #endif /* REALMODE_H */ diff --git a/gpxe/src/arch/i386/include/registers.h b/gpxe/src/arch/i386/include/registers.h index 2b9b2b43..e68fa85a 100644 --- a/gpxe/src/arch/i386/include/registers.h +++ b/gpxe/src/arch/i386/include/registers.h @@ -10,8 +10,7 @@ * */ -#include "compiler.h" /* for doxygen */ -#include "stdint.h" +#include /** * A 16-bit general register. @@ -184,4 +183,14 @@ struct i386_all_regs { #define SF ( 1 << 7 ) #define OF ( 1 << 11 ) +/* Segment:offset structure. Note that the order within the structure + * is offset:segment. + */ +struct segoff { + uint16_t offset; + uint16_t segment; +} PACKED; + +typedef struct segoff segoff_t; + #endif /* REGISTERS_H */ diff --git a/gpxe/src/arch/i386/include/undi.h b/gpxe/src/arch/i386/include/undi.h index 9936e17f..c6253d0a 100644 --- a/gpxe/src/arch/i386/include/undi.h +++ b/gpxe/src/arch/i386/include/undi.h @@ -24,10 +24,6 @@ struct undi_device { SEGOFF16_t ppxe; /** Entry point */ SEGOFF16_t entry; - /** Return stack */ - UINT16_t return_stack[3]; - /** Return type */ - UINT16_t return_type; /** Free base memory after load */ UINT16_t fbms; /** Free base memory prior to load */ @@ -99,4 +95,10 @@ static inline void * undi_get_drvdata ( struct undi_device *undi ) { /** UNDI flag: START_UNDI has been called */ #define UNDI_FL_STARTED 0x0001 +/** UNDI flag: UNDI_STARTUP and UNDI_INITIALIZE have been called */ +#define UNDI_FL_INITIALIZED 0x0002 + +/** UNDI flag: keep stack resident */ +#define UNDI_FL_KEEP_ALL 0x0004 + #endif /* _UNDI_H */ diff --git a/gpxe/src/arch/i386/include/virtaddr.h b/gpxe/src/arch/i386/include/virtaddr.h deleted file mode 100644 index f2ffa2a1..00000000 --- a/gpxe/src/arch/i386/include/virtaddr.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef VIRTADDR_H -#define VIRTADDR_H - -/* Segment selectors as used in our protected-mode GDTs. - * - * Don't change these unless you really know what you're doing. - */ - -#define VIRTUAL_CS 0x08 -#define VIRTUAL_DS 0x10 -#define PHYSICAL_CS 0x18 -#define PHYSICAL_DS 0x20 -#define REAL_CS 0x28 -#define REAL_DS 0x30 -#if 0 -#define LONG_CS 0x38 -#define LONG_DS 0x40 -#endif - -#ifndef ASSEMBLY - -#include "stdint.h" -#include "string.h" - -#ifndef KEEP_IT_REAL - -/* - * Without -DKEEP_IT_REAL, we are in 32-bit protected mode with a - * fixed link address but an unknown physical start address. Our GDT - * sets up code and data segments with an offset of virt_offset, so - * that link-time addresses can still work. - * - */ - -/* C-callable function prototypes */ - -extern void relocate_to ( uint32_t new_phys_addr ); - -/* Variables in virtaddr.S */ -extern unsigned long virt_offset; - -/* - * Convert between virtual and physical addresses - * - */ -static inline unsigned long virt_to_phys ( volatile const void *virt_addr ) { - return ( ( unsigned long ) virt_addr ) + virt_offset; -} - -static inline void * phys_to_virt ( unsigned long phys_addr ) { - return ( void * ) ( phys_addr - virt_offset ); -} - -static inline void copy_to_phys ( physaddr_t dest, const void *src, - size_t len ) { - memcpy ( phys_to_virt ( dest ), src, len ); -} - -static inline void copy_from_phys ( void *dest, physaddr_t src, size_t len ) { - memcpy ( dest, phys_to_virt ( src ), len ); -} - -static inline void copy_phys_to_phys ( physaddr_t dest, physaddr_t src, - size_t len ) { - memcpy ( phys_to_virt ( dest ), phys_to_virt ( src ), len ); -} - -#else /* KEEP_IT_REAL */ - -/* - * With -DKEEP_IT_REAL, we are in 16-bit real mode with fixed link - * addresses and a segmented memory model. We have separate code and - * data segments. - * - * Because we may be called in 16-bit protected mode (damn PXE spec), - * we cannot simply assume that physical = segment * 16 + offset. - * Instead, we have to look up the physical start address of the - * segment in the !PXE structure. We have to assume that - * virt_to_phys() is called only on pointers within the data segment, - * because nothing passes segment information to us. - * - * We don't implement phys_to_virt at all, because there will be many - * addresses that simply cannot be reached via a virtual address when - * the virtual address space is limited to 64kB! - */ - -static inline unsigned long virt_to_phys ( volatile const void *virt_addr ) { - /* Cheat: just for now, do the segment*16+offset calculation */ - uint16_t ds; - - __asm__ ( "movw %%ds, %%ax" : "=a" ( ds ) : ); - return ( 16 * ds + ( ( unsigned long ) virt_addr ) ); -} - -/* Define it as a deprecated function so that we get compile-time - * warnings, rather than just the link-time errors. - */ -extern void * phys_to_virt ( unsigned long phys_addr ) - __attribute__ ((deprecated)); - -#endif /* KEEP_IT_REAL */ - -#endif /* ASSEMBLY */ - -#endif /* VIRTADDR_H */ diff --git a/gpxe/src/arch/i386/interface/efi/efix86_nap.c b/gpxe/src/arch/i386/interface/efi/efix86_nap.c new file mode 100644 index 00000000..45e99a68 --- /dev/null +++ b/gpxe/src/arch/i386/interface/efi/efix86_nap.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2008 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +/** @file + * + * gPXE CPU sleeping API for EFI + * + */ + +/** + * Sleep until next interrupt + * + */ +static void efix86_cpu_nap ( void ) { + /* + * I can't find any EFI API that allows us to put the CPU to + * sleep. The CpuSleep() function is defined in CpuLib.h, but + * isn't part of any exposed protocol so we have no way to + * call it. + * + * The EFI shell doesn't seem to bother sleeping the CPU; it + * just sits there idly burning power. + * + */ + __asm__ __volatile__ ( "hlt" ); +} + +PROVIDE_NAP ( efix86, cpu_nap, efix86_cpu_nap ); diff --git a/gpxe/src/arch/i386/interface/pcbios/bios_nap.c b/gpxe/src/arch/i386/interface/pcbios/bios_nap.c new file mode 100644 index 00000000..2f4a0513 --- /dev/null +++ b/gpxe/src/arch/i386/interface/pcbios/bios_nap.c @@ -0,0 +1,14 @@ +#include +#include + +/** + * Save power by halting the CPU until the next interrupt + * + */ +static void bios_cpu_nap ( void ) { + __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" + "hlt\n\t" + "cli\n\t" ) : : ); +} + +PROVIDE_NAP ( pcbios, cpu_nap, bios_cpu_nap ); diff --git a/gpxe/src/arch/i386/interface/pcbios/bios_timer.c b/gpxe/src/arch/i386/interface/pcbios/bios_timer.c new file mode 100644 index 00000000..0b475ea3 --- /dev/null +++ b/gpxe/src/arch/i386/interface/pcbios/bios_timer.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/** @file + * + * BIOS timer + * + */ + +#include +#include +#include + +/** + * Get current system time in ticks + * + * @ret ticks Current time, in ticks + * + * Use direct memory access to BIOS variables, longword 0040:006C + * (ticks today) and byte 0040:0070 (midnight crossover flag) instead + * of calling timeofday BIOS interrupt. + */ +static unsigned long bios_currticks ( void ) { + static int days = 0; + uint32_t ticks; + uint8_t midnight; + + /* Re-enable interrupts so that the timer interrupt can occur */ + __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" + "nop\n\t" + "nop\n\t" + "cli\n\t" ) : : ); + + get_real ( ticks, BDA_SEG, 0x006c ); + get_real ( midnight, BDA_SEG, 0x0070 ); + + if ( midnight ) { + midnight = 0; + put_real ( midnight, BDA_SEG, 0x0070 ); + days += 0x1800b0; + } + + return ( days + ticks ); +} + +PROVIDE_TIMER_INLINE ( pcbios, udelay ); +PROVIDE_TIMER ( pcbios, currticks, bios_currticks ); +PROVIDE_TIMER_INLINE ( pcbios, ticks_per_sec ); diff --git a/gpxe/src/arch/i386/interface/pcbios/biosint.c b/gpxe/src/arch/i386/interface/pcbios/biosint.c index 8ef2d7ab..1306f918 100644 --- a/gpxe/src/arch/i386/interface/pcbios/biosint.c +++ b/gpxe/src/arch/i386/interface/pcbios/biosint.c @@ -7,17 +7,6 @@ * */ -/** - * Hooked interrupt count - * - * At exit, after unhooking all possible interrupts, this counter - * should be examined. If it is non-zero, it means that we failed to - * unhook at least one interrupt vector, and so must not free up the - * memory we are using. (Note that this also implies that we should - * re-hook INT 15 in order to hide ourselves from the memory map). - */ -int hooked_bios_interrupts = 0; - /** * Hook INT vector * diff --git a/gpxe/src/arch/i386/interface/pcbios/memtop_umalloc.c b/gpxe/src/arch/i386/interface/pcbios/memtop_umalloc.c new file mode 100644 index 00000000..2eb7f76d --- /dev/null +++ b/gpxe/src/arch/i386/interface/pcbios/memtop_umalloc.c @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * 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 + * + * External memory allocation + * + */ + +#include +#include +#include +#include +#include +#include + +/** Alignment of external allocated memory */ +#define EM_ALIGN ( 4 * 1024 ) + +/** Equivalent of NOWHERE for user pointers */ +#define UNOWHERE ( ~UNULL ) + +/** An external memory block */ +struct external_memory { + /** Size of this memory block (excluding this header) */ + size_t size; + /** Block is currently in use */ + int used; +}; + +/** Top of heap */ +static userptr_t top = UNULL; + +/** Bottom of heap (current lowest allocated block) */ +static userptr_t bottom = UNULL; + +/** + * 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; + } + } + + if ( ! top ) { + DBG ( "No external heap available\n" ); + return -ENOMEM; + } + + DBG ( "External heap grows downwards from %lx\n", + user_to_phys ( top, 0 ) ); + return 0; +} + +/** + * Collect free blocks + * + */ +static void ecollect_free ( void ) { + struct external_memory extmem; + + /* Walk the free list and collect empty blocks */ + while ( bottom != top ) { + copy_from_user ( &extmem, bottom, -sizeof ( extmem ), + sizeof ( extmem ) ); + if ( extmem.used ) + 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 ) ) ); + } +} + +/** + * Reallocate external memory + * + * @v old_ptr Memory previously allocated by umalloc(), or UNULL + * @v new_size Requested size + * @ret new_ptr Allocated memory, or UNULL + * + * Calling realloc() with a new size of zero is a valid way to free a + * memory block. + */ +static userptr_t 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 ( ! top ) { + if ( ( rc = init_eheap() ) != 0 ) + return rc; + } + + /* Get block properties into extmem */ + if ( ptr && ( ptr != UNOWHERE ) ) { + /* Determine old size */ + copy_from_user ( &extmem, ptr, -sizeof ( extmem ), + sizeof ( extmem ) ); + } else { + /* Create a zero-length block */ + ptr = bottom = userptr_add ( bottom, -sizeof ( extmem ) ); + DBG ( "EXTMEM allocating [%lx,%lx)\n", + user_to_phys ( ptr, 0 ), user_to_phys ( ptr, 0 ) ); + extmem.size = 0; + } + extmem.used = ( new_size > 0 ); + + /* Expand/shrink block if possible */ + if ( ptr == bottom ) { + /* Update block */ + new = userptr_add ( ptr, - ( new_size - extmem.size ) ); + align = ( user_to_phys ( new, 0 ) & ( EM_ALIGN - 1 ) ); + new_size += align; + new = userptr_add ( new, -align ); + DBG ( "EXTMEM expanding [%lx,%lx) to [%lx,%lx)\n", + user_to_phys ( ptr, 0 ), + user_to_phys ( ptr, extmem.size ), + user_to_phys ( new, 0 ), + 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; + } else { + /* Cannot expand; can only pretend to shrink */ + if ( new_size > extmem.size ) { + /* Refuse to expand */ + DBG ( "EXTMEM cannot expand [%lx,%lx)\n", + user_to_phys ( ptr, 0 ), + user_to_phys ( ptr, extmem.size ) ); + return UNULL; + } + } + + /* Write back block properties */ + copy_to_user ( new, -sizeof ( extmem ), &extmem, + sizeof ( extmem ) ); + + /* Collect any free blocks and update hidden memory region */ + ecollect_free(); + hide_umalloc ( user_to_phys ( bottom, -sizeof ( extmem ) ), + user_to_phys ( top, 0 ) ); + + return ( new_size ? new : UNOWHERE ); +} + +PROVIDE_UMALLOC ( memtop, urealloc, memtop_urealloc ); diff --git a/gpxe/src/arch/i386/interface/pcbios/pcibios.c b/gpxe/src/arch/i386/interface/pcbios/pcibios.c new file mode 100644 index 00000000..81b4fd3c --- /dev/null +++ b/gpxe/src/arch/i386/interface/pcbios/pcibios.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2006 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include + +/** @file + * + * PCI configuration space access via PCI BIOS + * + */ + +/** + * Determine maximum PCI bus number within system + * + * @ret max_bus Maximum bus number + */ +static int pcibios_max_bus ( void ) { + int discard_a, discard_D; + uint8_t max_bus; + + __asm__ __volatile__ ( REAL_CODE ( "stc\n\t" + "int $0x1a\n\t" + "jnc 1f\n\t" + "xorw %%cx, %%cx\n\t" + "\n1:\n\t" ) + : "=c" ( max_bus ), "=a" ( discard_a ), + "=D" ( discard_D ) + : "a" ( PCIBIOS_INSTALLATION_CHECK >> 16 ), + "D" ( 0 ) + : "ebx", "edx" ); + + return max_bus; +} + +/** + * Read configuration space via PCI BIOS + * + * @v pci PCI device + * @v command PCI BIOS command + * @v value Value read + * @ret rc Return status code + */ +int pcibios_read ( struct pci_device *pci, uint32_t command, uint32_t *value ){ + int discard_b, discard_D; + int status; + + __asm__ __volatile__ ( REAL_CODE ( "stc\n\t" + "int $0x1a\n\t" + "jnc 1f\n\t" + "xorl %%eax, %%eax\n\t" + "decl %%eax\n\t" + "movl %%eax, %%ecx\n\t" + "\n1:\n\t" ) + : "=a" ( status ), "=b" ( discard_b ), + "=c" ( *value ), "=D" ( discard_D ) + : "a" ( command >> 16 ), "D" ( command ), + "b" ( PCI_BUSDEVFN ( pci->bus, pci->devfn ) ) + : "edx" ); + + return ( ( status >> 8 ) & 0xff ); +} + +/** + * Write configuration space via PCI BIOS + * + * @v pci PCI device + * @v command PCI BIOS command + * @v value Value to be written + * @ret rc Return status code + */ +int pcibios_write ( struct pci_device *pci, uint32_t command, uint32_t value ){ + int discard_b, discard_c, discard_D; + int status; + + __asm__ __volatile__ ( REAL_CODE ( "stc\n\t" + "int $0x1a\n\t" + "jnc 1f\n\t" + "movb $0xff, %%ah\n\t" + "\n1:\n\t" ) + : "=a" ( status ), "=b" ( discard_b ), + "=c" ( discard_c ), "=D" ( discard_D ) + : "a" ( command >> 16 ), "D" ( command ), + "b" ( PCI_BUSDEVFN ( pci->bus, pci->devfn ) ), + "c" ( value ) + : "edx" ); + + return ( ( status >> 8 ) & 0xff ); +} + +PROVIDE_PCIAPI ( pcbios, pci_max_bus, pcibios_max_bus ); +PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_byte ); +PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_word ); +PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_dword ); +PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_byte ); +PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_word ); +PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_dword ); diff --git a/gpxe/src/arch/i386/interface/pxe/pxe_entry.S b/gpxe/src/arch/i386/interface/pxe/pxe_entry.S index e5d327a5..8dd1a2ea 100644 --- a/gpxe/src/arch/i386/interface/pxe/pxe_entry.S +++ b/gpxe/src/arch/i386/interface/pxe/pxe_entry.S @@ -44,10 +44,10 @@ ppxe: .byte SegDescCnt /* SegDescCnt */ .word 0 /* FirstSelector */ pxe_segments: - .word 0, 0, 0, _data16_size /* Stack */ - .word 0, 0, 0, _data16_size /* UNDIData */ - .word 0, 0, 0, _text16_size /* UNDICode */ - .word 0, 0, 0, _text16_size /* UNDICodeWrite */ + .word 0, 0, 0, _data16_memsz /* Stack */ + .word 0, 0, 0, _data16_memsz /* UNDIData */ + .word 0, 0, 0, _text16_memsz /* UNDICode */ + .word 0, 0, 0, _text16_memsz /* UNDICodeWrite */ .word 0, 0, 0, 0 /* BC_Data */ .word 0, 0, 0, 0 /* BC_Code */ .word 0, 0, 0, 0 /* BC_CodeWrite */ @@ -76,15 +76,15 @@ pxenv: .long 0 /* PMEntry */ .word 0 /* PMSelector */ .word 0 /* StackSeg */ - .word _data16_size /* StackSize */ + .word _data16_memsz /* StackSize */ .word 0 /* BC_CodeSeg */ .word 0 /* BC_CodeSize */ .word 0 /* BC_DataSeg */ .word 0 /* BC_DataSize */ .word 0 /* UNDIDataSeg */ - .word _data16_size /* UNDIDataSize */ + .word _data16_memsz /* UNDIDataSize */ .word 0 /* UNDICodeSeg */ - .word _text16_size /* UNDICodeSize */ + .word _text16_memsz /* UNDICodeSize */ .word ppxe, 0 /* PXEPtr */ .equ pxenv_length, . - pxenv .size pxenv, . - pxenv diff --git a/gpxe/src/arch/i386/prefix/dskprefix.S b/gpxe/src/arch/i386/prefix/dskprefix.S index cdc43b37..0156812a 100644 --- a/gpxe/src/arch/i386/prefix/dskprefix.S +++ b/gpxe/src/arch/i386/prefix/dskprefix.S @@ -144,8 +144,8 @@ got_sectors: /* Jump to loaded copy */ ljmp $SYSSEG, $start_runtime -endseg: .word SYSSEG + _load_size_pgh - .section ".zinfo.fixup", "a" /* Compressor fixup information */ +endseg: .word SYSSEG + _filesz_pgh + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ .ascii "SUBW" .long endseg .long 16 @@ -353,6 +353,7 @@ msg1end: .word 0xAA55 start_runtime: + /* Install gPXE */ call install /* Set up real-mode stack */ @@ -368,7 +369,10 @@ start_runtime: pushl $main pushw %cs call prot_call - popl %eax /* discard */ + popl %ecx /* discard */ + + /* Uninstall gPXE */ + call uninstall /* Boot next device */ int $0x18 diff --git a/gpxe/src/arch/i386/prefix/efiprefix.S b/gpxe/src/arch/i386/prefix/efiprefix.S new file mode 100644 index 00000000..c4cf68e4 --- /dev/null +++ b/gpxe/src/arch/i386/prefix/efiprefix.S @@ -0,0 +1,175 @@ + .text + .code32 + .arch i386 + .section ".prefix", "a", @progbits + .org 0x00 + + /* DOS (.com) header + * + * EFI executables seem to leave most of this empty + */ +mzhdr: + .ascii "MZ" /* Magic number */ + .word 0 /* Bytes on last page of file */ + .word 0 /* Pages in file */ + .word 0 /* Relocations */ + .word 0 /* Size of header in paragraphs */ + .word 0 /* Minimum extra paragraphs needed */ + .word 0 /* Maximum extra paragraphs needed */ + .word 0 /* Initial (relative) SS value */ + .word 0 /* Initial SP value */ + .word 0 /* "Checksum" */ + .word 0 /* Initial IP value */ + .word 0 /* Initial (relative) CS value */ + .word 0 /* File address of relocation table */ + .word 0 /* Ovesrlay number */ + .word 0, 0, 0, 0 /* Reserved words */ + .word 0 /* OEM identifier (for e_oeminfo) */ + .word 0 /* OEM information; e_oemid specific */ + .word 0, 0, 0, 0, 0 /* Reserved words */ + .word 0, 0, 0, 0, 0 /* Reserved words */ + .long pehdr_lma /* File address of new exe header */ + .size mzhdr, . - mzhdr + + /* PE header */ + .org 0xc0 /* For compatibility with MS toolchain */ +pehdr: + .ascii "PE\0\0" /* Magic number */ + .word 0x014c /* CPU architecture: i386 */ + .word num_pe_sections /* Number of sections */ + .long 0x10d1a884 /* Timestamp */ + .long 0 /* Symbol table */ + .long 0 /* Number of symbols */ + .word opthdr_size /* Size of optional header */ + .word 0x2102 /* Characteristics */ + .size pehdr, . - pehdr + .equ pehdr_lma, pehdr - mzhdr + + /* "Optional" header */ +opthdr: + .word 0x010b /* Magic number */ + .byte 0 /* Linker major version number */ + .byte 0 /* Linker minor version number */ + .long _text_filesz /* Size of text section */ + .long _data_filesz /* Size of data section */ + .long _bss_filesz /* Size of bss section */ + .long efi_entry_lma /* Entry point */ + .long _text_lma /* Text section start RVA */ + .long _data_lma /* Data section start RVA */ + .long 0 /* Image base address */ + .long _max_align /* Section alignment */ + .long _max_align /* File alignment */ + .word 0 /* Operating system major version number */ + .word 0 /* Operating system minor version number */ + .word 0 /* Image major version number */ + .word 0 /* Image minor version number */ + .word 0 /* Subsystem major version number */ + .word 0 /* Subsystem minor version number */ + .long 0 /* Reserved */ + .long _filesz /* Total image size */ + .long _prefix_filesz /* Total header size */ + .long 0 /* "Checksum" */ + .word 0x0a /* Subsystem: EFI */ + .word 0 /* DLL characteristics */ + .long 0 /* Size of stack reserve */ + .long 0 /* Size of stack commit */ + .long 0 /* Size of heap reserve */ + .long 0 /* Size of heap commit */ + .long 0 /* Loader flags */ + .long 16 /* Number of data directory entries */ + .long 0, 0 /* Export directory */ + .long 0, 0 /* Import directory */ + .long 0, 0 /* Resource directory */ + .long 0, 0 /* Exception directory */ + .long 0, 0 /* Security directory */ + .long _reloc_lma, _reloc_filesz /* Base relocation directory */ + .long debugdir_lma, debugdir_size /* Debug directory */ + .long 0, 0 /* Description directory */ + .long 0, 0 /* Special directory */ + .long 0, 0 /* Thread storage directory */ + .long 0, 0 /* Load configuration directory */ + .long 0, 0 /* Bound import directory */ + .long 0, 0 /* Import address table directory */ + .long 0, 0 /* Delay import directory */ + .long 0, 0 /* Reserved */ + .long 0, 0 /* Reserved */ + .size opthdr, . - opthdr + .equ opthdr_size, . - opthdr + + /* PE sections */ +pe_sections: +text_section: + .asciz ".text" /* Section name */ + .align 8 + .long _text_filesz /* Section size */ + .long _text_lma /* Relative Virtual Address */ + .long _text_filesz /* Section size (rounded up) */ + .long _text_lma /* Pointer to raw data */ + .long 0 /* Link-time relocations */ + .long 0 /* Line numbers */ + .word 0 /* Number of link-time relocations */ + .word 0 /* Number of line numbers */ + .long 0x68000020 /* Characteristics */ +rodata_section: + .asciz ".rodata" /* Section name */ + .align 8 + .long _rodata_filesz /* Section size */ + .long _rodata_lma /* Relative Virtual Address */ + .long _rodata_filesz /* Section size (rounded up) */ + .long _rodata_lma /* Pointer to raw data */ + .long 0 /* Link-time relocations */ + .long 0 /* Line numbers */ + .word 0 /* Number of link-time relocations */ + .word 0 /* Number of line numbers */ + .long 0x48000040 /* Characteristics */ +data_section: + .asciz ".data" /* Section name */ + .align 8 + .long _data_filesz /* Section size */ + .long _data_lma /* Relative Virtual Address */ + .long _data_filesz /* Section size (rounded up) */ + .long _data_lma /* Pointer to raw data */ + .long 0 /* Link-time relocations */ + .long 0 /* Line numbers */ + .word 0 /* Number of link-time relocations */ + .word 0 /* Number of line numbers */ + .long 0xc8000040 /* Characteristics */ +reloc_section: + .asciz ".reloc" /* Section name */ + .align 8 + .long _reloc_filesz /* Section size */ + .long _reloc_lma /* Relative Virtual Address */ + .long _reloc_filesz /* Section size (rounded up) */ + .long _reloc_lma /* Pointer to raw data */ + .long 0 /* Link-time relocations */ + .long 0 /* Line numbers */ + .word 0 /* Number of link-time relocations */ + .word 0 /* Number of line numbers */ + .long 0x42000040 /* Characteristics */ + +pe_sections_end: + .size pe_sections, . - pe_sections + .equ num_pe_sections, ( ( . - pe_sections ) / 0x28 ) + + /* Debug directory */ + .section ".rodata" + .globl debugdir +debugdir: + .long 0 /* Characteristics */ + .long 0x10d1a884 /* Timestamp */ + .word 0 /* Major version */ + .word 0 /* Minor version */ + .long 0x02 /* RSDS? */ + .long codeview_rsds_size /* Size of data */ + .long codeview_rsds_lma /* RVA */ + .long codeview_rsds_lma /* File offset */ + .size debugdir, . - debugdir + .equ debugdir_size, . - debugdir + /* Codeview structure */ + .globl codeview_rsds +codeview_rsds: + .ascii "RSDS" /* Magic number */ + .long 0, 0, 0, 0, 0 /* Unused by EFI */ + .asciz "efiprefix.pdb" + .size codeview_rsds, . - codeview_rsds + .equ codeview_rsds_size, . - codeview_rsds diff --git a/gpxe/src/arch/i386/prefix/hdprefix.S b/gpxe/src/arch/i386/prefix/hdprefix.S index 56fcb36d..086d7f45 100644 --- a/gpxe/src/arch/i386/prefix/hdprefix.S +++ b/gpxe/src/arch/i386/prefix/hdprefix.S @@ -63,9 +63,9 @@ max_sector: max_head: .byte 0 load_length: - .long _load_size_sect + .long _filesz_sect - .section ".zinfo.fixup", "a" /* Compressor fixup information */ + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ .ascii "SUBL" .long load_length .long 512 @@ -82,6 +82,7 @@ load_failed: .byte 0x55, 0xaa start_image: + /* Install gPXE */ call install /* Set up real-mode stack */ @@ -97,7 +98,10 @@ start_image: pushl $main pushw %cs call prot_call - popl %eax /* discard */ + popl %ecx /* discard */ + + /* Uninstall gPXE */ + call uninstall /* Boot next device */ int $0x18 diff --git a/gpxe/src/arch/i386/prefix/kkpxeprefix.S b/gpxe/src/arch/i386/prefix/kkpxeprefix.S new file mode 100644 index 00000000..38300bed --- /dev/null +++ b/gpxe/src/arch/i386/prefix/kkpxeprefix.S @@ -0,0 +1,8 @@ +/***************************************************************************** + * PXE prefix that keep the whole PXE stack present + ***************************************************************************** + */ + +#define PXELOADER_KEEP_UNDI +#define PXELOADER_KEEP_PXE +#include "pxeprefix.S" diff --git a/gpxe/src/arch/i386/prefix/libprefix.S b/gpxe/src/arch/i386/prefix/libprefix.S index ae2a491f..56ca64d9 100644 --- a/gpxe/src/arch/i386/prefix/libprefix.S +++ b/gpxe/src/arch/i386/prefix/libprefix.S @@ -199,6 +199,39 @@ print_pci_busdevfn: ret .size print_pci_busdevfn, . - print_pci_busdevfn +/***************************************************************************** + * Utility function: clear current line + * + * Parameters: + * %ds:di : output buffer (or %di=0 to print to console) + * Returns: + * %ds:di : next character in output buffer (if applicable) + ***************************************************************************** + */ + .section ".prefix.lib" + .code16 + .globl print_kill_line +print_kill_line: + /* Preserve registers */ + pushw %ax + pushw %cx + /* Print CR */ + movb $'\r', %al + call print_character + /* Print 79 spaces */ + movb $' ', %al + movw $79, %cx +1: call print_character + loop 1b + /* Print CR */ + movb $'\r', %al + call print_character + /* Restore registers and return */ + popw %cx + popw %ax + ret + .size print_kill_line, . - print_kill_line + /**************************************************************************** * pm_call (real-mode near call) * @@ -308,7 +341,7 @@ pm_call: /* Switch CPU to protected mode and load up segment registers */ pushl %eax cli - lgdt PM_CALL_VAR(gdt)(%bp) + data32 lgdt PM_CALL_VAR(gdt)(%bp) movl %cr0, %eax orb $CR0_PE, %al movl %eax, %cr0 @@ -344,7 +377,7 @@ pm_call: popw %es popw %fs popw %gs - lgdt PM_CALL_VAR(pm_saved_gdt)(%bp) + data32 lgdt PM_CALL_VAR(pm_saved_gdt)(%bp) popfl movw %bp, %sp popw %bp @@ -504,30 +537,88 @@ install_block: .code16 .globl alloc_basemem alloc_basemem: + /* Preserve registers */ + pushw %fs + /* FBMS => %ax as segment address */ - movw $0x40, %ax - movw %ax, %fs + pushw $0x40 + popw %fs movw %fs:0x13, %ax shlw $6, %ax - /* .data16 segment address */ - subw $_data16_size_pgh, %ax + /* Calculate .data16 segment address */ + subw $_data16_memsz_pgh, %ax pushw %ax - /* .text16 segment address */ - subw $_text16_size_pgh, %ax + /* Calculate .text16 segment address */ + subw $_text16_memsz_pgh, %ax pushw %ax /* Update FBMS */ shrw $6, %ax movw %ax, %fs:0x13 - /* Return */ + /* Retrieve .text16 and .data16 segment addresses */ popw %ax popw %bx + + /* Restore registers and return */ + popw %fs ret .size alloc_basemem, . - alloc_basemem +/**************************************************************************** + * free_basemem (real-mode near call) + * + * Free space allocated with alloc_basemem. + * + * Parameters: + * %ax : .text16 segment address + * %bx : .data16 segment address + * Returns: + * %ax : 0 if successfully freed + * Corrupts: + * none + **************************************************************************** + */ + .section ".text16" + .code16 + .globl free_basemem +free_basemem: + /* Preserve registers */ + pushw %fs + + /* Check FBMS counter */ + pushw %ax + shrw $6, %ax + pushw $0x40 + popw %fs + cmpw %ax, %fs:0x13 + popw %ax + jne 1f + + /* Check hooked interrupt count */ + cmpw $0, %cs:hooked_bios_interrupts + jne 1f + + /* OK to free memory */ + addw $_text16_memsz_pgh, %ax + addw $_data16_memsz_pgh, %ax + shrw $6, %ax + movw %ax, %fs:0x13 + xorw %ax, %ax + +1: /* Restore registers and return */ + popw %fs + ret + .size free_basemem, . - free_basemem + + .section ".text16.data" + .globl hooked_bios_interrupts +hooked_bios_interrupts: + .word 0 + .size hooked_bios_interrupts, . - hooked_bios_interrupts + /**************************************************************************** * install (real-mode near call) * @@ -594,19 +685,19 @@ install_prealloc: jnz 1f movw %cs, %si shll $4, %esi -1: addl $_payload_offset, %esi +1: addl $_payload_lma, %esi /* Install .text16 and .data16 */ pushl %edi movzwl %ax, %edi shll $4, %edi - movl $_text16_size, %ecx + movl $_text16_memsz, %ecx movl %ecx, %edx call install_block /* .text16 */ movzwl %bx, %edi shll $4, %edi - movl $_data16_progbits_size, %ecx - movl $_data16_size, %edx + movl $_data16_filesz, %ecx + movl $_data16_memsz, %edx call install_block /* .data16 */ popl %edi @@ -622,8 +713,8 @@ install_prealloc: * prior to reading the E820 memory map and relocating * properly. */ - movl $_textdata_progbits_size, %ecx - movl $_textdata_size, %edx + movl $_textdata_filesz, %ecx + movl $_textdata_memsz, %edx call install_block /* Initialise librm at current location */ @@ -676,30 +767,53 @@ prot_call_vector: .size prot_call_vector, . - prot_call_vector #endif +/**************************************************************************** + * uninstall (real-mode near call) + * + * Uninstall all text and data segments. + * + * Parameters: + * %ax : .text16 segment address + * %bx : .data16 segment address + * Returns: + * none + * Corrupts: + * none + **************************************************************************** + */ + .section ".text16" + .code16 + .globl uninstall +uninstall: + call free_basemem + ret + .size uninstall, . - uninstall + + /* File split information for the compressor */ #if COMPRESS - .section ".zinfo", "a" + .section ".zinfo", "a", @progbits .ascii "COPY" - .long _prefix_load_offset - .long _prefix_progbits_size + .long _prefix_lma + .long _prefix_filesz .long _max_align .ascii "PACK" - .long _text16_load_offset - .long _text16_progbits_size + .long _text16_lma + .long _text16_filesz .long _max_align .ascii "PACK" - .long _data16_load_offset - .long _data16_progbits_size + .long _data16_lma + .long _data16_filesz .long _max_align .ascii "PACK" - .long _textdata_load_offset - .long _textdata_progbits_size + .long _textdata_lma + .long _textdata_filesz .long _max_align #else /* COMPRESS */ - .section ".zinfo", "a" + .section ".zinfo", "a", @progbits .ascii "COPY" - .long _prefix_load_offset - .long _load_size + .long _prefix_lma + .long _filesz .long _max_align #endif /* COMPRESS */ diff --git a/gpxe/src/arch/i386/prefix/lkrnprefix.S b/gpxe/src/arch/i386/prefix/lkrnprefix.S index c1e92f57..094263d2 100644 --- a/gpxe/src/arch/i386/prefix/lkrnprefix.S +++ b/gpxe/src/arch/i386/prefix/lkrnprefix.S @@ -92,9 +92,9 @@ setup_sects: root_flags: .word 0 syssize: - .long _load_size_pgh - PREFIXPGH + .long _filesz_pgh - PREFIXPGH - .section ".zinfo.fixup", "a" /* Compressor fixup information */ + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ .ascii "SUBL" .long syssize .long 16 @@ -189,6 +189,7 @@ run_gpxe: movw %ax, %ss movw $0x7c00, %sp + /* Install gPXE */ call install /* Set up real-mode stack */ @@ -204,7 +205,10 @@ run_gpxe: pushl $main pushw %cs call prot_call - popl %eax /* discard */ + popl %ecx /* discard */ + + /* Uninstall gPXE */ + call uninstall /* Boot next device */ int $0x18 diff --git a/gpxe/src/arch/i386/prefix/nbiprefix.S b/gpxe/src/arch/i386/prefix/nbiprefix.S index d4904b73..d1753e30 100644 --- a/gpxe/src/arch/i386/prefix/nbiprefix.S +++ b/gpxe/src/arch/i386/prefix/nbiprefix.S @@ -32,11 +32,11 @@ segment_header: .byte 0 .byte 0x04 /* Last segment */ .long 0x00007e00 -imglen: .long _load_size - 512 -memlen: .long _load_size - 512 +imglen: .long _filesz - 512 +memlen: .long _filesz - 512 .size segment_header, . - segment_header - .section ".zinfo.fixup", "a" /* Compressor fixup information */ + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ .ascii "SUBL" .long imglen .long 1 @@ -52,7 +52,7 @@ memlen: .long _load_size - 512 ***************************************************************************** */ entry: - /* Install low and high memory regions */ + /* Install gPXE */ call install /* Jump to .text16 segment */ @@ -64,7 +64,10 @@ entry: pushl $main pushw %cs call prot_call - popl %eax /* discard */ + popl %ecx /* discard */ + + /* Uninstall gPXE */ + call uninstall /* Reboot system */ int $0x19 diff --git a/gpxe/src/arch/i386/prefix/pxeprefix.S b/gpxe/src/arch/i386/prefix/pxeprefix.S index 302f8e5d..a5f0c711 100644 --- a/gpxe/src/arch/i386/prefix/pxeprefix.S +++ b/gpxe/src/arch/i386/prefix/pxeprefix.S @@ -2,7 +2,7 @@ #define PXENV_UNDI_GET_NIC_TYPE 0x0012 #define PXENV_STOP_UNDI 0x0015 #define PXENV_UNLOAD_STACK 0x0070 - + .text .arch i386 .org 0 @@ -12,36 +12,39 @@ #include +#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) ) + /***************************************************************************** * Entry point: set operating context, print welcome message ***************************************************************************** */ .section ".prefix" - /* Set up our non-stack segment registers */ jmp $0x7c0, $1f -1: pushfl - /* %ax here is the default return type... */ - movw $5, %ax /* Keep PXE+UNDI */ +1: + /* Preserve registers for possible return to PXE */ + pushfl pushal - pushw %ds - pushw %es - pushw %fs pushw %gs + pushw %fs + pushw %es + pushw %ds + + /* Store magic word on PXE stack and remember PXE %ss:esp */ + pushl $STACK_MAGIC + movw %ss, %cs:pxe_ss + movl %esp, %cs:pxe_esp + + /* Set up our non-stack segment registers */ movw %cs, %ax movw %ax, %ds - movw $0x40, %ax /* BIOS data segment access */ movw %ax, %fs - - pushw %fs:0x13 /* Record PXENV+ and !PXE nominal addresses */ - movw %es, pxenv_segment + movw %es, %ax /* PXENV+ address */ + movw %ax, pxenv_segment movw %bx, pxenv_offset - movw %sp, %bp - movw %ss, return_stack_segment - movl %esp, return_stack_offset - movl 50(%bp), %eax - movl %eax, ppxe_segoff /* !PXE address */ + popl %eax /* Discard return address */ + popl ppxe_segoff /* !PXE address */ /* Set up stack just below 0x7c00 */ xorw %ax, %ax movw %ax, %ss @@ -60,7 +63,7 @@ * Verify PXENV+ structure and record parameters of interest ***************************************************************************** */ -detect_pxenv: +ect_pxenv: /* Signature check */ les pxenv_segoff, %bx cmpl $0x4e455850, %es:(%bx) /* 'PXEN' signature */ @@ -264,7 +267,7 @@ no_physical_device: * Leave NIC in a safe state ***************************************************************************** */ -#ifndef PXELOADER_KEEP_UNDI +#ifndef PXELOADER_KEEP_PXE shutdown_nic: /* Issue PXENV_UNDI_SHUTDOWN */ movw $PXENV_UNDI_SHUTDOWN, %bx @@ -272,11 +275,6 @@ shutdown_nic: jnc 1f call print_pxe_error 1: - -/***************************************************************************** - * Unload PXE base code - ***************************************************************************** - */ unload_base_code: /* Issue PXENV_UNLOAD_STACK */ movw $PXENV_UNLOAD_STACK, %bx @@ -289,12 +287,14 @@ unload_base_code: movw %fs:(0x13), %bx call free_basemem 99: + andw $~( UNDI_FL_INITIALIZED | UNDI_FL_KEEP_ALL ), flags +#endif /* PXELOADER_KEEP_PXE */ /***************************************************************************** * Unload UNDI driver ***************************************************************************** */ - +#ifndef PXELOADER_KEEP_UNDI unload_undi: /* Issue PXENV_STOP_UNDI */ movw $PXENV_STOP_UNDI, %bx @@ -309,6 +309,7 @@ unload_undi: /* Clear UNDI_FL_STARTED */ andw $~UNDI_FL_STARTED, flags 99: +#endif /* PXELOADER_KEEP_UNDI */ /***************************************************************************** * Print remaining free base memory @@ -325,15 +326,14 @@ print_free_basemem: 10: .asciz " " 20: .asciz "kB free base memory after PXE unload\n" .previous -#endif /* PXELOADER_KEEP_UNDI */ /***************************************************************************** * Exit point ***************************************************************************** */ finished: - jmp run_etherboot - + jmp run_gpxe + /***************************************************************************** * Subroutine: print segment:offset address * @@ -527,6 +527,10 @@ print_pxe_error: * PXE data structures ***************************************************************************** */ + .section ".prefix.data" + +pxe_ss: .word 0 +pxe_esp: .long 0 pxe_parameter_structure: .fill 20 @@ -554,12 +558,6 @@ entry_segoff: entry_offset: .word 0 entry_segment: .word 0 -return_stack_segoff: -return_stack_offset: .long 0 -return_stack_segment: .word 0 - -return_type: .word 0 /* Default: unload PXE and boot next */ - undi_fbms_start: .word 0 undi_fbms_end: .word 0 @@ -569,16 +567,18 @@ isapnp_read_port: .word UNDI_NO_ISAPNP_READ_PORT pci_vendor: .word 0 pci_device: .word 0 -flags: .word UNDI_FL_STARTED +flags: + .word ( UNDI_FL_INITIALIZED | UNDI_FL_STARTED | UNDI_FL_KEEP_ALL ) .equ undi_device_size, ( . - undi_device ) /***************************************************************************** - * Run Etherboot main code + * Run gPXE main code ***************************************************************************** - */ -run_etherboot: - /* Install Etherboot */ + */ + .section ".prefix" +run_gpxe: + /* Install gPXE */ call install /* Set up real-mode stack */ @@ -594,6 +594,10 @@ run_etherboot: rep movsb #endif + /* Retrieve PXE %ss:esp */ + movw pxe_ss, %di + movl pxe_esp, %ebp + /* Jump to .text16 segment with %ds pointing to .data16 */ movw %bx, %ds pushw %ax @@ -605,29 +609,30 @@ run_etherboot: pushl $main pushw %cs call prot_call - popl %eax /* discard */ + popl %ecx /* discard */ -#ifdef PXELOADER_KEEP_UNDI - /* Boot next device */ - movw $0x40, %ax - movw %ax, %fs - movw $preloaded_undi,%bx - - cli - movw %ss:return_type-undi_device(%bx),%ax - lssl %ss:return_stack_segoff-undi_device(%bx), %esp - movw %sp,%bp - movw %ax,38(%bp) /* Overwrite return AX value */ - popw %fs:0x13 /* 0 */ - popw %gs /* 2 */ - popw %fs /* 4 */ - popw %es /* 6 */ - popw %ds /* 8 */ - popal /* 10, 14, 18, 22, 26, 30, 34, 38 */ - popfl /* 42 */ - lret /* 46 */ -#else - int $0x18 -#endif + /* Uninstall gPXE */ + call uninstall + + /* Restore PXE stack */ + movw %di, %ss + movl %ebp, %esp + /* Check PXE stack magic */ + popl %eax + cmpl $STACK_MAGIC, %eax + jne 1f + + /* PXE stack OK: return to caller */ + popw %ds + popw %es + popw %fs + popw %gs + popal + popfl + xorw %ax, %ax /* Return success */ + lret + +1: /* PXE stack corrupt or removed: use INT 18 */ + int $0x18 .previous diff --git a/gpxe/src/arch/i386/prefix/romprefix.S b/gpxe/src/arch/i386/prefix/romprefix.S index 92a931cd..a6431cd9 100644 --- a/gpxe/src/arch/i386/prefix/romprefix.S +++ b/gpxe/src/arch/i386/prefix/romprefix.S @@ -14,6 +14,7 @@ #define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) ) #define PNP_GET_BBS_VERSION 0x60 #define PMM_ALLOCATE 0x0000 +#define PMM_DEALLOCATE 0x0002 /* ROM banner timeout. Based on the configurable BANNER_TIMEOUT in * config.h, but converted to a number of (18Hz) timer ticks, and @@ -30,7 +31,7 @@ .org 0x00 romheader: .word 0xAA55 /* BIOS extension signature */ -romheader_size: .byte _load_size_sect /* Size in 512-byte blocks */ +romheader_size: .byte _filesz_sect /* Size in 512-byte blocks */ jmp init /* Initialisation vector */ checksum: .byte 0 @@ -42,7 +43,7 @@ checksum: .word pnpheader .size romheader, . - romheader - .section ".zinfo.fixup", "a" /* Compressor fixup information */ + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ .ascii "SUBB" .long romheader_size .long 512 @@ -58,18 +59,18 @@ pciheader: .byte 0x03 /* PCI data structure revision */ .byte 0x02, 0x00, 0x00 /* Class code */ pciheader_image_length: - .word _load_size_sect /* Image length */ + .word _filesz_sect /* Image length */ .word 0x0001 /* Revision level */ .byte 0x00 /* Code type */ .byte 0x80 /* Last image indicator */ pciheader_runtime_length: - .word _load_size_sect /* Maximum run-time image length */ + .word _filesz_sect /* Maximum run-time image length */ .word 0x0000 /* Configuration utility code header */ .word 0x0000 /* DMTF CLP entry point */ .equ pciheader_len, . - pciheader .size pciheader, . - pciheader - .section ".zinfo.fixup", "a" /* Compressor fixup information */ + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ .ascii "SUBW" .long pciheader_image_length .long 512 @@ -109,12 +110,12 @@ mfgstr: /* Product string * - * Defaults to "gPXE". If the ROM image is writable at initialisation - * time, it will be filled in to include the PCI bus:dev.fn number of - * the card as well. + * Defaults to PRODUCT_SHORT_NAME. If the ROM image is writable at + * initialisation time, it will be filled in to include the PCI + * bus:dev.fn number of the card as well. */ prodstr: - .ascii "gPXE" + .ascii PRODUCT_SHORT_NAME prodstr_separator: .byte 0 .ascii "(PCI " @@ -130,9 +131,9 @@ undiheader: .byte 0 /* Structure revision */ .byte 0,1,2 /* PXE version: 2.1.0 */ .word undiloader /* Offset to loader routine */ - .word _data16_size /* Stack segment size */ - .word _data16_size /* Data segment size */ - .word _text16_size /* Code segment size */ + .word _data16_memsz /* Stack segment size */ + .word _data16_memsz /* Data segment size */ + .word _text16_memsz /* Code segment size */ .ascii "PCIR" /* Bus type */ .equ undiheader_len, . - undiheader .size undiheader, . - undiheader @@ -190,11 +191,11 @@ init: stc movw $0xb101, %ax int $0x1a - jc 1f + jc no_pci3 cmpl $PCI_SIGNATURE, %edx - jne 1f + jne no_pci3 testb %ah, %ah - jnz 1f + jnz no_pci3 movw $init_message_pci, %si xorw %di, %di call print_message @@ -205,11 +206,33 @@ init: movb %bl, %al call print_hex_byte cmpb $3, %bh - jae 2f -1: /* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */ + jb no_pci3 + /* PCI >=3.0: leave %gs as-is if sane */ + movw %gs, %ax + cmpw $0xa000, %ax /* Insane if %gs < 0xa000 */ + jb pci3_insane + movw %cs, %bx /* Sane if %cs == %gs */ + cmpw %bx, %ax + je 1f + movzbw romheader_size, %cx /* Sane if %cs+len <= %gs */ + shlw $5, %cx + addw %cx, %bx + cmpw %bx, %ax + jae 1f + movw %cs, %bx /* Sane if %gs+len <= %cs */ + addw %cx, %ax + cmpw %bx, %ax + jbe 1f +pci3_insane: /* PCI 3.0 with insane %gs value: print error and ignore %gs */ + movb $'!', %al + call print_character + movw %gs, %ax + call print_hex_word +no_pci3: + /* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */ pushw %cs popw %gs -2: popl %edi +1: popl %edi popl %edx popl %ebx @@ -268,21 +291,52 @@ pmm_scan: movw $init_message_pmm, %si xorw %di, %di call print_message - /* Try to allocate 2MB block via PMM */ + /* We have PMM and so a 1kB stack: preserve upper register halves */ + pushal + /* Calculate required allocation size in %esi */ + movzbl romheader_size, %eax + shll $9, %eax + addl $_textdata_memsz, %eax + orw $0xffff, %ax /* Ensure allocation size is at least 64kB */ + bsrl %eax, %ecx + subw $15, %cx /* Round up and convert to 64kB count */ + movw $1, %si + shlw %cl, %si +pmm_loop: + /* Try to allocate block via PMM */ pushw $0x0006 /* Aligned, extended memory */ pushl $0xffffffff /* No handle */ - pushl $( 0x00200000 / 16 ) /* 2MB in paragraphs */ + movzwl %si, %eax + shll $12, %eax + pushl %eax /* Allocation size in paragraphs */ pushw $PMM_ALLOCATE lcall *%es:7 addw $12, %sp + /* Abort if allocation fails */ + testw %dx, %dx /* %ax==0 even on success, since align>=64kB */ + jz pmm_fail + /* If block has A20==1, free block and try again with twice + * the allocation size (and hence alignment). + */ + testw $0x0010, %dx + jz got_pmm + pushw %dx + pushw $0 + pushw $PMM_DEALLOCATE + lcall *%es:7 + addw $6, %sp + addw %si, %si + jmp pmm_loop +got_pmm: /* PMM allocation succeeded */ + movw %dx, ( image_source + 2 ) movw %dx, %ax xorw %di, %di call print_hex_word - movw %dx, ( image_source + 2 ) - testw %dx, %dx /* %ax==0 even on success, since align=2MB */ - jz no_pmm - /* PMM allocation succeeded: copy ROM to PMM block */ - pushal /* PMM presence implies 1kB stack */ + movb $'@', %al + call print_character + movw %si, %ax + call print_hex_byte + /* Copy ROM to PMM block */ xorw %ax, %ax movw %ax, %es movl image_source, %edi @@ -294,13 +348,15 @@ pmm_scan: /* Shrink ROM and update checksum */ xorw %bx, %bx xorw %si, %si - movw $_prefix_size_sect, %cx + movw $_prefix_memsz_sect, %cx movb %cl, romheader_size shlw $9, %cx 1: lodsb addb %al, %bl loop 1b subb %bl, checksum +pmm_fail: + /* Restore upper register halves */ popal no_pmm: @@ -324,23 +380,28 @@ no_pmm: movw $init_message_prompt, %si xorw %di, %di call print_message + movw $prodstr, %si + call print_message + movw $init_message_dots, %si + call print_message /* Wait for Ctrl-B */ movw $0xff02, %bx call wait_for_key /* Clear prompt */ pushf - movw $clear_message, %si xorw %di, %di + call print_kill_line + movw $init_message_done, %si call print_message popf - jnz 1f + jnz 2f /* Ctrl-B was pressed: invoke gPXE. The keypress will be * picked up by the initial shell prompt, and we will drop * into a shell. */ pushw %cs call exec -1: +2: /* Restore registers */ popw %gs popw %fs @@ -353,7 +414,26 @@ no_pmm: lret .size init, . - init +/* + * Note to hardware vendors: + * + * If you wish to brand this boot ROM, please do so by defining the + * strings PRODUCT_NAME and PRODUCT_SHORT_NAME in config/general.h. + * + * While nothing in the GPL prevents you from removing all references + * to gPXE or http://etherboot.org, we prefer you not to do so. + * + * If you have an OEM-mandated branding requirement that cannot be + * satisfied simply by defining PRODUCT_NAME and PRODUCT_SHORT_NAME, + * please contact us. + * + * [ Including an ASCII NUL in PRODUCT_NAME is considered to be + * bypassing the spirit of this request! ] + */ init_message: + .ascii "\n" + .ascii PRODUCT_NAME + .ascii "\n" .asciz "gPXE (http://etherboot.org) - " .size init_message, . - init_message init_message_pci: @@ -372,11 +452,14 @@ init_message_int19: .asciz " INT19" .size init_message_int19, . - init_message_int19 init_message_prompt: - .asciz "\nPress Ctrl-B to configure gPXE..." + .asciz "\nPress Ctrl-B to configure " .size init_message_prompt, . - init_message_prompt -clear_message: - .asciz "\r \n\n" - .size clear_message, . - clear_message +init_message_dots: + .asciz "..." + .size init_message_dots, . - init_message_dots +init_message_done: + .asciz "\n\n" + .size init_message_done, . - init_message_done /* ROM image location * @@ -432,8 +515,9 @@ int19_entry: movw $0xdf42, %bx call wait_for_key pushf - movw $clear_message, %si xorw %di, %di + call print_kill_line + movw $int19_message_done, %si call print_message popf jnz 1f @@ -460,6 +544,9 @@ int19_message_prompt: int19_message_dots: .asciz "..." .size int19_message_dots, . - int19_message_dots +int19_message_done: + .asciz "\n\n" + .size int19_message_done, . - int19_message_done /* Execute as a boot device * @@ -504,8 +591,11 @@ exec: /* Set %ds = %cs */ pushl $main pushw %cs call prot_call - /* No need to clean up stack; we are about to reload %ss:sp */ - + popl %ecx /* discard */ + + /* Uninstall gPXE */ + call uninstall + /* Restore BIOS stack */ movw %dx, %ss movw %bp, %sp diff --git a/gpxe/src/arch/i386/scripts/efi.lds b/gpxe/src/arch/i386/scripts/efi.lds new file mode 100644 index 00000000..b6255a68 --- /dev/null +++ b/gpxe/src/arch/i386/scripts/efi.lds @@ -0,0 +1,180 @@ +/* -*- sh -*- */ + +/* + * Linker script for EFI images + * + */ + +EXTERN ( efi_entry ) + +SECTIONS { + + /* The file starts at a virtual address of zero, and sections are + * contiguous. Each section is aligned to at least _max_align, + * which defaults to 32. Load addresses are equal to virtual + * addresses. + */ + + . = 0; + PROVIDE ( _max_align = 32 ); + + /* + * The prefix + * + */ + + .prefix : { + _prefix = .; + *(.prefix) + *(.prefix.*) + _mprefix = .; + } .bss.prefix (NOLOAD) : { + _eprefix = .; + } + _prefix_filesz = ABSOLUTE ( _mprefix - _prefix ); + _prefix_memsz = ABSOLUTE ( _eprefix - _prefix ); + + /* + * The text section + * + */ + + . = ALIGN ( _max_align ); + .text : { + _text = .; + *(.text) + *(.text.*) + _mtext = .; + } .bss.text (NOLOAD) : { + _etext = .; + } + _text_filesz = ABSOLUTE ( _mtext - _text ); + _text_memsz = ABSOLUTE ( _etext - _text ); + + /* + * The rodata section + * + */ + + . = ALIGN ( _max_align ); + .rodata : { + _rodata = .; + *(.rodata) + *(.rodata.*) + _mrodata = .; + } .bss.rodata (NOLOAD) : { + _erodata = .; + } + _rodata_filesz = ABSOLUTE ( _mrodata - _rodata ); + _rodata_memsz = ABSOLUTE ( _erodata - _rodata ); + + /* + * The data section + * + */ + + . = ALIGN ( _max_align ); + .data : { + _data = .; + *(.data) + *(.data.*) + *(SORT(.tbl.*)) /* Various tables. See include/tables.h */ + /* EFI seems to not support proper bss sections */ + *(.bss) + *(.bss.*) + *(COMMON) + *(.stack) + *(.stack.*) + _mdata = .; + } .bss.data (NOLOAD) : { + _edata = .; + } + _data_filesz = ABSOLUTE ( _mdata - _data ); + _data_memsz = ABSOLUTE ( _edata - _data ); + + /* + * The bss section + * + */ + + . = ALIGN ( _max_align ); + .bss : { + _bss = .; + /* EFI seems to not support proper bss sections */ + _mbss = .; + } .bss.bss (NOLOAD) : { + _ebss = .; + } + _bss_filesz = ABSOLUTE ( _mbss - _bss ); + _bss_memsz = ABSOLUTE ( _ebss - _bss ); + + /* + * The reloc section + * + */ + + . = ALIGN ( _max_align ); + .reloc : { + _reloc = .; + /* Provide some dummy contents to force ld to include this + * section. It will be created by the efilink utility. + */ + . += 1; + _mreloc = .; + } .bss.reloc (NOLOAD) : { + _ereloc = .; + } + _reloc_filesz = ABSOLUTE ( _mreloc - _reloc ); + _reloc_memsz = ABSOLUTE ( _ereloc - _reloc ); + + _filesz = ABSOLUTE ( . ); + + /* + * Weak symbols that need zero values if not otherwise defined + * + */ + + .weak 0x0 : { + _weak = .; + *(.weak) + _eweak = .; + } + _assert = ASSERT ( ( _weak == _eweak ), ".weak is non-zero length" ); + + /* + * Dispose of the comment and note sections to make the link map + * easier to read + * + */ + + /DISCARD/ : { + *(.comment) + *(.comment.*) + *(.note) + *(.note.*) + *(.eh_frame) + *(.eh_frame.*) + *(.rel) + *(.rel.*) + } + + /* + * Load address calculations. + * + */ + + _prefix_lma = ABSOLUTE ( _prefix ); + _text_lma = ABSOLUTE ( _text ); + _rodata_lma = ABSOLUTE ( _rodata ); + _data_lma = ABSOLUTE ( _data ); + _bss_lma = ABSOLUTE ( _bss ); + _reloc_lma = ABSOLUTE ( _reloc ); + + /* + * Load addresses required by the prefix + * + */ + efi_entry_lma = ABSOLUTE ( efi_entry ); + debugdir_lma = ABSOLUTE ( debugdir ); + codeview_rsds_lma = ABSOLUTE ( codeview_rsds ); +} diff --git a/gpxe/src/arch/i386/scripts/i386.lds b/gpxe/src/arch/i386/scripts/i386.lds index 729ad30a..8a0c6733 100644 --- a/gpxe/src/arch/i386/scripts/i386.lds +++ b/gpxe/src/arch/i386/scripts/i386.lds @@ -5,15 +5,9 @@ * */ -OUTPUT_FORMAT ( "elf32-i386", "elf32-i386", "elf32-i386" ) -OUTPUT_ARCH ( i386 ) -ENTRY ( _entry ) - SECTIONS { - /* All sections in the resulting file have consecutive load - * addresses, but may have individual link addresses depending on - * the memory model being used. + /* Each section starts at a virtual address of zero. * * We guarantee alignment of virtual addresses to any alignment * specified by the constituent object files (e.g. via @@ -30,255 +24,186 @@ SECTIONS { * */ - /* - * Weak symbols that need zero values if not otherwise defined - */ - - . = 0; - .weak : AT ( 0 ) { - *(.weak) - } - _assert = ASSERT ( ( . == 0 ), ".weak is non-zero length" ); - /* * The prefix + * */ - _prefix_link_addr = 0; - . = _prefix_link_addr; - _prefix = .; - - .prefix : AT ( _prefix_load_offset + __prefix ) { - __prefix = .; - _entry = .; + .prefix 0x0 : AT ( _prefix_lma ) { + _prefix = .; *(.prefix) *(.prefix.*) - _eprefix_progbits = .; + _mprefix = .; + } .bss.prefix (NOLOAD) : AT ( _end_lma ) { + _eprefix = .; } - - _eprefix = .; + _prefix_filesz = ABSOLUTE ( _mprefix - _prefix ); + _prefix_memsz = ABSOLUTE ( _eprefix - _prefix ); /* - * The 16-bit sections, if present + * The 16-bit (real-mode) code section + * */ - _text16_link_addr = 0; - . = _text16_link_addr; - _text16 = .; - - /* We need to allow code at the NULL address in .text16 */ - - .text16 : AT ( _text16_load_offset + __text16 ) { - __text16 = .; + .text16 0x0 : AT ( _text16_lma ) { + _text16 = .; *(.text16.null) - . += 1; /* Prevent NULL being valid */ + . += 1; /* Prevent NULL being valid */ *(.text16) *(.text16.*) - _etext16_progbits = .; - } = 0x9090 - - _etext16 = .; - - _data16_link_addr = 0; - . = _data16_link_addr; - _data16 = .; + _mtext16 = .; + } .bss.text16 (NOLOAD) : AT ( _end_lma ) { + _etext16 = .; + } + _text16_filesz = ABSOLUTE ( _mtext16 - _text16 ); + _text16_memsz = ABSOLUTE ( _etext16 - _text16 ); - . += 1; /* Prevent NULL being valid */ + /* + * The 16-bit (real-mode) data section + * + */ - .rodata16 : AT ( _data16_load_offset + __rodata16 ) { - __rodata16 = .; + .data16 0x0 : AT ( _data16_lma ) { + _data16 = .; + . += 1; /* Prevent NULL being valid */ *(.rodata16) *(.rodata16.*) - } - .data16 : AT ( _data16_load_offset + __data16 ) { - __data16 = .; *(.data16) *(.data16.*) - _edata16_progbits = .; - } - .bss16 : AT ( _data16_load_offset + __bss16 ) { - __bss16 = .; - _bss16 = .; + _mdata16 = .; + } .bss.data16 (NOLOAD) : AT ( _end_lma ) { *(.bss16) *(.bss16.*) - _ebss16 = .; - } - .stack16 : AT ( _data16_load_offset + __stack16 ) { - __stack16 = .; *(.stack16) *(.stack16.*) + _edata16 = .; } - - _edata16 = .; + _data16_filesz = ABSOLUTE ( _mdata16 - _data16 ); + _data16_memsz = ABSOLUTE ( _edata16 - _data16 ); /* * The 32-bit sections + * */ - _textdata_link_addr = 0; - . = _textdata_link_addr; - _textdata = .; - - _text = .; - - . += 1; /* Prevent NULL being valid */ - - .text : AT ( _textdata_load_offset + __text ) { - __text = .; + .textdata 0x0 : AT ( _textdata_lma ) { + _textdata = .; *(.text.null_trap) + . += 1; /* Prevent NULL being valid */ *(.text) *(.text.*) - } = 0x9090 - - _etext = .; - - _data = .; - - .rodata : AT ( _textdata_load_offset + __rodata ) { - __rodata = .; *(.rodata) *(.rodata.*) - } - .data : AT ( _textdata_load_offset + __data ) { - __data = .; *(.data) *(.data.*) *(SORT(.tbl.*)) /* Various tables. See include/tables.h */ - _etextdata_progbits = .; - } - .bss : AT ( _textdata_load_offset + __bss ) { - __bss = .; - _bss = .; + _mtextdata = .; + } .bss.textdata (NOLOAD) : AT ( _end_lma ) { *(.bss) *(.bss.*) *(COMMON) - _ebss = .; - } - .stack : AT ( _textdata_load_offset + __stack ) { - __stack = .; *(.stack) *(.stack.*) + _etextdata = .; } - - _edata = .; - - _etextdata = .; - - _end = .; + _textdata_filesz = ABSOLUTE ( _mtextdata - _textdata ); + _textdata_memsz = ABSOLUTE ( _etextdata - _textdata ); /* * Compressor information block + * */ - _zinfo_link_addr = 0; - . = _zinfo_link_addr; - _zinfo = .; - - .zinfo : AT ( _zinfo_load_offset + __zinfo ) { - __zinfo = .; - _entry = .; + .zinfo 0x0 : AT ( _zinfo_lma ) { + _zinfo = .; *(.zinfo) *(.zinfo.*) - _ezinfo_progbits = .; + _mzinfo = .; + } .bss.zinfo (NOLOAD) : AT ( _end_lma ) { + _ezinfo = .; } - - _ezinfo = .; + _zinfo_filesz = ABSOLUTE ( _mzinfo - _zinfo ); + _zinfo_memsz = ABSOLUTE ( _ezinfo - _zinfo ); + + /* + * Weak symbols that need zero values if not otherwise defined + * + */ + + .weak 0x0 : AT ( _end_lma ) { + _weak = .; + *(.weak) + _eweak = .; + } + _assert = ASSERT ( ( _weak == _eweak ), ".weak is non-zero length" ); /* * Dispose of the comment and note sections to make the link map * easier to read + * */ /DISCARD/ : { *(.comment) + *(.comment.*) *(.note) + *(.note.*) + *(.eh_frame) + *(.eh_frame.*) + *(.rel) + *(.rel.*) } /* - * Load address calculations. The slightly obscure nature of the - * calculations is because ALIGN(x) can only operate on the - * location counter. + * Load address calculations. In older versions of ld, ALIGN() + * can operate only on the location counter, so we use that. + * */ - _max_align = 16; - _load_addr = 0; - - . = _load_addr; - - . -= _prefix_link_addr; - _prefix_load_offset = ALIGN ( _max_align ); - _prefix_load_addr = _prefix_link_addr + _prefix_load_offset; - _prefix_size = _eprefix - _prefix; - _prefix_progbits_size = _eprefix_progbits - _prefix; - . = _prefix_load_addr + _prefix_progbits_size; - - . -= _text16_link_addr; - _text16_load_offset = ALIGN ( _max_align ); - _text16_load_addr = _text16_link_addr + _text16_load_offset; - _text16_size = _etext16 - _text16; - _text16_progbits_size = _etext16_progbits - _text16; - . = _text16_load_addr + _text16_progbits_size; + PROVIDE ( _max_align = 16 ); + . = 0; - . -= _data16_link_addr; - _data16_load_offset = ALIGN ( _max_align ); - _data16_load_addr = _data16_link_addr + _data16_load_offset; - _data16_size = _edata16 - _data16; - _data16_progbits_size = _edata16_progbits - _data16; - . = _data16_load_addr + _data16_progbits_size; + . = ALIGN ( _max_align ); + _prefix_lma = .; + . += _prefix_filesz; - . -= _textdata_link_addr; - _textdata_load_offset = ALIGN ( _max_align ); - _textdata_load_addr = _textdata_link_addr + _textdata_load_offset; - _textdata_size = _etextdata - _textdata; - _textdata_progbits_size = _etextdata_progbits - _textdata; - . = _textdata_load_addr + _textdata_progbits_size; + . = ALIGN ( _max_align ); + _payload_lma = .; + _text16_lma = .; + . += _text16_filesz; - _load_size = . - _load_addr; + . = ALIGN ( _max_align ); + _data16_lma = .; + . += _data16_filesz; - . -= _zinfo_link_addr; - _zinfo_load_offset = ALIGN ( _max_align ); - _zinfo_load_addr = _zinfo_link_addr + _zinfo_load_offset; - _zinfo_size = _ezinfo - _zinfo; - _zinfo_progbits_size = _ezinfo_progbits - _zinfo; - . = _zinfo_load_addr + _zinfo_progbits_size; + . = ALIGN ( _max_align ); + _textdata_lma = .; + . += _textdata_filesz; - _payload_offset = _text16_load_offset; + _filesz = .; /* Do not include zinfo block in file size */ - /* - * Alignment checks. ALIGN() can only operate on the location - * counter, so we set the location counter to each value we want - * to check. - */ - - . = _prefix_load_addr - _prefix_link_addr; - _assert = ASSERT ( ( . == ALIGN ( _max_align ) ), - "_prefix is badly aligned" ); - - . = _text16_load_addr - _text16_link_addr; - _assert = ASSERT ( ( . == ALIGN ( _max_align ) ), - "_text16 is badly aligned" ); + . = ALIGN ( _max_align ); + _zinfo_lma = .; + . += _zinfo_filesz; - . = _data16_load_addr - _data16_link_addr; - _assert = ASSERT ( ( . == ALIGN ( _max_align ) ), - "_data16 is badly aligned" ); - - . = _textdata_load_addr - _textdata_link_addr; - _assert = ASSERT ( ( . == ALIGN ( _max_align ) ), - "_text is badly aligned" ); + . = ALIGN ( _max_align ); + _end_lma = .; /* * Values calculated to save code from doing it + * */ - _prefix_size_pgh = ( ( _prefix_size + 15 ) / 16 ); - _prefix_size_sect = ( ( _prefix_size + 511 ) / 512 ); - _text16_size_pgh = ( ( _text16_size + 15 ) / 16 ); - _data16_size_pgh = ( ( _data16_size + 15 ) / 16 ); + _prefix_memsz_pgh = ( ( _prefix_memsz + 15 ) / 16 ); + _prefix_memsz_sect = ( ( _prefix_memsz + 511 ) / 512 ); + _text16_memsz_pgh = ( ( _text16_memsz + 15 ) / 16 ); + _data16_memsz_pgh = ( ( _data16_memsz + 15 ) / 16 ); /* - * Load sizes in paragraphs and sectors. Note that wherever the - * _load_size variables are used, there must be a corresponding + * File size in paragraphs and sectors. Note that wherever the + * _filesz variables are used, there must be a corresponding * .zinfo.fixup section. + * */ - _load_size_pgh = ( ( _load_size + 15 ) / 16 ); - _load_size_sect = ( ( _load_size + 511 ) / 512 ); + _filesz_pgh = ( ( _filesz + 15 ) / 16 ); + _filesz_sect = ( ( _filesz + 511 ) / 512 ); } diff --git a/gpxe/src/arch/i386/transitions/librm.S b/gpxe/src/arch/i386/transitions/librm.S old mode 100644 new mode 100755 index ff4b1d97..7e9fd45d --- a/gpxe/src/arch/i386/transitions/librm.S +++ b/gpxe/src/arch/i386/transitions/librm.S @@ -203,8 +203,8 @@ real_to_prot: /* Switch to protected mode */ cli - data32 lgdt gdtr - data32 lidt idtr + data32 lgdt gdtr + data32 lidt idtr movl %cr0, %eax orb $CR0_PE, %al movl %eax, %cr0 @@ -316,7 +316,7 @@ p2r_jump_target: movl %edx, %esp /* Reset IDTR to the real-mode defaults */ - lidt rm_idtr + data32 lidt rm_idtr /* Return to real-mode address */ data32 ret @@ -424,8 +424,8 @@ prot_call: 1: /* Reload GDT and IDT, restore registers and flags and return */ movw %sp, %bp - lgdt (%bp) - lidt 8(%bp) + data32 lgdt (%bp) + data32 lidt 8(%bp) addw $20, %sp /* also skip %cs and %ss */ popw %ds popw %es diff --git a/gpxe/src/arch/i386/transitions/librm_mgmt.c b/gpxe/src/arch/i386/transitions/librm_mgmt.c old mode 100644 new mode 100755 index 59b2eabc..50569f8e --- a/gpxe/src/arch/i386/transitions/librm_mgmt.c +++ b/gpxe/src/arch/i386/transitions/librm_mgmt.c @@ -1,45 +1,56 @@ -/* - * librm: a library for interfacing to real-mode code - * - * Michael Brown - * - */ - -#include -#include - -/* - * This file provides functions for managing librm. - * - */ - -/** - * Allocate space on the real-mode stack and copy data there from a - * user buffer - * - * @v data User buffer - * @v size Size of stack data - * @ret sp New value of real-mode stack pointer - */ -uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) { - userptr_t rm_stack; - rm_sp -= size; - rm_stack = real_to_user ( rm_ss, rm_sp ); - memcpy_user ( rm_stack, 0, data, 0, size ); - return rm_sp; -}; - -/** - * Deallocate space on the real-mode stack, optionally copying back - * data to a user buffer. - * - * @v data User buffer - * @v size Size of stack data - */ -void remove_user_from_rm_stack ( userptr_t data, size_t size ) { - if ( data ) { - userptr_t rm_stack = real_to_user ( rm_ss, rm_sp ); - memcpy_user ( rm_stack, 0, data, 0, size ); - } - rm_sp += size; -}; +/* + * librm: a library for interfacing to real-mode code + * + * Michael Brown + * + */ + +#include +#include + +/* + * This file provides functions for managing librm. + * + */ + +/** + * Allocate space on the real-mode stack and copy data there from a + * user buffer + * + * @v data User buffer + * @v size Size of stack data + * @ret sp New value of real-mode stack pointer + */ +uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) { + userptr_t rm_stack; + rm_sp -= size; + rm_stack = real_to_user ( rm_ss, rm_sp ); + memcpy_user ( rm_stack, 0, data, 0, size ); + return rm_sp; +}; + +/** + * Deallocate space on the real-mode stack, optionally copying back + * data to a user buffer. + * + * @v data User buffer + * @v size Size of stack data + */ +void remove_user_from_rm_stack ( userptr_t data, size_t size ) { + if ( data ) { + userptr_t rm_stack = real_to_user ( rm_ss, rm_sp ); + memcpy_user ( rm_stack, 0, data, 0, size ); + } + rm_sp += size; +}; + +PROVIDE_UACCESS_INLINE ( librm, phys_to_user ); +PROVIDE_UACCESS_INLINE ( librm, user_to_phys ); +PROVIDE_UACCESS_INLINE ( librm, virt_to_user ); +PROVIDE_UACCESS_INLINE ( librm, user_to_virt ); +PROVIDE_UACCESS_INLINE ( librm, userptr_add ); +PROVIDE_UACCESS_INLINE ( librm, memcpy_user ); +PROVIDE_UACCESS_INLINE ( librm, memmove_user ); +PROVIDE_UACCESS_INLINE ( librm, memset_user ); +PROVIDE_UACCESS_INLINE ( librm, strlen_user ); +PROVIDE_UACCESS_INLINE ( librm, memchr_user ); diff --git a/gpxe/src/config.h b/gpxe/src/config.h deleted file mode 100644 index 603604ab..00000000 --- a/gpxe/src/config.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * This file defines the configuration for Etherboot. - * - * The build system splits this file into several individual header - * files of the form config/%.h, so that changing one option doesn't - * necessitate a rebuild of every single object. For this reason, it - * is important to maintain the strict formatting in this file. - * - */ - -/* @BEGIN general.h - * - * Console configuration - * - * These options specify the console types that Etherboot will use for - * interaction with the user. - * - */ - -#define CONSOLE_FIRMWARE /* Default BIOS console */ -#undef CONSOLE_SERIAL /* Serial port */ -#undef CONSOLE_DIRECT_VGA /* Direct access to VGA card */ -#undef CONSOLE_BTEXT /* Who knows what this does? */ -#undef CONSOLE_PC_KBD /* Direct access to PC keyboard */ - -/* @END general.h */ - -/* @BEGIN serial.h - * - * Serial port configuration - * - * These options affect the operation of the serial console. They - * take effect only if the serial console is included using the - * CONSOLE_SERIAL option. - * - */ - -#define COMCONSOLE 0x3f8 /* I/O port address */ - -/* Keep settings from a previous user of the serial port (e.g. lilo or - * LinuxBIOS), ignoring COMSPEED, COMDATA, COMPARITY and COMSTOP. - */ -#undef COMPRESERVE - -#ifndef COMPRESERVE -#define COMSPEED 115200 /* Baud rate */ -#define COMDATA 8 /* Data bits */ -#define COMPARITY 0 /* Parity: 0=None, 1=Odd, 2=Even */ -#define COMSTOP 1 /* Stop bits */ -#endif - -/* @END serial.h */ - -/* @BEGIN general.h - * - * Timer configuration - * - */ -#define TIMER_BIOS /* 18Hz BIOS timer */ -#define TIMER_RDTSC /* CPU TimeStamp Counter timer */ -#define BANNER_TIMEOUT 20 /* Tenths of a second for which the shell - banner should appear */ - -/* @END general.h */ - -/* @BEGIN isa.h - * - * ISA probe address configuration - * - * You can override the list of addresses that will be probed by any - * ISA drivers. - * - */ -#undef ISA_PROBE_ADDRS /* e.g. 0x200, 0x300 */ -#undef ISA_PROBE_ONLY /* Do not probe any other addresses */ - -/* @END isa.h */ - -/* @BEGIN general.h - * - * Network protocols - * - */ - -#define NET_PROTO_IPV4 /* IPv4 protocol */ - -/* @END general.h */ - -/* @BEGIN general.h - * - * Download protocols - * - */ - -#define DOWNLOAD_PROTO_TFTP /* Trivial File Transfer Protocol */ -#define DOWNLOAD_PROTO_NFS /* Network File System */ -#define DOWNLOAD_PROTO_HTTP /* Hypertext Transfer Protocol */ -#define DOWNLOAD_PROTO_HTTPS /* Secure Hypertext Transfer Protocol */ -#define DOWNLOAD_PROTO_FTP /* File Transfer Protocol */ -#undef DOWNLOAD_PROTO_TFTM /* Multicast Trivial File Transfer Protocol */ -#undef DOWNLOAD_PROTO_SLAM /* Scalable Local Area Multicast */ -#undef DOWNLOAD_PROTO_FSP /* FSP? */ - -/* @END general.h */ - -/* @BEGIN general.h - * - * Name resolution modules - * - */ - -#define DNS_RESOLVER /* DNS resolver */ -#undef NMB_RESOLVER /* NMB resolver */ - -/* @END general.h */ - -/* @BEGIN general.h - * - * Image types - * - * Etherboot supports various image formats. Select whichever ones - * you want to use. - * - */ -#undef IMAGE_NBI /* NBI image support */ -#define IMAGE_ELF /* ELF image support */ -#undef IMAGE_FREEBSD /* FreeBSD kernel image support */ -#define IMAGE_MULTIBOOT /* MultiBoot image support */ -#undef IMAGE_AOUT /* a.out image support */ -#undef IMAGE_WINCE /* WinCE image support */ -#define IMAGE_PXE /* PXE image support */ -#define IMAGE_SCRIPT /* gPXE script image support */ -#define IMAGE_BZIMAGE /* Linux bzImage image support */ -#define IMAGE_COMBOOT /* SYSLINUX COMBOOT image support */ - -/* @END general.h */ - -/* @BEGIN general.h - * - * Command-line commands to include - * - */ -#define AUTOBOOT_CMD /* Automatic booting */ -#define NVO_CMD /* Non-volatile option storage commands */ -#define CONFIG_CMD /* Option configuration console */ -#define IFMGMT_CMD /* Interface management commands */ -#define ROUTE_CMD /* Routing table management commands */ -#define IMAGE_CMD /* Image management commands */ -#define DHCP_CMD /* DHCP management commands */ -#define SANBOOT_CMD /* SAN boot commands */ - -/* @END general.h */ - -/* @BEGIN general.h - * - * Obscure configuration options - * - * You probably don't need to touch these. - * - */ - -#undef BUILD_SERIAL /* Include an automatic build serial - * number. Add "bs" to the list of - * make targets. For example: - * "make bin/rtl8139.dsk bs" */ -#undef BUILD_ID /* Include a custom build ID string, - * e.g "test-foo" */ -#undef NULL_TRAP /* Attempt to catch NULL function calls */ -#undef GDBSERIAL /* Remote GDB debugging over serial */ -#undef GDBUDP /* Remote GDB debugging over UDP - * (both may be set) */ - -/* @END general.h */ - -/* @TRYSOURCE config-local.h */ diff --git a/gpxe/src/config/.gitignore b/gpxe/src/config/.gitignore index 499ae122..8e94f32f 100644 --- a/gpxe/src/config/.gitignore +++ b/gpxe/src/config/.gitignore @@ -1,2 +1 @@ -*.h .buildserial.* diff --git a/gpxe/src/config/console.h b/gpxe/src/config/console.h new file mode 100644 index 00000000..b4ea1dda --- /dev/null +++ b/gpxe/src/config/console.h @@ -0,0 +1,21 @@ +#ifndef CONFIG_CONSOLE_H +#define CONFIG_CONSOLE_H + +/** @file + * + * Console configuration + * + * These options specify the console types that Etherboot will use for + * interaction with the user. + * + */ + +#include + +//#define CONSOLE_PCBIOS /* Default BIOS console */ +//#define CONSOLE_SERIAL /* Serial port */ +//#define CONSOLE_DIRECT_VGA /* Direct access to VGA card */ +//#define CONSOLE_BTEXT /* Who knows what this does? */ +//#define CONSOLE_PC_KBD /* Direct access to PC keyboard */ + +#endif /* CONFIG_CONSOLE_H */ diff --git a/gpxe/src/config/defaults.h b/gpxe/src/config/defaults.h new file mode 100644 index 00000000..1f55ef3c --- /dev/null +++ b/gpxe/src/config/defaults.h @@ -0,0 +1,8 @@ +#ifndef CONFIG_DEFAULTS_H +#define CONFIG_DEFAULTS_H + +#define CONFIG_DEFAULTS(_platform) + +#include CONFIG_DEFAULTS(PLATFORM) + +#endif /* CONFIG_DEFAULTS_H */ diff --git a/gpxe/src/config/defaults/efi.h b/gpxe/src/config/defaults/efi.h new file mode 100644 index 00000000..d980136a --- /dev/null +++ b/gpxe/src/config/defaults/efi.h @@ -0,0 +1,20 @@ +#ifndef CONFIG_DEFAULTS_EFI_H +#define CONFIG_DEFAULTS_EFI_H + +/** @file + * + * Configuration defaults for EFI + * + */ + +#define UACCESS_EFI +#define IOAPI_EFI +#define PCIAPI_EFI +#define CONSOLE_EFI +#define TIMER_EFI +#define NAP_EFIX86 +#define UMALLOC_EFI + +#define IMAGE_EFI /* EFI image support */ + +#endif /* CONFIG_DEFAULTS_EFI_H */ diff --git a/gpxe/src/config/defaults/pcbios.h b/gpxe/src/config/defaults/pcbios.h new file mode 100644 index 00000000..e1360f53 --- /dev/null +++ b/gpxe/src/config/defaults/pcbios.h @@ -0,0 +1,28 @@ +#ifndef CONFIG_DEFAULTS_PCBIOS_H +#define CONFIG_DEFAULTS_PCBIOS_H + +/** @file + * + * Configuration defaults for PCBIOS + * + */ + +#define UACCESS_LIBRM +#define IOAPI_X86 +#define PCIAPI_PCBIOS +#define TIMER_PCBIOS +#define CONSOLE_PCBIOS +#define NAP_PCBIOS +#define UMALLOC_MEMTOP + +#define IMAGE_ELF /* ELF image support */ +#define IMAGE_MULTIBOOT /* MultiBoot image support */ +#define IMAGE_PXE /* PXE image support */ +#define IMAGE_SCRIPT /* gPXE script image support */ +#define IMAGE_BZIMAGE /* Linux bzImage image support */ +#define IMAGE_COMBOOT /* SYSLINUX COMBOOT image support */ + +#define SANBOOT_PROTO_ISCSI /* iSCSI protocol */ +#define SANBOOT_PROTO_AOE /* AoE protocol */ + +#endif /* CONFIG_DEFAULTS_PCBIOS_H */ diff --git a/gpxe/src/config/general.h b/gpxe/src/config/general.h new file mode 100644 index 00000000..6454b946 --- /dev/null +++ b/gpxe/src/config/general.h @@ -0,0 +1,122 @@ +#ifndef CONFIG_GENERAL_H +#define CONFIG_GENERAL_H + +/** @file + * + * General configuration + * + */ + +#include + +/* + * Branding + * + * Vendors may use these strings to add their own branding to gPXE. + * PRODUCT_NAME is displayed prior to any gPXE branding in startup + * messages, and PRODUCT_SHORT_NAME is used where a brief product + * label is required (e.g. in BIOS boot selection menus). + * + * To minimise end-user confusion, it's probably a good idea to either + * make PRODUCT_SHORT_NAME a substring of PRODUCT_NAME or leave it as + * "gPXE". + * + */ +#define PRODUCT_NAME "" +#define PRODUCT_SHORT_NAME "gPXE" + +/* + * Timer configuration + * + */ +#define BANNER_TIMEOUT 20 /* Tenths of a second for which the shell + banner should appear */ + +/* + * Network protocols + * + */ + +#define NET_PROTO_IPV4 /* IPv4 protocol */ + +/* + * Download protocols + * + */ + +#define DOWNLOAD_PROTO_TFTP /* Trivial File Transfer Protocol */ +#undef DOWNLOAD_PROTO_NFS /* Network File System */ +#define DOWNLOAD_PROTO_HTTP /* Hypertext Transfer Protocol */ +#undef DOWNLOAD_PROTO_HTTPS /* Secure Hypertext Transfer Protocol */ +#undef DOWNLOAD_PROTO_FTP /* File Transfer Protocol */ +#undef DOWNLOAD_PROTO_TFTM /* Multicast Trivial File Transfer Protocol */ +#undef DOWNLOAD_PROTO_SLAM /* Scalable Local Area Multicast */ +#undef DOWNLOAD_PROTO_FSP /* FSP? */ + +/* + * SAN boot protocols + * + */ + +//#undef SANBOOT_PROTO_ISCSI /* iSCSI protocol */ +//#undef SANBOOT_PROTO_AOE /* AoE protocol */ + +/* + * Name resolution modules + * + */ + +#define DNS_RESOLVER /* DNS resolver */ +#undef NMB_RESOLVER /* NMB resolver */ + +/* + * Image types + * + * Etherboot supports various image formats. Select whichever ones + * you want to use. + * + */ +//#define IMAGE_NBI /* NBI image support */ +//#define IMAGE_ELF /* ELF image support */ +//#define IMAGE_FREEBSD /* FreeBSD kernel image support */ +//#define IMAGE_MULTIBOOT /* MultiBoot image support */ +//#define IMAGE_AOUT /* a.out image support */ +//#define IMAGE_WINCE /* WinCE image support */ +//#define IMAGE_PXE /* PXE image support */ +//#define IMAGE_SCRIPT /* gPXE script image support */ +//#define IMAGE_BZIMAGE /* Linux bzImage image support */ +//#define IMAGE_COMBOOT /* SYSLINUX COMBOOT image support */ +//#define IMAGE_EFI /* EFI image support */ + +/* + * Command-line commands to include + * + */ +#define AUTOBOOT_CMD /* Automatic booting */ +#define NVO_CMD /* Non-volatile option storage commands */ +#define CONFIG_CMD /* Option configuration console */ +#define IFMGMT_CMD /* Interface management commands */ +#define ROUTE_CMD /* Routing table management commands */ +#define IMAGE_CMD /* Image management commands */ +#define DHCP_CMD /* DHCP management commands */ +#define SANBOOT_CMD /* SAN boot commands */ + +/* + * Obscure configuration options + * + * You probably don't need to touch these. + * + */ + +#undef BUILD_SERIAL /* Include an automatic build serial + * number. Add "bs" to the list of + * make targets. For example: + * "make bin/rtl8139.dsk bs" */ +#undef BUILD_ID /* Include a custom build ID string, + * e.g "test-foo" */ +#undef NULL_TRAP /* Attempt to catch NULL function calls */ +#undef GDBSERIAL /* Remote GDB debugging over serial */ +#undef GDBUDP /* Remote GDB debugging over UDP + * (both may be set) */ + +#endif /* CONFIG_GENERAL_H */ diff --git a/gpxe/src/config/ioapi.h b/gpxe/src/config/ioapi.h new file mode 100644 index 00000000..7726a0f0 --- /dev/null +++ b/gpxe/src/config/ioapi.h @@ -0,0 +1,15 @@ +#ifndef CONFIG_IOAPI_H +#define CONFIG_IOAPI_H + +/** @file + * + * I/O API configuration + * + */ + +#include + +//#undef PCIAPI_PCBIOS /* Access via PCI BIOS */ +//#define PCIAPI_DIRECT /* Direct access via Type 1 accesses */ + +#endif /* CONFIG_IOAPI_H */ diff --git a/gpxe/src/config/isa.h b/gpxe/src/config/isa.h new file mode 100644 index 00000000..523be1c0 --- /dev/null +++ b/gpxe/src/config/isa.h @@ -0,0 +1,15 @@ +#ifndef CONFIG_ISA_H +#define CONFIG_ISA_H + +/** @file + * + * ISA probe address configuration + * + * You can override the list of addresses that will be probed by any + * ISA drivers. + * + */ +#undef ISA_PROBE_ADDRS /* e.g. 0x200, 0x300 */ +#undef ISA_PROBE_ONLY /* Do not probe any other addresses */ + +#endif /* CONFIG_ISA_H */ diff --git a/gpxe/src/config/nap.h b/gpxe/src/config/nap.h new file mode 100644 index 00000000..8648d925 --- /dev/null +++ b/gpxe/src/config/nap.h @@ -0,0 +1,15 @@ +#ifndef CONFIG_NAP_H +#define CONFIG_NAP_H + +/** @file + * + * CPU sleeping + * + */ + +#include + +//#undef NAP_PCBIOS +//#define NAP_NULL + +#endif /* CONFIG_NAP_H */ diff --git a/gpxe/src/config/serial.h b/gpxe/src/config/serial.h new file mode 100644 index 00000000..984a7a9c --- /dev/null +++ b/gpxe/src/config/serial.h @@ -0,0 +1,28 @@ +#ifndef CONFIG_SERIAL_H +#define CONFIG_SERIAL_H + +/** @file + * + * Serial port configuration + * + * These options affect the operation of the serial console. They + * take effect only if the serial console is included using the + * CONSOLE_SERIAL option. + * + */ + +#define COMCONSOLE 0x3f8 /* I/O port address */ + +/* Keep settings from a previous user of the serial port (e.g. lilo or + * LinuxBIOS), ignoring COMSPEED, COMDATA, COMPARITY and COMSTOP. + */ +#undef COMPRESERVE + +#ifndef COMPRESERVE +#define COMSPEED 115200 /* Baud rate */ +#define COMDATA 8 /* Data bits */ +#define COMPARITY 0 /* Parity: 0=None, 1=Odd, 2=Even */ +#define COMSTOP 1 /* Stop bits */ +#endif + +#endif /* CONFIG_SERIAL_H */ diff --git a/gpxe/src/config/timer.h b/gpxe/src/config/timer.h new file mode 100644 index 00000000..7c3f3521 --- /dev/null +++ b/gpxe/src/config/timer.h @@ -0,0 +1,15 @@ +#ifndef CONFIG_TIMER_H +#define CONFIG_TIMER_H + +/** @file + * + * Timer configuration. + * + */ + +#include + +//#undef TIMER_PCBIOS +//#define TIMER_RDTSC + +#endif /* CONFIG_TIMER_H */ diff --git a/gpxe/src/config/umalloc.h b/gpxe/src/config/umalloc.h new file mode 100644 index 00000000..de4019e5 --- /dev/null +++ b/gpxe/src/config/umalloc.h @@ -0,0 +1,12 @@ +#ifndef CONFIG_UMALLOC_H +#define CONFIG_UMALLOC_H + +/** @file + * + * User memory allocation API configuration + * + */ + +#include + +#endif /* CONFIG_UMALLOC_H */ diff --git a/gpxe/src/core/config.c b/gpxe/src/core/config.c index b5624fae..b14d25a8 100644 --- a/gpxe/src/core/config.c +++ b/gpxe/src/core/config.c @@ -5,7 +5,8 @@ * your option) any later version. */ -#include "config/general.h" +#include +#include /* * Build ID string calculations @@ -38,19 +39,9 @@ /* * Drag in all requested console types * - * CONSOLE_DUAL sets both CONSOLE_FIRMWARE and CONSOLE_SERIAL for - * legacy compatibility. - * */ -#ifdef CONSOLE_DUAL -#undef CONSOLE_FIRMWARE -#define CONSOLE_FIRMWARE 1 -#undef CONSOLE_SERIAL -#define CONSOLE_SERIAL 1 -#endif - -#ifdef CONSOLE_FIRMWARE +#ifdef CONSOLE_PCBIOS REQUIRE_OBJECT ( bios_console ); #endif #ifdef CONSOLE_SERIAL @@ -68,15 +59,8 @@ REQUIRE_OBJECT ( pc_kbd ); #ifdef CONSOLE_SYSLOG REQUIRE_OBJECT ( syslog ); #endif - -/* - * Drag in all requested timers - */ -#ifdef TIMER_BIOS -REQUIRE_OBJECT ( timer_bios ); -#endif -#ifdef TIMER_RDTSC -REQUIRE_OBJECT ( timer_rdtsc ); +#ifdef CONSOLE_EFI +REQUIRE_OBJECT ( efi_console ); #endif /* @@ -113,6 +97,17 @@ REQUIRE_OBJECT ( tftm ); REQUIRE_OBJECT ( slam ); #endif +/* + * Drag in all requested SAN boot protocols + * + */ +#ifdef SANBOOT_PROTO_ISCSI +REQUIRE_OBJECT ( iscsiboot ); +#endif +#ifdef SANBOOT_PROTO_AOE +REQUIRE_OBJECT ( aoeboot ); +#endif + /* * Drag in all requested resolvers * @@ -166,6 +161,9 @@ REQUIRE_OBJECT ( com32_call ); REQUIRE_OBJECT ( com32_wrapper ); REQUIRE_OBJECT ( comboot_resolv ); #endif +#ifdef IMAGE_EFI +REQUIRE_OBJECT ( efi_image ); +#endif /* * Drag in all requested commands diff --git a/gpxe/src/core/console.c b/gpxe/src/core/console.c index 653f689d..c9773f71 100644 --- a/gpxe/src/core/console.c +++ b/gpxe/src/core/console.c @@ -1,11 +1,10 @@ #include "stddef.h" #include "console.h" #include +#include /** @file */ -#include "bios.h" - static struct console_driver console_drivers[0] __table_start ( struct console_driver, console ); static struct console_driver console_drivers_end[0] @@ -82,9 +81,6 @@ static struct console_driver * has_input ( void ) { * * The character read will not be echoed back to any console. * - * @bug We need a cleaner way to pick up cpu_nap(). It makes a - * real-mode call, and so we don't want to use it with LinuxBIOS. - * */ int getchar ( void ) { struct console_driver *console; diff --git a/gpxe/src/core/debug.c b/gpxe/src/core/debug.c index 09830420..3079cd4c 100644 --- a/gpxe/src/core/debug.c +++ b/gpxe/src/core/debug.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include void pause ( void ) { diff --git a/gpxe/src/core/gdbudp.c b/gpxe/src/core/gdbudp.c index c49a1bca..26feb38a 100644 --- a/gpxe/src/core/gdbudp.c +++ b/gpxe/src/core/gdbudp.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -27,6 +26,7 @@ #include #include #include +#include #include #include diff --git a/gpxe/src/core/main.c b/gpxe/src/core/main.c index d5892261..aaf8111b 100644 --- a/gpxe/src/core/main.c +++ b/gpxe/src/core/main.c @@ -20,6 +20,7 @@ Literature dealing with the network protocols: #include #include #include +#include #define NORMAL "\033[0m" #define BOLD "\033[1m" @@ -39,8 +40,19 @@ __cdecl int main ( void ) { initialise(); startup(); - /* Print welcome banner */ - printf ( NORMAL "\n\n\n" BOLD "gPXE " VERSION + /* + * Print welcome banner + * + * + * If you wish to brand this build of gPXE, please do so by + * defining the string PRODUCT_NAME in config/general.h. + * + * While nothing in the GPL prevents you from removing all + * references to gPXE or http://etherboot.org, we prefer you + * not to do so. + * + */ + printf ( NORMAL "\n\n" PRODUCT_NAME "\n" BOLD "gPXE " VERSION NORMAL " -- Open Source Boot Firmware -- " CYAN "http://etherboot.org" NORMAL "\n" "Features:" ); diff --git a/gpxe/src/core/malloc.c b/gpxe/src/core/malloc.c index 2d892f42..db7f1bed 100644 --- a/gpxe/src/core/malloc.c +++ b/gpxe/src/core/malloc.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/gpxe/src/core/monojob.c b/gpxe/src/core/monojob.c index 2c91e132..657bfd7a 100644 --- a/gpxe/src/core/monojob.c +++ b/gpxe/src/core/monojob.c @@ -63,7 +63,8 @@ struct job_interface monojob = { int monojob_wait ( const char *string ) { int key; int rc; - tick_t last_progress_dot; + unsigned long last_progress_dot; + unsigned long elapsed; printf ( "%s.", string ); monojob_rc = -EINPROGRESS; @@ -81,7 +82,8 @@ int monojob_wait ( const char *string ) { break; } } - if ( ( currticks() - last_progress_dot ) > TICKS_PER_SEC ) { + elapsed = ( currticks() - last_progress_dot ); + if ( elapsed >= TICKS_PER_SEC ) { printf ( "." ); last_progress_dot = currticks(); } @@ -89,6 +91,7 @@ int monojob_wait ( const char *string ) { rc = monojob_rc; done: + job_done ( &monojob, rc ); if ( rc ) { printf ( " %s\n", strerror ( rc ) ); } else { diff --git a/gpxe/src/core/null_nap.c b/gpxe/src/core/null_nap.c new file mode 100644 index 00000000..a3b01eb1 --- /dev/null +++ b/gpxe/src/core/null_nap.c @@ -0,0 +1,3 @@ +#include + +PROVIDE_NAP_INLINE ( null, cpu_nap ); diff --git a/gpxe/src/core/nvo.c b/gpxe/src/core/nvo.c index 13078022..e5c07d98 100644 --- a/gpxe/src/core/nvo.c +++ b/gpxe/src/core/nvo.c @@ -203,7 +203,7 @@ void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs, nvo->nvs = nvs; nvo->fragments = fragments; settings_init ( &nvo->settings, &nvo_settings_operations, refcnt, - "nvo" ); + "nvo", 0 ); } /** diff --git a/gpxe/src/core/pc_kbd.c b/gpxe/src/core/pc_kbd.c index d43357fe..799c8beb 100644 --- a/gpxe/src/core/pc_kbd.c +++ b/gpxe/src/core/pc_kbd.c @@ -10,7 +10,7 @@ * yhlu@tyan.com */ -#include "io.h" +#include #include "console.h" static char key_map[][128] = { diff --git a/gpxe/src/core/process.c b/gpxe/src/core/process.c index cf931acf..6a687140 100644 --- a/gpxe/src/core/process.c +++ b/gpxe/src/core/process.c @@ -79,7 +79,9 @@ void step ( void ) { list_for_each_entry ( process, &run_queue, list ) { list_del ( &process->list ); list_add_tail ( &process->list, &run_queue ); + DBGC2 ( process, "PROCESS %p executing\n", process ); process->step ( process ); + DBGC2 ( process, "PROCESS %p finished executing\n", process ); break; } } diff --git a/gpxe/src/core/serial.c b/gpxe/src/core/serial.c index 97640f93..5b3be39c 100644 --- a/gpxe/src/core/serial.c +++ b/gpxe/src/core/serial.c @@ -13,7 +13,7 @@ #include "stddef.h" #include -#include "io.h" +#include #include #include #include "config/serial.h" diff --git a/gpxe/src/core/settings.c b/gpxe/src/core/settings.c index 3e9eb18a..2d9c096e 100644 --- a/gpxe/src/core/settings.c +++ b/gpxe/src/core/settings.c @@ -333,6 +333,9 @@ int fetch_setting ( struct settings *settings, struct setting *setting, struct settings *child; int ret; + /* Avoid returning uninitialised data on error */ + memset ( data, 0, len ); + /* NULL settings implies starting at the global settings root */ if ( ! settings ) settings = &settings_root; @@ -417,20 +420,23 @@ int fetch_ipv4_setting ( struct settings *settings, struct setting *setting, int fetch_int_setting ( struct settings *settings, struct setting *setting, long *value ) { union { - long value; uint8_t u8[ sizeof ( long ) ]; int8_t s8[ sizeof ( long ) ]; } buf; int len; int i; - buf.value = 0; + /* Avoid returning uninitialised data on error */ + *value = 0; + + /* Fetch raw (network-ordered, variable-length) setting */ len = fetch_setting ( settings, setting, &buf, sizeof ( buf ) ); if ( len < 0 ) return len; if ( len > ( int ) sizeof ( buf ) ) return -ERANGE; + /* Convert to host-ordered signed long */ *value = ( ( buf.s8[0] >= 0 ) ? 0 : -1L ); for ( i = 0 ; i < len ; i++ ) { *value = ( ( *value << 8 ) | buf.u8[i] ); @@ -452,10 +458,15 @@ int fetch_uint_setting ( struct settings *settings, struct setting *setting, long svalue; int len; + /* Avoid returning uninitialised data on error */ + *value = 0; + + /* Fetch as a signed long */ len = fetch_int_setting ( settings, setting, &svalue ); if ( len < 0 ) return len; + /* Mask off sign-extended bits */ *value = ( svalue & ( -1UL >> ( sizeof ( long ) - len ) ) ); return len; @@ -469,7 +480,7 @@ int fetch_uint_setting ( struct settings *settings, struct setting *setting, * @ret value Setting value, or zero */ long fetch_intz_setting ( struct settings *settings, struct setting *setting ){ - long value = 0; + long value; fetch_int_setting ( settings, setting, &value ); return value; @@ -484,7 +495,7 @@ long fetch_intz_setting ( struct settings *settings, struct setting *setting ){ */ unsigned long fetch_uintz_setting ( struct settings *settings, struct setting *setting ) { - unsigned long value = 0; + unsigned long value; fetch_uint_setting ( settings, setting, &value ); return value; @@ -655,6 +666,7 @@ static int parse_setting_name ( const char *name, struct settings **settings, } tmp++; } + setting->tag |= (*settings)->tag_magic; } /* Identify setting type, if specified */ diff --git a/gpxe/src/core/timer.c b/gpxe/src/core/timer.c index 4e047ea7..d71e3da1 100644 --- a/gpxe/src/core/timer.c +++ b/gpxe/src/core/timer.c @@ -1,7 +1,5 @@ /* - * core/timer.c - * - * Copyright (C) 2007 Alexey Zaytsev + * Copyright (C) 2008 Michael Brown . * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -18,96 +16,25 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include -#include - -static struct timer ts_table[0] - __table_start ( struct timer, timers ); -static struct timer ts_table_end[0] - __table_end ( struct timer, timers ); - -/* - * This function may be used in custom timer driver. - * - * This udelay implementation works well if you've got a - * fast currticks(). - */ -void generic_currticks_udelay ( unsigned int usecs ) { - tick_t start; - tick_t elapsed; - - start = currticks(); - do { - /* xxx: Relax the cpu some way. */ - elapsed = ( currticks() - start ); - } while ( elapsed < usecs ); -} - -/** - * Identify timer source - * - * @ret timer Timer source - */ -static struct timer * timer ( void ) { - static struct timer *ts = NULL; - - /* If we have a timer, use it */ - if ( ts ) - return ts; - - /* Scan for a usable timer */ - for ( ts = ts_table ; ts < ts_table_end ; ts++ ) { - if ( ts->init() == 0 ) - return ts; - } - - /* No timer found; we cannot continue */ - assert ( 0 ); - while ( 1 ) {}; -} - -/** - * Read current time - * - * @ret ticks Current time, in ticks - */ -tick_t currticks ( void ) { - tick_t ct; - - ct = timer()->currticks(); - DBG ( "currticks: %ld.%06ld seconds\n", - ct / USECS_IN_SEC, ct % USECS_IN_SEC ); - - return ct; -} - -/** - * Delay - * - * @v usecs Time to delay, in microseconds - */ -void udelay ( unsigned int usecs ) { - timer()->udelay ( usecs ); -} +#include /** - * Delay + * Delay for a fixed number of milliseconds * - * @v msecs Time to delay, in milliseconds + * @v msecs Number of milliseconds for which to delay */ -void mdelay ( unsigned int msecs ) { +void mdelay ( unsigned long msecs ) { while ( msecs-- ) - udelay ( USECS_IN_MSEC ); + udelay ( 1000 ); } /** - * Delay + * Delay for a fixed number of seconds * - * @v secs Time to delay, in seconds + * @v secs Number of seconds for which to delay */ unsigned int sleep ( unsigned int secs ) { while ( secs-- ) - mdelay ( MSECS_IN_SEC ); + mdelay ( 1000 ); return 0; } diff --git a/gpxe/src/core/uri.c b/gpxe/src/core/uri.c index cf2b071d..7bb46da0 100644 --- a/gpxe/src/core/uri.c +++ b/gpxe/src/core/uri.c @@ -92,8 +92,12 @@ struct uri * parse_uri ( const char *uri_string ) { uri->fragment = tmp; } - /* Identify absolute/relative URI */ - if ( ( tmp = strchr ( raw, ':' ) ) ) { + /* Identify absolute/relative URI. We ignore schemes that are + * apparently only a single character long, since otherwise we + * misinterpret a DOS-style path name ("C:\path\to\file") as a + * URI with scheme="C",opaque="\path\to\file". + */ + if ( ( tmp = strchr ( raw, ':' ) ) && ( tmp > ( raw + 1 ) ) ) { /* Absolute URI: identify hierarchical/opaque */ uri->scheme = raw; *(tmp++) = '\0'; diff --git a/gpxe/src/crypto/cryptoLayer.h b/gpxe/src/crypto/cryptoLayer.h index 28ce97bc..d2e10f2f 100644 --- a/gpxe/src/crypto/cryptoLayer.h +++ b/gpxe/src/crypto/cryptoLayer.h @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include /* Drag in pscrypto.h */ diff --git a/gpxe/src/drivers/bitbash/i2c_bit.c b/gpxe/src/drivers/bitbash/i2c_bit.c index a3af610b..b85057af 100644 --- a/gpxe/src/drivers/bitbash/i2c_bit.c +++ b/gpxe/src/drivers/bitbash/i2c_bit.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ static void i2c_delay ( void ) { * @v state New state of SCL */ static void setscl ( struct bit_basher *basher, int state ) { + DBG2 ( "%c", ( state ? '/' : '\\' ) ); write_bit ( basher, I2C_BIT_SCL, state ); i2c_delay(); } @@ -60,6 +62,7 @@ static void setscl ( struct bit_basher *basher, int state ) { * @v state New state of SDA */ static void setsda ( struct bit_basher *basher, int state ) { + DBG2 ( "%c", ( state ? '1' : '0' ) ); write_bit ( basher, I2C_BIT_SDA, state ); i2c_delay(); } @@ -71,7 +74,10 @@ static void setsda ( struct bit_basher *basher, int state ) { * @ret state State of SDA */ static int getsda ( struct bit_basher *basher ) { - return read_bit ( basher, I2C_BIT_SDA ); + int state; + state = read_bit ( basher, I2C_BIT_SDA ); + DBG2 ( "%c", ( state ? '+' : '-' ) ); + return state; } /** @@ -137,15 +143,20 @@ static void i2c_stop ( struct bit_basher *basher ) { */ static int i2c_send_byte ( struct bit_basher *basher, uint8_t byte ) { int i; - + int ack; + /* Send byte */ + DBG2 ( "[send %02x]", byte ); for ( i = 8 ; i ; i-- ) { i2c_send_bit ( basher, byte & 0x80 ); byte <<= 1; } /* Check for acknowledgement from slave */ - return ( i2c_recv_bit ( basher ) == 0 ? 0 : -EIO ); + ack = ( i2c_recv_bit ( basher ) == 0 ); + DBG2 ( "%s", ( ack ? "[acked]" : "[not acked]" ) ); + + return ( ack ? 0 : -EIO ); } /** @@ -157,19 +168,20 @@ static int i2c_send_byte ( struct bit_basher *basher, uint8_t byte ) { * Receives a byte via the I2C bus and sends NACK to the slave device. */ static uint8_t i2c_recv_byte ( struct bit_basher *basher ) { - uint8_t value = 0; + uint8_t byte = 0; int i; /* Receive byte */ for ( i = 8 ; i ; i-- ) { - value <<= 1; - value |= ( i2c_recv_bit ( basher ) & 0x1 ); + byte <<= 1; + byte |= ( i2c_recv_bit ( basher ) & 0x1 ); } /* Send NACK */ i2c_send_bit ( basher, 1 ); - return value; + DBG2 ( "[rcvd %02x]", byte ); + return byte; } /** @@ -177,36 +189,75 @@ static uint8_t i2c_recv_byte ( struct bit_basher *basher ) { * * @v basher Bit-bashing interface * @v i2cdev I2C device + * @v offset Starting offset within the device * @v direction I2C_READ or I2C_WRITE * @ret rc Return status code */ static int i2c_select ( struct bit_basher *basher, struct i2c_device *i2cdev, - unsigned int direction ) { + unsigned int offset, unsigned int direction ) { unsigned int address; + int shift; + unsigned int byte; int rc; i2c_start ( basher ); - /* First byte of the address */ - address = i2cdev->address; - if ( i2cdev->tenbit ) { - address |= I2C_TENBIT_ADDRESS; - address >>= 8; - } - if ( ( rc = i2c_send_byte ( basher, - ( ( address << 1 ) | direction ) ) ) != 0 ) - return rc; + /* Calculate address to appear on bus */ + address = ( ( ( i2cdev->dev_addr | + ( offset >> ( 8 * i2cdev->word_addr_len ) ) ) << 1 ) + | direction ); - /* Second byte of the address (10-bit addresses only) */ - if ( i2cdev->tenbit ) { - if ( ( rc = i2c_send_byte ( basher, - ( i2cdev->address & 0xff ) ) ) !=0) + /* Send address a byte at a time */ + for ( shift = ( 8 * ( i2cdev->dev_addr_len - 1 ) ) ; + shift >= 0 ; shift -= 8 ) { + byte = ( ( address >> shift ) & 0xff ); + if ( ( rc = i2c_send_byte ( basher, byte ) ) != 0 ) return rc; } return 0; } +/** + * Reset I2C bus + * + * @v basher Bit-bashing interface + * @ret rc Return status code + * + * i2c devices often don't have a reset line, so even a reboot or + * system power cycle is sometimes not enough to bring them back to a + * known state. + */ +static int i2c_reset ( struct bit_basher *basher ) { + unsigned int i; + int sda; + + /* Clock through several cycles, waiting for an opportunity to + * pull SDA low while SCL is high (which creates a start + * condition). + */ + setscl ( basher, 0 ); + setsda ( basher, 1 ); + for ( i = 0 ; i < I2C_RESET_MAX_CYCLES ; i++ ) { + setscl ( basher, 1 ); + sda = getsda ( basher ); + if ( sda ) { + /* Now that the device will see a start, issue it */ + i2c_start ( basher ); + /* Stop the bus to leave it in a known good state */ + i2c_stop ( basher ); + DBGC ( basher, "I2CBIT %p reset after %d attempts\n", + basher, ( i + 1 ) ); + return 0; + } + setscl ( basher, 0 ); + } + + DBGC ( basher, "I2CBIT %p could not reset after %d attempts\n", + basher, i ); + return -ETIMEDOUT; +} + /** * Read data from I2C device via bit-bashing interface * @@ -228,12 +279,14 @@ static int i2c_bit_read ( struct i2c_interface *i2c, struct bit_basher *basher = &i2cbit->basher; int rc = 0; - DBG ( "Reading from I2C device %x: ", i2cdev->address ); + DBGC ( basher, "I2CBIT %p reading from device %x: ", + basher, i2cdev->dev_addr ); - while ( 1 ) { + for ( ; ; data++, offset++ ) { /* Select device for writing */ - if ( ( rc = i2c_select ( basher, i2cdev, I2C_WRITE ) ) != 0 ) + if ( ( rc = i2c_select ( basher, i2cdev, offset, + I2C_WRITE ) ) != 0 ) break; /* Abort at end of data */ @@ -241,19 +294,20 @@ static int i2c_bit_read ( struct i2c_interface *i2c, break; /* Select offset */ - if ( ( rc = i2c_send_byte ( basher, offset++ ) ) != 0 ) + if ( ( rc = i2c_send_byte ( basher, offset ) ) != 0 ) break; /* Select device for reading */ - if ( ( rc = i2c_select ( basher, i2cdev, I2C_READ ) ) != 0 ) + if ( ( rc = i2c_select ( basher, i2cdev, offset, + I2C_READ ) ) != 0 ) break; /* Read byte */ - *data++ = i2c_recv_byte ( basher ); - DBG ( "%02x ", *(data - 1) ); + *data = i2c_recv_byte ( basher ); + DBGC ( basher, "%02x ", *data ); } - DBG ( "%s\n", ( rc ? "failed" : "" ) ); + DBGC ( basher, "%s\n", ( rc ? "failed" : "" ) ); i2c_stop ( basher ); return rc; } @@ -279,12 +333,14 @@ static int i2c_bit_write ( struct i2c_interface *i2c, struct bit_basher *basher = &i2cbit->basher; int rc = 0; - DBG ( "Writing to I2C device %x: ", i2cdev->address ); + DBGC ( basher, "I2CBIT %p writing to device %x: ", + basher, i2cdev->dev_addr ); - while ( 1 ) { + for ( ; ; data++, offset++ ) { /* Select device for writing */ - if ( ( rc = i2c_select ( basher, i2cdev, I2C_WRITE ) ) != 0 ) + if ( ( rc = i2c_select ( basher, i2cdev, offset, + I2C_WRITE ) ) != 0 ) break; /* Abort at end of data */ @@ -292,16 +348,16 @@ static int i2c_bit_write ( struct i2c_interface *i2c, break; /* Select offset */ - if ( ( rc = i2c_send_byte ( basher, offset++ ) ) != 0 ) + if ( ( rc = i2c_send_byte ( basher, offset ) ) != 0 ) break; /* Write data to device */ - DBG ( "%02x ", *data ); - if ( ( rc = i2c_send_byte ( basher, *data++ ) ) != 0 ) + DBGC ( basher, "%02x ", *data ); + if ( ( rc = i2c_send_byte ( basher, *data ) ) != 0 ) break; } - DBG ( "%s\n", ( rc ? "failed" : "" ) ); + DBGC ( basher, "%s\n", ( rc ? "failed" : "" ) ); i2c_stop ( basher ); return rc; } @@ -310,13 +366,26 @@ static int i2c_bit_write ( struct i2c_interface *i2c, * Initialise I2C bit-bashing interface * * @v i2cbit I2C bit-bashing interface + * @v bash_op Bit-basher operations */ -void init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit ) { +int init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit, + struct bit_basher_operations *bash_op ) { struct bit_basher *basher = &i2cbit->basher; - + int rc; + + /* Initialise data structures */ + basher->op = bash_op; assert ( basher->op->read != NULL ); assert ( basher->op->write != NULL ); i2cbit->i2c.read = i2c_bit_read; i2cbit->i2c.write = i2c_bit_write; - i2c_stop ( basher ); + + /* Reset I2C bus */ + if ( ( rc = i2c_reset ( basher ) ) != 0 ) { + DBGC ( basher, "I2CBIT %p could not reset I2C bus: %s\n", + basher, strerror ( rc ) ); + return rc; + } + + return 0; } diff --git a/gpxe/src/drivers/bus/eisa.c b/gpxe/src/drivers/bus/eisa.c index ee03df3a..d9e42359 100644 --- a/gpxe/src/drivers/bus/eisa.c +++ b/gpxe/src/drivers/bus/eisa.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include diff --git a/gpxe/src/drivers/bus/isa.c b/gpxe/src/drivers/bus/isa.c index a4105fd0..fa5def54 100644 --- a/gpxe/src/drivers/bus/isa.c +++ b/gpxe/src/drivers/bus/isa.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include /* @@ -49,9 +49,9 @@ static isa_probe_addr_t isa_extra_probe_addrs[] = { (driver)->probe_addrs[(ioidx)] ) static struct isa_driver isa_drivers[0] - __table_start ( struct isa_driver, isa_driver ); + __table_start ( struct isa_driver, isa_drivers ); static struct isa_driver isa_drivers_end[0] - __table_end ( struct isa_driver, isa_driver ); + __table_end ( struct isa_driver, isa_drivers ); static void isabus_remove ( struct root_device *rootdev ); diff --git a/gpxe/src/drivers/bus/isapnp.c b/gpxe/src/drivers/bus/isapnp.c index f4968eb1..0915a92b 100644 --- a/gpxe/src/drivers/bus/isapnp.c +++ b/gpxe/src/drivers/bus/isapnp.c @@ -60,7 +60,7 @@ #include #include #include -#include +#include #include #include diff --git a/gpxe/src/drivers/bus/mca.c b/gpxe/src/drivers/bus/mca.c index eb7b7e39..e9233813 100644 --- a/gpxe/src/drivers/bus/mca.c +++ b/gpxe/src/drivers/bus/mca.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include static struct mca_driver mca_drivers[0] diff --git a/gpxe/src/drivers/infiniband/arbel.c b/gpxe/src/drivers/infiniband/arbel.c index 1b55131b..e516031b 100644 --- a/gpxe/src/drivers/infiniband/arbel.c +++ b/gpxe/src/drivers/infiniband/arbel.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "arbel.h" /** @@ -482,6 +483,50 @@ arbel_cmd_map_fa ( struct arbel *arbel, 0, map, 1, NULL ); } +/*************************************************************************** + * + * MAD operations + * + *************************************************************************** + */ + +/** + * Issue management datagram + * + * @v ibdev Infiniband device + * @v mad Management datagram + * @ret rc Return status code + */ +static int arbel_mad ( struct ib_device *ibdev, union ib_mad *mad ) { + struct arbel *arbel = ib_get_drvdata ( ibdev ); + union arbelprm_mad mad_ifc; + int rc; + + linker_assert ( sizeof ( *mad ) == sizeof ( mad_ifc.mad ), + mad_size_mismatch ); + + /* Copy in request packet */ + memcpy ( &mad_ifc.mad, mad, sizeof ( mad_ifc.mad ) ); + + /* Issue MAD */ + if ( ( rc = arbel_cmd_mad_ifc ( arbel, ibdev->port, + &mad_ifc ) ) != 0 ) { + DBGC ( arbel, "Arbel %p could not issue MAD IFC: %s\n", + arbel, strerror ( rc ) ); + return rc; + } + + /* Copy out reply packet */ + memcpy ( mad, &mad_ifc.mad, sizeof ( *mad ) ); + + if ( mad->hdr.status != 0 ) { + DBGC ( arbel, "Arbel %p MAD IFC status %04x\n", + arbel, ntohs ( mad->hdr.status ) ); + return -EIO; + } + return 0; +} + /*************************************************************************** * * Completion queue operations @@ -1006,7 +1051,7 @@ static int arbel_post_send ( struct ib_device *ibdev, ud_address_vector.pd, ARBEL_GLOBAL_PD, ud_address_vector.port_number, ibdev->port ); MLX_FILL_2 ( &wqe->ud, 1, - ud_address_vector.rlid, av->dlid, + ud_address_vector.rlid, av->lid, ud_address_vector.g, av->gid_present ); MLX_FILL_2 ( &wqe->ud, 2, ud_address_vector.max_stat_rate, @@ -1015,7 +1060,7 @@ static int arbel_post_send ( struct ib_device *ibdev, MLX_FILL_1 ( &wqe->ud, 3, ud_address_vector.sl, av->sl ); gid = ( av->gid_present ? &av->gid : &arbel_no_gid ); memcpy ( &wqe->ud.u.dwords[4], gid, sizeof ( *gid ) ); - MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->dest_qp ); + MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->qpn ); MLX_FILL_1 ( &wqe->ud, 9, q_key, av->qkey ); MLX_FILL_1 ( &wqe->data[0], 0, byte_count, iob_len ( iobuf ) ); MLX_FILL_1 ( &wqe->data[0], 1, l_key, arbel->reserved_lkey ); @@ -1106,17 +1151,12 @@ static int arbel_post_recv ( struct ib_device *ibdev, * @v ibdev Infiniband device * @v cq Completion queue * @v cqe Hardware completion queue entry - * @v complete_send Send completion handler - * @v complete_recv Receive completion handler * @ret rc Return status code */ static int arbel_complete ( struct ib_device *ibdev, struct ib_completion_queue *cq, - union arbelprm_completion_entry *cqe, - ib_completer_t complete_send, - ib_completer_t complete_recv ) { + union arbelprm_completion_entry *cqe ) { struct arbel *arbel = ib_get_drvdata ( ibdev ); - struct ib_completion completion; struct ib_work_queue *wq; struct ib_queue_pair *qp; struct arbel_queue_pair *arbel_qp; @@ -1124,16 +1164,17 @@ static int arbel_complete ( struct ib_device *ibdev, struct arbel_recv_work_queue *arbel_recv_wq; struct arbelprm_recv_wqe *recv_wqe; struct io_buffer *iobuf; - ib_completer_t complete; + struct ib_address_vector av; + struct ib_global_route_header *grh; unsigned int opcode; unsigned long qpn; int is_send; unsigned long wqe_adr; unsigned int wqe_idx; + size_t len; int rc = 0; /* Parse completion */ - memset ( &completion, 0, sizeof ( completion ) ); qpn = MLX_GET ( &cqe->normal, my_qpn ); is_send = MLX_GET ( &cqe->normal, s ); wqe_adr = ( MLX_GET ( &cqe->normal, wqe_adr ) << 6 ); @@ -1141,9 +1182,8 @@ static int arbel_complete ( struct ib_device *ibdev, if ( opcode >= ARBEL_OPCODE_RECV_ERROR ) { /* "s" field is not valid for error opcodes */ is_send = ( opcode == ARBEL_OPCODE_SEND_ERROR ); - completion.syndrome = MLX_GET ( &cqe->error, syndrome ); - DBGC ( arbel, "Arbel %p CPN %lx syndrome %x vendor %lx\n", - arbel, cq->cqn, completion.syndrome, + DBGC ( arbel, "Arbel %p CPN %lx syndrome %lx vendor %lx\n", + arbel, cq->cqn, MLX_GET ( &cqe->error, syndrome ), MLX_GET ( &cqe->error, vendor_code ) ); rc = -EIO; /* Don't return immediately; propagate error to completer */ @@ -1181,9 +1221,12 @@ static int arbel_complete ( struct ib_device *ibdev, } wq->iobufs[wqe_idx] = NULL; - /* Fill in length for received packets */ - if ( ! is_send ) { - completion.len = MLX_GET ( &cqe->normal, byte_cnt ); + if ( is_send ) { + /* Hand off to completion handler */ + ib_complete_send ( ibdev, qp, iobuf, rc ); + } else { + /* Set received length */ + len = MLX_GET ( &cqe->normal, byte_cnt ); recv_wqe = &arbel_recv_wq->wqe[wqe_idx].recv; assert ( MLX_GET ( &recv_wqe->data[0], local_address_l ) == virt_to_bus ( iobuf->data ) ); @@ -1192,18 +1235,22 @@ static int arbel_complete ( struct ib_device *ibdev, MLX_FILL_1 ( &recv_wqe->data[0], 0, byte_count, 0 ); MLX_FILL_1 ( &recv_wqe->data[0], 1, l_key, ARBEL_INVALID_LKEY ); - if ( completion.len > iob_tailroom ( iobuf ) ) { - DBGC ( arbel, "Arbel %p CQN %lx QPN %lx IDX %x " - "overlength received packet length %zd\n", - arbel, cq->cqn, qpn, wqe_idx, completion.len ); - return -EIO; - } + assert ( len <= iob_tailroom ( iobuf ) ); + iob_put ( iobuf, len ); + assert ( iob_len ( iobuf ) >= sizeof ( *grh ) ); + grh = iobuf->data; + iob_pull ( iobuf, sizeof ( *grh ) ); + /* Construct address vector */ + memset ( &av, 0, sizeof ( av ) ); + av.qpn = MLX_GET ( &cqe->normal, rqpn ); + av.lid = MLX_GET ( &cqe->normal, rlid ); + av.sl = MLX_GET ( &cqe->normal, sl ); + av.gid_present = MLX_GET ( &cqe->normal, g ); + memcpy ( &av.gid, &grh->sgid, sizeof ( av.gid ) ); + /* Hand off to completion handler */ + ib_complete_recv ( ibdev, qp, &av, iobuf, rc ); } - /* Pass off to caller's completion handler */ - complete = ( is_send ? complete_send : complete_recv ); - complete ( ibdev, qp, &completion, iobuf ); - return rc; } @@ -1212,13 +1259,9 @@ static int arbel_complete ( struct ib_device *ibdev, * * @v ibdev Infiniband device * @v cq Completion queue - * @v complete_send Send completion handler - * @v complete_recv Receive completion handler */ static void arbel_poll_cq ( struct ib_device *ibdev, - struct ib_completion_queue *cq, - ib_completer_t complete_send, - ib_completer_t complete_recv ) { + struct ib_completion_queue *cq ) { struct arbel *arbel = ib_get_drvdata ( ibdev ); struct arbel_completion_queue *arbel_cq = ib_cq_get_drvdata ( cq ); struct arbelprm_cq_ci_db_record *ci_db_rec; @@ -1236,8 +1279,7 @@ static void arbel_poll_cq ( struct ib_device *ibdev, } /* Handle completion */ - if ( ( rc = arbel_complete ( ibdev, cq, cqe, complete_send, - complete_recv ) ) != 0 ) { + if ( ( rc = arbel_complete ( ibdev, cq, cqe ) ) != 0 ) { DBGC ( arbel, "Arbel %p failed to complete: %s\n", arbel, strerror ( rc ) ); DBGC_HD ( arbel, cqe, sizeof ( *cqe ) ); @@ -1397,6 +1439,9 @@ static void arbel_event_port_state_change ( struct arbel *arbel, return; } + /* Update MAD parameters */ + ib_smc_update ( arbel->ibdev[port], arbel_mad ); + /* Notify Infiniband core of link state change */ ib_link_state_changed ( arbel->ibdev[port] ); } @@ -1486,6 +1531,9 @@ static int arbel_open ( struct ib_device *ibdev ) { return rc; } + /* Update MAD parameters */ + ib_smc_update ( ibdev, arbel_mad ); + return 0; } @@ -1601,51 +1649,6 @@ static void arbel_mcast_detach ( struct ib_device *ibdev, } } -/*************************************************************************** - * - * MAD operations - * - *************************************************************************** - */ - -/** - * Issue management datagram - * - * @v ibdev Infiniband device - * @v mad Management datagram - * @v len Length of management datagram - * @ret rc Return status code - */ -static int arbel_mad ( struct ib_device *ibdev, struct ib_mad_hdr *mad, - size_t len ) { - struct arbel *arbel = ib_get_drvdata ( ibdev ); - union arbelprm_mad mad_ifc; - int rc; - - /* Copy in request packet */ - memset ( &mad_ifc, 0, sizeof ( mad_ifc ) ); - assert ( len <= sizeof ( mad_ifc.mad ) ); - memcpy ( &mad_ifc.mad, mad, len ); - - /* Issue MAD */ - if ( ( rc = arbel_cmd_mad_ifc ( arbel, ibdev->port, - &mad_ifc ) ) != 0 ) { - DBGC ( arbel, "Arbel %p could not issue MAD IFC: %s\n", - arbel, strerror ( rc ) ); - return rc; - } - - /* Copy out reply packet */ - memcpy ( mad, &mad_ifc.mad, len ); - - if ( mad->status != 0 ) { - DBGC ( arbel, "Arbel %p MAD IFC status %04x\n", - arbel, ntohs ( mad->status ) ); - return -EIO; - } - return 0; -} - /** Arbel Infiniband operations */ static struct ib_device_operations arbel_ib_operations = { .create_cq = arbel_create_cq, @@ -1661,7 +1664,6 @@ static struct ib_device_operations arbel_ib_operations = { .close = arbel_close, .mcast_attach = arbel_mcast_attach, .mcast_detach = arbel_mcast_detach, - .mad = arbel_mad, }; /*************************************************************************** diff --git a/gpxe/src/drivers/infiniband/hermon.c b/gpxe/src/drivers/infiniband/hermon.c index 3ca60033..01eab396 100644 --- a/gpxe/src/drivers/infiniband/hermon.c +++ b/gpxe/src/drivers/infiniband/hermon.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "hermon.h" /** @@ -608,6 +609,50 @@ static void hermon_free_mtt ( struct hermon *hermon, mtt->num_pages ); } +/*************************************************************************** + * + * MAD operations + * + *************************************************************************** + */ + +/** + * Issue management datagram + * + * @v ibdev Infiniband device + * @v mad Management datagram + * @ret rc Return status code + */ +static int hermon_mad ( struct ib_device *ibdev, union ib_mad *mad ) { + struct hermon *hermon = ib_get_drvdata ( ibdev ); + union hermonprm_mad mad_ifc; + int rc; + + linker_assert ( sizeof ( *mad ) == sizeof ( mad_ifc.mad ), + mad_size_mismatch ); + + /* Copy in request packet */ + memcpy ( &mad_ifc.mad, mad, sizeof ( mad_ifc.mad ) ); + + /* Issue MAD */ + if ( ( rc = hermon_cmd_mad_ifc ( hermon, ibdev->port, + &mad_ifc ) ) != 0 ) { + DBGC ( hermon, "Hermon %p could not issue MAD IFC: %s\n", + hermon, strerror ( rc ) ); + return rc; + } + + /* Copy out reply packet */ + memcpy ( mad, &mad_ifc.mad, sizeof ( *mad ) ); + + if ( mad->hdr.status != 0 ) { + DBGC ( hermon, "Hermon %p MAD IFC status %04x\n", + hermon, ntohs ( mad->hdr.status ) ); + return -EIO; + } + return 0; +} + /*************************************************************************** * * Completion queue operations @@ -1015,7 +1060,7 @@ static int hermon_post_send ( struct ib_device *ibdev, ud_address_vector.pd, HERMON_GLOBAL_PD, ud_address_vector.port_number, ibdev->port ); MLX_FILL_2 ( &wqe->ud, 1, - ud_address_vector.rlid, av->dlid, + ud_address_vector.rlid, av->lid, ud_address_vector.g, av->gid_present ); MLX_FILL_1 ( &wqe->ud, 2, ud_address_vector.max_stat_rate, @@ -1024,7 +1069,7 @@ static int hermon_post_send ( struct ib_device *ibdev, MLX_FILL_1 ( &wqe->ud, 3, ud_address_vector.sl, av->sl ); gid = ( av->gid_present ? &av->gid : &hermon_no_gid ); memcpy ( &wqe->ud.u.dwords[4], gid, sizeof ( *gid ) ); - MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->dest_qp ); + MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->qpn ); MLX_FILL_1 ( &wqe->ud, 9, q_key, av->qkey ); MLX_FILL_1 ( &wqe->data[0], 0, byte_count, iob_len ( iobuf ) ); MLX_FILL_1 ( &wqe->data[0], 1, l_key, hermon->reserved_lkey ); @@ -1101,39 +1146,34 @@ static int hermon_post_recv ( struct ib_device *ibdev, * @v ibdev Infiniband device * @v cq Completion queue * @v cqe Hardware completion queue entry - * @v complete_send Send completion handler - * @v complete_recv Receive completion handler * @ret rc Return status code */ static int hermon_complete ( struct ib_device *ibdev, struct ib_completion_queue *cq, - union hermonprm_completion_entry *cqe, - ib_completer_t complete_send, - ib_completer_t complete_recv ) { + union hermonprm_completion_entry *cqe ) { struct hermon *hermon = ib_get_drvdata ( ibdev ); - struct ib_completion completion; struct ib_work_queue *wq; struct ib_queue_pair *qp; struct hermon_queue_pair *hermon_qp; struct io_buffer *iobuf; - ib_completer_t complete; + struct ib_address_vector av; + struct ib_global_route_header *grh; unsigned int opcode; unsigned long qpn; int is_send; unsigned int wqe_idx; + size_t len; int rc = 0; /* Parse completion */ - memset ( &completion, 0, sizeof ( completion ) ); qpn = MLX_GET ( &cqe->normal, qpn ); is_send = MLX_GET ( &cqe->normal, s_r ); opcode = MLX_GET ( &cqe->normal, opcode ); if ( opcode >= HERMON_OPCODE_RECV_ERROR ) { /* "s" field is not valid for error opcodes */ is_send = ( opcode == HERMON_OPCODE_SEND_ERROR ); - completion.syndrome = MLX_GET ( &cqe->error, syndrome ); - DBGC ( hermon, "Hermon %p CQN %lx syndrome %x vendor %lx\n", - hermon, cq->cqn, completion.syndrome, + DBGC ( hermon, "Hermon %p CQN %lx syndrome %lx vendor %lx\n", + hermon, cq->cqn, MLX_GET ( &cqe->error, syndrome ), MLX_GET ( &cqe->error, vendor_error_syndrome ) ); rc = -EIO; /* Don't return immediately; propagate error to completer */ @@ -1160,21 +1200,28 @@ static int hermon_complete ( struct ib_device *ibdev, } wq->iobufs[wqe_idx] = NULL; - /* Fill in length for received packets */ - if ( ! is_send ) { - completion.len = MLX_GET ( &cqe->normal, byte_cnt ); - if ( completion.len > iob_tailroom ( iobuf ) ) { - DBGC ( hermon, "Hermon %p CQN %lx QPN %lx IDX %x " - "overlength received packet length %zd\n", - hermon, cq->cqn, qpn, wqe_idx, completion.len ); - return -EIO; - } + if ( is_send ) { + /* Hand off to completion handler */ + ib_complete_send ( ibdev, qp, iobuf, rc ); + } else { + /* Set received length */ + len = MLX_GET ( &cqe->normal, byte_cnt ); + assert ( len <= iob_tailroom ( iobuf ) ); + iob_put ( iobuf, len ); + assert ( iob_len ( iobuf ) >= sizeof ( *grh ) ); + grh = iobuf->data; + iob_pull ( iobuf, sizeof ( *grh ) ); + /* Construct address vector */ + memset ( &av, 0, sizeof ( av ) ); + av.qpn = MLX_GET ( &cqe->normal, srq_rqpn ); + av.lid = MLX_GET ( &cqe->normal, slid_smac47_32 ); + av.sl = MLX_GET ( &cqe->normal, sl ); + av.gid_present = MLX_GET ( &cqe->normal, g ); + memcpy ( &av.gid, &grh->sgid, sizeof ( av.gid ) ); + /* Hand off to completion handler */ + ib_complete_recv ( ibdev, qp, &av, iobuf, rc ); } - /* Pass off to caller's completion handler */ - complete = ( is_send ? complete_send : complete_recv ); - complete ( ibdev, qp, &completion, iobuf ); - return rc; } @@ -1183,13 +1230,9 @@ static int hermon_complete ( struct ib_device *ibdev, * * @v ibdev Infiniband device * @v cq Completion queue - * @v complete_send Send completion handler - * @v complete_recv Receive completion handler */ static void hermon_poll_cq ( struct ib_device *ibdev, - struct ib_completion_queue *cq, - ib_completer_t complete_send, - ib_completer_t complete_recv ) { + struct ib_completion_queue *cq ) { struct hermon *hermon = ib_get_drvdata ( ibdev ); struct hermon_completion_queue *hermon_cq = ib_cq_get_drvdata ( cq ); union hermonprm_completion_entry *cqe; @@ -1209,8 +1252,7 @@ static void hermon_poll_cq ( struct ib_device *ibdev, DBGCP_HD ( hermon, cqe, sizeof ( *cqe ) ); /* Handle completion */ - if ( ( rc = hermon_complete ( ibdev, cq, cqe, complete_send, - complete_recv ) ) != 0 ) { + if ( ( rc = hermon_complete ( ibdev, cq, cqe ) ) != 0 ) { DBGC ( hermon, "Hermon %p failed to complete: %s\n", hermon, strerror ( rc ) ); DBGC_HD ( hermon, cqe, sizeof ( *cqe ) ); @@ -1380,6 +1422,9 @@ static void hermon_event_port_state_change ( struct hermon *hermon, return; } + /* Update MAD parameters */ + ib_smc_update ( hermon->ibdev[port], hermon_mad ); + /* Notify Infiniband core of link state change */ ib_link_state_changed ( hermon->ibdev[port] ); } @@ -1468,6 +1513,9 @@ static int hermon_open ( struct ib_device *ibdev ) { return rc; } + /* Update MAD parameters */ + ib_smc_update ( ibdev, hermon_mad ); + return 0; } @@ -1582,51 +1630,6 @@ static void hermon_mcast_detach ( struct ib_device *ibdev, } } -/*************************************************************************** - * - * MAD operations - * - *************************************************************************** - */ - -/** - * Issue management datagram - * - * @v ibdev Infiniband device - * @v mad Management datagram - * @v len Length of management datagram - * @ret rc Return status code - */ -static int hermon_mad ( struct ib_device *ibdev, struct ib_mad_hdr *mad, - size_t len ) { - struct hermon *hermon = ib_get_drvdata ( ibdev ); - union hermonprm_mad mad_ifc; - int rc; - - /* Copy in request packet */ - memset ( &mad_ifc, 0, sizeof ( mad_ifc ) ); - assert ( len <= sizeof ( mad_ifc.mad ) ); - memcpy ( &mad_ifc.mad, mad, len ); - - /* Issue MAD */ - if ( ( rc = hermon_cmd_mad_ifc ( hermon, ibdev->port, - &mad_ifc ) ) != 0 ) { - DBGC ( hermon, "Hermon %p could not issue MAD IFC: %s\n", - hermon, strerror ( rc ) ); - return rc; - } - - /* Copy out reply packet */ - memcpy ( mad, &mad_ifc.mad, len ); - - if ( mad->status != 0 ) { - DBGC ( hermon, "Hermon %p MAD IFC status %04x\n", - hermon, ntohs ( mad->status ) ); - return -EIO; - } - return 0; -} - /** Hermon Infiniband operations */ static struct ib_device_operations hermon_ib_operations = { .create_cq = hermon_create_cq, @@ -1642,7 +1645,6 @@ static struct ib_device_operations hermon_ib_operations = { .close = hermon_close, .mcast_attach = hermon_mcast_attach, .mcast_detach = hermon_mcast_detach, - .mad = hermon_mad, }; /*************************************************************************** diff --git a/gpxe/src/drivers/infiniband/ib_packet.c b/gpxe/src/drivers/infiniband/ib_packet.c new file mode 100644 index 00000000..74721337 --- /dev/null +++ b/gpxe/src/drivers/infiniband/ib_packet.c @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2008 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @file + * + * Infiniband Packet Formats + * + */ + +/** + * Add IB headers + * + * @v ibdev Infiniband device + * @v iobuf I/O buffer to contain headers + * @v qp Queue pair + * @v payload_len Payload length + * @v av Address vector + */ +int ib_push ( struct ib_device *ibdev, struct io_buffer *iobuf, + struct ib_queue_pair *qp, size_t payload_len, + const struct ib_address_vector *av ) { + struct ib_local_route_header *lrh; + struct ib_global_route_header *grh; + struct ib_base_transport_header *bth; + struct ib_datagram_extended_transport_header *deth; + size_t orig_iob_len = iob_len ( iobuf ); + size_t pad_len; + size_t lrh_len; + size_t grh_len; + unsigned int vl; + unsigned int lnh; + + DBGC2 ( ibdev, "IBDEV %p TX %04x:%08lx => %04x:%08lx (key %08lx)\n", + ibdev, ibdev->lid, qp->qpn, av->lid, av->qpn, av->qkey ); + + /* Calculate packet length */ + pad_len = ( (-payload_len) & 0x3 ); + payload_len += pad_len; + payload_len += 4; /* ICRC */ + + /* Reserve space for headers */ + orig_iob_len = iob_len ( iobuf ); + deth = iob_push ( iobuf, sizeof ( *deth ) ); + bth = iob_push ( iobuf, sizeof ( *bth ) ); + grh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len ); + grh = ( av->gid_present ? + iob_push ( iobuf, sizeof ( *grh ) ) : NULL ); + lrh = iob_push ( iobuf, sizeof ( *lrh ) ); + lrh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len ); + + /* Construct LRH */ + vl = ( ( av->qpn == IB_QPN_SMP ) ? IB_VL_SMP : IB_VL_DEFAULT ); + lrh->vl__lver = ( vl << 4 ); + lnh = ( grh ? IB_LNH_GRH : IB_LNH_BTH ); + lrh->sl__lnh = ( ( av->sl << 4 ) | lnh ); + lrh->dlid = htons ( av->lid ); + lrh->length = htons ( lrh_len >> 2 ); + lrh->slid = htons ( ibdev->lid ); + + /* Construct GRH, if required */ + if ( grh ) { + grh->ipver__tclass__flowlabel = + htonl ( IB_GRH_IPVER_IPv6 << 28 ); + grh->paylen = htons ( grh_len ); + grh->nxthdr = IB_GRH_NXTHDR_IBA; + grh->hoplmt = 0; + memcpy ( &grh->sgid, &ibdev->gid, sizeof ( grh->sgid ) ); + memcpy ( &grh->dgid, &av->gid, sizeof ( grh->dgid ) ); + } + + /* Construct BTH */ + bth->opcode = BTH_OPCODE_UD_SEND; + bth->se__m__padcnt__tver = ( pad_len << 4 ); + bth->pkey = htons ( ibdev->pkey ); + bth->dest_qp = htonl ( av->qpn ); + bth->ack__psn = htonl ( ( ibdev->psn++ ) & 0xffffffUL ); + + /* Construct DETH */ + deth->qkey = htonl ( av->qkey ); + deth->src_qp = htonl ( qp->qpn ); + + DBGCP_HDA ( ibdev, 0, iobuf->data, + ( iob_len ( iobuf ) - orig_iob_len ) ); + + return 0; +} + +/** + * Remove IB headers + * + * @v ibdev Infiniband device + * @v iobuf I/O buffer containing headers + * @v qp Queue pair to fill in, or NULL + * @v payload_len Payload length to fill in, or NULL + * @v av Address vector to fill in + */ +int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf, + struct ib_queue_pair **qp, size_t *payload_len, + struct ib_address_vector *av ) { + struct ib_local_route_header *lrh; + struct ib_global_route_header *grh; + struct ib_base_transport_header *bth; + struct ib_datagram_extended_transport_header *deth; + size_t orig_iob_len = iob_len ( iobuf ); + unsigned int lnh; + size_t pad_len; + unsigned long qpn; + unsigned int lid; + + /* Clear return values */ + if ( qp ) + *qp = NULL; + if ( payload_len ) + *payload_len = 0; + memset ( av, 0, sizeof ( *av ) ); + + /* Extract LRH */ + if ( iob_len ( iobuf ) < sizeof ( *lrh ) ) { + DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for LRH\n", + ibdev, iob_len ( iobuf ) ); + return -EINVAL; + } + lrh = iobuf->data; + iob_pull ( iobuf, sizeof ( *lrh ) ); + av->lid = ntohs ( lrh->slid ); + av->sl = ( lrh->sl__lnh >> 4 ); + lnh = ( lrh->sl__lnh & 0x3 ); + lid = ntohs ( lrh->dlid ); + + /* Reject unsupported packets */ + if ( ! ( ( lnh == IB_LNH_BTH ) || ( lnh == IB_LNH_GRH ) ) ) { + DBGC ( ibdev, "IBDEV %p RX unsupported LNH %x\n", + ibdev, lnh ); + return -ENOTSUP; + } + + /* Extract GRH, if present */ + if ( lnh == IB_LNH_GRH ) { + if ( iob_len ( iobuf ) < sizeof ( *grh ) ) { + DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) " + "for GRH\n", ibdev, iob_len ( iobuf ) ); + return -EINVAL; + } + grh = iobuf->data; + iob_pull ( iobuf, sizeof ( *grh ) ); + av->gid_present = 1; + memcpy ( &av->gid, &grh->sgid, sizeof ( av->gid ) ); + } else { + grh = NULL; + } + + /* Extract BTH */ + if ( iob_len ( iobuf ) < sizeof ( *bth ) ) { + DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for BTH\n", + ibdev, iob_len ( iobuf ) ); + return -EINVAL; + } + bth = iobuf->data; + iob_pull ( iobuf, sizeof ( *bth ) ); + if ( bth->opcode != BTH_OPCODE_UD_SEND ) { + DBGC ( ibdev, "IBDEV %p unsupported BTH opcode %x\n", + ibdev, bth->opcode ); + return -ENOTSUP; + } + qpn = ntohl ( bth->dest_qp ); + + /* Extract DETH */ + if ( iob_len ( iobuf ) < sizeof ( *deth ) ) { + DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for DETH\n", + ibdev, iob_len ( iobuf ) ); + return -EINVAL; + } + deth = iobuf->data; + iob_pull ( iobuf, sizeof ( *deth ) ); + av->qpn = ntohl ( deth->src_qp ); + av->qkey = ntohl ( deth->qkey ); + + /* Calculate payload length, if applicable */ + if ( payload_len ) { + pad_len = ( ( bth->se__m__padcnt__tver >> 4 ) & 0x3 ); + *payload_len = ( ( ntohs ( lrh->length ) << 2 ) + - ( orig_iob_len - iob_len ( iobuf ) ) + - pad_len - 4 /* ICRC */ ); + } + + /* Determine destination QP, if applicable */ + if ( qp ) { + if ( IB_LID_MULTICAST ( lid ) && grh ) { + *qp = ib_find_qp_mgid ( ibdev, &grh->dgid ); + } else { + *qp = ib_find_qp_qpn ( ibdev, qpn ); + } + if ( ! *qp ) { + DBGC ( ibdev, "IBDEV %p RX for nonexistent QP\n", + ibdev ); + return -ENODEV; + } + } + + DBGC2 ( ibdev, "IBDEV %p RX %04x:%08lx <= %04x:%08lx (key %08lx)\n", + ibdev, lid, + ( IB_LID_MULTICAST( lid ) ? ( qp ? (*qp)->qpn : -1UL ) : qpn ), + av->lid, av->qpn, ntohl ( deth->qkey ) ); + DBGCP_HDA ( ibdev, 0, + ( iobuf->data - ( orig_iob_len - iob_len ( iobuf ) ) ), + ( orig_iob_len - iob_len ( iobuf ) ) ); + + return 0; +} diff --git a/gpxe/src/drivers/infiniband/ib_sma.c b/gpxe/src/drivers/infiniband/ib_sma.c new file mode 100644 index 00000000..9426c8f1 --- /dev/null +++ b/gpxe/src/drivers/infiniband/ib_sma.c @@ -0,0 +1,553 @@ +/* + * Copyright (C) 2008 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @file + * + * Infiniband Subnet Management Agent + * + */ + +/** + * Get node information + * + * @v sma Subnet management agent + * @v get Attribute to get + */ +static void ib_sma_get_node_info ( struct ib_sma *sma, + union ib_smp_data *get ) { + struct ib_device *ibdev = sma->ibdev; + struct ib_node_info *node_info = &get->node_info; + struct ib_device *tmp; + + memset ( node_info, 0, sizeof ( *node_info ) ); + node_info->base_version = IB_MGMT_BASE_VERSION; + node_info->class_version = IB_SMP_CLASS_VERSION; + node_info->node_type = IB_NODE_TYPE_HCA; + /* Search for IB devices with the same physical device to + * identify port count and a suitable Node GUID. + */ + for_each_ibdev ( tmp ) { + if ( tmp->dev != ibdev->dev ) + continue; + if ( node_info->num_ports == 0 ) { + memcpy ( node_info->sys_guid, &tmp->gid.u.half[1], + sizeof ( node_info->sys_guid ) ); + memcpy ( node_info->node_guid, &tmp->gid.u.half[1], + sizeof ( node_info->node_guid ) ); + } + node_info->num_ports++; + } + memcpy ( node_info->port_guid, &ibdev->gid.u.half[1], + sizeof ( node_info->port_guid ) ); + node_info->partition_cap = htons ( 1 ); + node_info->local_port_num = ibdev->port; +} + +/** + * Get node description + * + * @v sma Subnet management agent + * @v get Attribute to get + */ +static void ib_sma_get_node_desc ( struct ib_sma *sma, + union ib_smp_data *get ) { + struct ib_device *ibdev = sma->ibdev; + struct ib_node_desc *node_desc = &get->node_desc; + struct ib_gid_half *guid = &ibdev->gid.u.half[1]; + + memset ( node_desc, 0, sizeof ( *node_desc ) ); + snprintf ( node_desc->node_string, sizeof ( node_desc->node_string ), + "gPXE %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)", + guid->bytes[0], guid->bytes[1], guid->bytes[2], + guid->bytes[3], guid->bytes[4], guid->bytes[5], + guid->bytes[6], guid->bytes[7], ibdev->dev->name ); +} + +/** + * Get GUID information + * + * @v sma Subnet management agent + * @v get Attribute to get + */ +static void ib_sma_get_guid_info ( struct ib_sma *sma, + union ib_smp_data *get ) { + struct ib_device *ibdev = sma->ibdev; + struct ib_guid_info *guid_info = &get->guid_info; + + memset ( guid_info, 0, sizeof ( *guid_info ) ); + memcpy ( guid_info->guid[0], &ibdev->gid.u.half[1], + sizeof ( guid_info->guid[0] ) ); +} + +/** + * Get port information + * + * @v sma Subnet management agent + * @v get Attribute to get + */ +static void ib_sma_get_port_info ( struct ib_sma *sma, + union ib_smp_data *get ) { + struct ib_device *ibdev = sma->ibdev; + struct ib_port_info *port_info = &get->port_info; + + memset ( port_info, 0, sizeof ( *port_info ) ); + memcpy ( port_info->gid_prefix, &ibdev->gid.u.half[0], + sizeof ( port_info->gid_prefix ) ); + port_info->lid = ntohs ( ibdev->lid ); + port_info->mastersm_lid = ntohs ( ibdev->sm_lid ); + port_info->local_port_num = ibdev->port; + port_info->link_width_enabled = ibdev->link_width; + port_info->link_width_supported = ibdev->link_width; + port_info->link_width_active = ibdev->link_width; + port_info->link_speed_supported__port_state = + ( ( ibdev->link_speed << 4 ) | ibdev->port_state ); + port_info->port_phys_state__link_down_def_state = + ( ( IB_PORT_PHYS_STATE_POLLING << 4 ) | + IB_PORT_PHYS_STATE_POLLING ); + port_info->link_speed_active__link_speed_enabled = + ( ( ibdev->link_speed << 4 ) | ibdev->link_speed ); + port_info->neighbour_mtu__mastersm_sl = + ( ( IB_MTU_2048 << 4 ) | ibdev->sm_sl ); + port_info->vl_cap__init_type = ( IB_VL_0 << 4 ); + port_info->init_type_reply__mtu_cap = IB_MTU_2048; + port_info->operational_vls__enforcement = ( IB_VL_0 << 4 ); + port_info->guid_cap = 1; +} + +/** + * Set port information + * + * @v sma Subnet management agent + * @v set Attribute to set + * @ret rc Return status code + */ +static int ib_sma_set_port_info ( struct ib_sma *sma, + const union ib_smp_data *set ) { + struct ib_device *ibdev = sma->ibdev; + const struct ib_port_info *port_info = &set->port_info; + + memcpy ( &ibdev->gid.u.half[0], port_info->gid_prefix, + sizeof ( ibdev->gid.u.half[0] ) ); + ibdev->lid = ntohs ( port_info->lid ); + ibdev->sm_lid = ntohs ( port_info->mastersm_lid ); + ibdev->sm_sl = ( port_info->neighbour_mtu__mastersm_sl & 0xf ); + + if ( ! sma->op->set_port_info ) { + /* Not an error; we just ignore all other settings */ + return 0; + } + + return sma->op->set_port_info ( ibdev, port_info ); +} + +/** + * Get partition key table + * + * @v sma Subnet management agent + * @v get Attribute to get + */ +static void ib_sma_get_pkey_table ( struct ib_sma *sma, + union ib_smp_data *get ) { + struct ib_device *ibdev = sma->ibdev; + struct ib_pkey_table *pkey_table = &get->pkey_table; + + memset ( pkey_table, 0, sizeof ( *pkey_table ) ); + pkey_table->pkey[0] = htons ( ibdev->pkey ); +} + +/** + * Set partition key table + * + * @v sma Subnet management agent + * @v set Attribute to set + */ +static int ib_sma_set_pkey_table ( struct ib_sma *sma, + const union ib_smp_data *get ) { + struct ib_device *ibdev = sma->ibdev; + const struct ib_pkey_table *pkey_table = &get->pkey_table; + + ibdev->pkey = ntohs ( pkey_table->pkey[0] ); + return 0; +} + +/** An attribute handler */ +struct ib_sma_handler { + /** Attribute (in network byte order) */ + uint16_t attr_id; + /** Get attribute + * + * @v sma Subnet management agent + * @v get Attribute to get + * @ret rc Return status code + */ + void ( * get ) ( struct ib_sma *sma, union ib_smp_data *get ); + /** Set attribute + * + * @v sma Subnet management agent + * @v set Attribute to set + * @ret rc Return status code + */ + int ( * set ) ( struct ib_sma *sma, const union ib_smp_data *set ); +}; + +/** List of attribute handlers */ +static struct ib_sma_handler ib_sma_handlers[] = { + { htons ( IB_SMP_ATTR_NODE_DESC ), + ib_sma_get_node_desc, NULL }, + { htons ( IB_SMP_ATTR_NODE_INFO ), + ib_sma_get_node_info, NULL }, + { htons ( IB_SMP_ATTR_GUID_INFO ), + ib_sma_get_guid_info, NULL }, + { htons ( IB_SMP_ATTR_PORT_INFO ), + ib_sma_get_port_info, ib_sma_set_port_info }, + { htons ( IB_SMP_ATTR_PKEY_TABLE ), + ib_sma_get_pkey_table, ib_sma_set_pkey_table }, +}; + +/** + * Identify attribute handler + * + * @v attr_id Attribute ID (in network byte order) + * @ret handler Attribute handler (or NULL) + */ +static struct ib_sma_handler * ib_sma_handler ( uint16_t attr_id ) { + struct ib_sma_handler *handler; + unsigned int i; + + for ( i = 0 ; i < ( sizeof ( ib_sma_handlers ) / + sizeof ( ib_sma_handlers[0] ) ) ; i++ ) { + handler = &ib_sma_handlers[i]; + if ( handler->attr_id == attr_id ) + return handler; + } + + return NULL; +} + +/** + * Respond to management datagram + * + * @v sma Subnet management agent + * @v mad Management datagram + * @ret rc Return status code + */ +static int ib_sma_mad ( struct ib_sma *sma, union ib_mad *mad ) { + struct ib_device *ibdev = sma->ibdev; + struct ib_mad_hdr *hdr = &mad->hdr; + struct ib_mad_smp *smp = &mad->smp; + struct ib_sma_handler *handler = NULL; + unsigned int hop_pointer; + unsigned int hop_count; + int rc; + + DBGC ( sma, "SMA %p received SMP with bv=%02x mc=%02x cv=%02x " + "meth=%02x attr=%04x mod=%08lx\n", sma, hdr->base_version, + hdr->mgmt_class, hdr->class_version, hdr->method, + ntohs ( hdr->attr_id ), ntohl ( hdr->attr_mod ) ); + DBGC2_HDA ( sma, 0, mad, sizeof ( *mad ) ); + + /* Sanity checks */ + if ( hdr->base_version != IB_MGMT_BASE_VERSION ) { + DBGC ( sma, "SMA %p unsupported base version %x\n", + sma, hdr->base_version ); + return -ENOTSUP; + } + if ( ( hdr->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE ) && + ( hdr->mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED ) ) { + DBGC ( sma, "SMA %p unsupported management class %x\n", + sma, hdr->mgmt_class ); + return -ENOTSUP; + } + if ( hdr->class_version != IB_SMP_CLASS_VERSION ) { + DBGC ( sma, "SMA %p unsupported class version %x\n", + sma, hdr->class_version ); + return -ENOTSUP; + } + if ( ( hdr->method != IB_MGMT_METHOD_GET ) && + ( hdr->method != IB_MGMT_METHOD_SET ) ) { + DBGC ( sma, "SMA %p unsupported method %x\n", + sma, hdr->method ); + return -ENOTSUP; + } + + /* Identify handler */ + if ( ! ( handler = ib_sma_handler ( hdr->attr_id ) ) ) { + DBGC ( sma, "SMA %p unsupported attribute %x\n", + sma, ntohs ( hdr->attr_id ) ); + hdr->status = htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR ); + goto respond_without_data; + } + + /* Set attribute (if applicable) */ + if ( hdr->method != IB_MGMT_METHOD_SET ) { + hdr->status = htons ( IB_MGMT_STATUS_OK ); + goto respond; + } + if ( ! handler->set ) { + DBGC ( sma, "SMA %p attribute %x is unsettable\n", + sma, ntohs ( hdr->attr_id ) ); + hdr->status = htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR ); + goto respond; + } + if ( ( rc = handler->set ( sma, &smp->smp_data ) ) != 0 ) { + DBGC ( sma, "SMA %p could not set attribute %x: %s\n", + sma, ntohs ( hdr->attr_id ), strerror ( rc ) ); + hdr->status = htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR ); + goto respond; + } + + hdr->status = htons ( IB_MGMT_STATUS_OK ); + + respond: + /* Get attribute */ + handler->get ( sma, &smp->smp_data ); + + respond_without_data: + + /* Set method to "Get Response" */ + hdr->method = IB_MGMT_METHOD_GET_RESP; + + /* Set response fields for directed route SMPs */ + if ( hdr->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE ) { + hdr->status |= htons ( IB_SMP_STATUS_D_INBOUND ); + hop_pointer = smp->mad_hdr.class_specific.smp.hop_pointer; + hop_count = smp->mad_hdr.class_specific.smp.hop_count; + assert ( hop_count == hop_pointer ); + if ( hop_pointer < ( sizeof ( smp->return_path.hops ) / + sizeof ( smp->return_path.hops[0] ) ) ) { + smp->return_path.hops[hop_pointer] = ibdev->port; + } else { + DBGC ( sma, "SMA %p invalid hop pointer %d\n", + sma, hop_pointer ); + return -EINVAL; + } + } + + DBGC ( sma, "SMA %p responding with status=%04x\n", + sma, ntohs ( hdr->status ) ); + DBGC2_HDA ( sma, 0, mad, sizeof ( *mad ) ); + + return 0; +} + +/** + * Refill SMA receive ring + * + * @v sma Subnet management agent + */ +static void ib_sma_refill_recv ( struct ib_sma *sma ) { + struct ib_device *ibdev = sma->ibdev; + struct io_buffer *iobuf; + int rc; + + while ( sma->qp->recv.fill < IB_SMA_NUM_RECV_WQES ) { + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( IB_SMA_PAYLOAD_LEN ); + if ( ! iobuf ) { + /* Non-fatal; we will refill on next attempt */ + return; + } + + /* Post I/O buffer */ + if ( ( rc = ib_post_recv ( ibdev, sma->qp, iobuf ) ) != 0 ) { + DBGC ( sma, "SMA %p could not refill: %s\n", + sma, strerror ( rc ) ); + free_iob ( iobuf ); + /* Give up */ + return; + } + } +} + +/** + * Complete SMA send + * + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v iobuf I/O buffer + * @v rc Completion status code + */ +static void ib_sma_complete_send ( struct ib_device *ibdev __unused, + struct ib_queue_pair *qp, + struct io_buffer *iobuf, int rc ) { + struct ib_sma *sma = ib_qp_get_ownerdata ( qp ); + + if ( rc != 0 ) { + DBGC ( sma, "SMA %p send completion error: %s\n", + sma, strerror ( rc ) ); + } + free_iob ( iobuf ); +} + +/** + * Complete SMA receive + * + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v av Address vector + * @v iobuf I/O buffer + * @v rc Completion status code + */ +static void ib_sma_complete_recv ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + struct ib_address_vector *av, + struct io_buffer *iobuf, int rc ) { + struct ib_sma *sma = ib_qp_get_ownerdata ( qp ); + union ib_mad *mad; + + /* Ignore errors */ + if ( rc != 0 ) { + DBGC ( sma, "SMA %p RX error: %s\n", sma, strerror ( rc ) ); + goto err; + } + + /* Sanity check */ + if ( iob_len ( iobuf ) != sizeof ( *mad ) ) { + DBGC ( sma, "SMA %p RX bad size (%zd bytes)\n", + sma, iob_len ( iobuf ) ); + goto err; + } + mad = iobuf->data; + + /* Construct MAD response */ + if ( ( rc = ib_sma_mad ( sma, mad ) ) != 0 ) { + DBGC ( sma, "SMA %p could not construct MAD response: %s\n", + sma, strerror ( rc ) ); + goto err; + } + + /* Send MAD response */ + if ( ( rc = ib_post_send ( ibdev, qp, av, iobuf ) ) != 0 ) { + DBGC ( sma, "SMA %p could not send MAD response: %s\n", + sma, strerror ( rc ) ); + goto err; + } + + return; + + err: + free_iob ( iobuf ); +} + +/** SMA completion operations */ +static struct ib_completion_queue_operations ib_sma_completion_ops = { + .complete_send = ib_sma_complete_send, + .complete_recv = ib_sma_complete_recv, +}; + +/** + * Poll SMA + * + * @v process Process + */ +static void ib_sma_step ( struct process *process ) { + struct ib_sma *sma = + container_of ( process, struct ib_sma, poll ); + struct ib_device *ibdev = sma->ibdev; + + /* Poll the kernel completion queue */ + ib_poll_cq ( ibdev, sma->cq ); + + /* Refill the receive ring */ + ib_sma_refill_recv ( sma ); +} + +/** + * Create SMA + * + * @v sma Subnet management agent + * @v ibdev Infiniband device + * @v op Subnet management operations + * @ret rc Return status code + */ +int ib_create_sma ( struct ib_sma *sma, struct ib_device *ibdev, + struct ib_sma_operations *op ) { + int rc; + + /* Initialise fields */ + memset ( sma, 0, sizeof ( *sma ) ); + sma->ibdev = ibdev; + sma->op = op; + process_init ( &sma->poll, ib_sma_step, &ibdev->refcnt ); + + /* Create completion queue */ + sma->cq = ib_create_cq ( ibdev, IB_SMA_NUM_CQES, + &ib_sma_completion_ops ); + if ( ! sma->cq ) { + rc = -ENOMEM; + goto err_create_cq; + } + + /* Create queue pair */ + sma->qp = ib_create_qp ( ibdev, IB_SMA_NUM_SEND_WQES, sma->cq, + IB_SMA_NUM_RECV_WQES, sma->cq, 0 ); + if ( ! sma->qp ) { + rc = -ENOMEM; + goto err_create_qp; + } + ib_qp_set_ownerdata ( sma->qp, sma ); + + /* If we don't get QP0, we can't function */ + if ( sma->qp->qpn != IB_QPN_SMP ) { + DBGC ( sma, "SMA %p on QPN %lx, needs to be on QPN 0\n", + sma, sma->qp->qpn ); + rc = -ENOTSUP; + goto err_not_qp0; + } + + /* Fill receive ring */ + ib_sma_refill_recv ( sma ); + return 0; + + err_not_qp0: + ib_destroy_qp ( ibdev, sma->qp ); + err_create_qp: + ib_destroy_cq ( ibdev, sma->cq ); + err_create_cq: + process_del ( &sma->poll ); + return rc; +} + +/** + * Destroy SMA + * + * @v sma Subnet management agent + */ +void ib_destroy_sma ( struct ib_sma *sma ) { + struct ib_device *ibdev = sma->ibdev; + + ib_destroy_qp ( ibdev, sma->qp ); + ib_destroy_cq ( ibdev, sma->cq ); + process_del ( &sma->poll ); +} diff --git a/gpxe/src/drivers/infiniband/ib_smc.c b/gpxe/src/drivers/infiniband/ib_smc.c new file mode 100644 index 00000000..c07a4fef --- /dev/null +++ b/gpxe/src/drivers/infiniband/ib_smc.c @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2008 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @file + * + * Infiniband Subnet Management Client + * + */ + +/** + * Get port information + * + * @v ibdev Infiniband device + * @v local_mad Method for issuing local MADs + * @v mad Management datagram to fill in + * @ret rc Return status code + */ +static int ib_smc_get_port_info ( struct ib_device *ibdev, + ib_local_mad_t local_mad, + union ib_mad *mad ) { + int rc; + + /* Construct MAD */ + memset ( mad, 0, sizeof ( *mad ) ); + mad->hdr.base_version = IB_MGMT_BASE_VERSION; + mad->hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; + mad->hdr.class_version = 1; + mad->hdr.method = IB_MGMT_METHOD_GET; + mad->hdr.attr_id = htons ( IB_SMP_ATTR_PORT_INFO ); + mad->hdr.attr_mod = htonl ( ibdev->port ); + + if ( ( rc = local_mad ( ibdev, mad ) ) != 0 ) { + DBGC ( ibdev, "IBDEV %p could not get port info: %s\n", + ibdev, strerror ( rc ) ); + return rc; + } + return 0; +} + +/** + * Get GUID information + * + * @v ibdev Infiniband device + * @v local_mad Method for issuing local MADs + * @v mad Management datagram to fill in + * @ret rc Return status code + */ +static int ib_smc_get_guid_info ( struct ib_device *ibdev, + ib_local_mad_t local_mad, + union ib_mad *mad ) { + int rc; + + /* Construct MAD */ + memset ( mad, 0, sizeof ( *mad ) ); + mad->hdr.base_version = IB_MGMT_BASE_VERSION; + mad->hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; + mad->hdr.class_version = 1; + mad->hdr.method = IB_MGMT_METHOD_GET; + mad->hdr.attr_id = htons ( IB_SMP_ATTR_GUID_INFO ); + + if ( ( rc = local_mad ( ibdev, mad ) ) != 0 ) { + DBGC ( ibdev, "IBDEV %p could not get GUID info: %s\n", + ibdev, strerror ( rc ) ); + return rc; + } + return 0; +} + +/** + * Get partition key table + * + * @v ibdev Infiniband device + * @v local_mad Method for issuing local MADs + * @v mad Management datagram to fill in + * @ret rc Return status code + */ +static int ib_smc_get_pkey_table ( struct ib_device *ibdev, + ib_local_mad_t local_mad, + union ib_mad *mad ) { + int rc; + + /* Construct MAD */ + memset ( mad, 0, sizeof ( *mad ) ); + mad->hdr.base_version = IB_MGMT_BASE_VERSION; + mad->hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; + mad->hdr.class_version = 1; + mad->hdr.method = IB_MGMT_METHOD_GET; + mad->hdr.attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE ); + + if ( ( rc = local_mad ( ibdev, mad ) ) != 0 ) { + DBGC ( ibdev, "IBDEV %p could not get pkey table: %s\n", + ibdev, strerror ( rc ) ); + return rc; + } + return 0; +} + +/** + * Get MAD parameters + * + * @v ibdev Infiniband device + * @v local_mad Method for issuing local MADs + * @ret rc Return status code + */ +int ib_smc_update ( struct ib_device *ibdev, ib_local_mad_t local_mad ) { + union ib_mad mad; + union ib_smp_data *smp = &mad.smp.smp_data; + int rc; + + /* Port info gives us the link state, the first half of the + * port GID and the SM LID. + */ + if ( ( rc = ib_smc_get_port_info ( ibdev, local_mad, &mad ) ) != 0 ) + return rc; + ibdev->port_state = + ( smp->port_info.link_speed_supported__port_state & 0x0f ); + memcpy ( &ibdev->gid.u.half[0], smp->port_info.gid_prefix, + sizeof ( ibdev->gid.u.half[0] ) ); + ibdev->lid = ntohs ( smp->port_info.lid ); + ibdev->sm_lid = ntohs ( smp->port_info.mastersm_lid ); + ibdev->sm_sl = ( smp->port_info.neighbour_mtu__mastersm_sl & 0xf ); + + /* GUID info gives us the second half of the port GID */ + if ( ( rc = ib_smc_get_guid_info ( ibdev, local_mad, &mad ) ) != 0 ) + return rc; + memcpy ( &ibdev->gid.u.half[1], smp->guid_info.guid[0], + sizeof ( ibdev->gid.u.half[1] ) ); + + /* Get partition key */ + if ( ( rc = ib_smc_get_pkey_table ( ibdev, local_mad, &mad ) ) != 0 ) + return rc; + ibdev->pkey = ntohs ( smp->pkey_table.pkey[0] ); + + DBGC ( ibdev, "IBDEV %p port GID is %08lx:%08lx:%08lx:%08lx\n", ibdev, + htonl ( ibdev->gid.u.dwords[0] ), + htonl ( ibdev->gid.u.dwords[1] ), + htonl ( ibdev->gid.u.dwords[2] ), + htonl ( ibdev->gid.u.dwords[3] ) ); + + return 0; +} diff --git a/gpxe/src/drivers/infiniband/linda.c b/gpxe/src/drivers/infiniband/linda.c new file mode 100644 index 00000000..170eec47 --- /dev/null +++ b/gpxe/src/drivers/infiniband/linda.c @@ -0,0 +1,2396 @@ +/* + * Copyright (C) 2008 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "linda.h" + +/** + * @file + * + * QLogic Linda Infiniband HCA + * + */ + +/** A Linda send work queue */ +struct linda_send_work_queue { + /** Send buffer usage */ + uint8_t *send_buf; + /** Producer index */ + unsigned int prod; + /** Consumer index */ + unsigned int cons; +}; + +/** A Linda receive work queue */ +struct linda_recv_work_queue { + /** Receive header ring */ + void *header; + /** Receive header producer offset (written by hardware) */ + struct QIB_7220_scalar header_prod; + /** Receive header consumer offset */ + unsigned int header_cons; + /** Offset within register space of the eager array */ + unsigned long eager_array; + /** Number of entries in eager array */ + unsigned int eager_entries; + /** Eager array producer index */ + unsigned int eager_prod; + /** Eager array consumer index */ + unsigned int eager_cons; +}; + +/** A Linda HCA */ +struct linda { + /** Registers */ + void *regs; + + /** In-use contexts */ + uint8_t used_ctx[LINDA_NUM_CONTEXTS]; + /** Send work queues */ + struct linda_send_work_queue send_wq[LINDA_NUM_CONTEXTS]; + /** Receive work queues */ + struct linda_recv_work_queue recv_wq[LINDA_NUM_CONTEXTS]; + + /** Offset within register space of the first send buffer */ + unsigned long send_buffer_base; + /** Send buffer availability (reported by hardware) */ + struct QIB_7220_SendBufAvail *sendbufavail; + /** Send buffer availability (maintained by software) */ + uint8_t send_buf[LINDA_MAX_SEND_BUFS]; + /** Send buffer availability producer counter */ + unsigned int send_buf_prod; + /** Send buffer availability consumer counter */ + unsigned int send_buf_cons; + /** Number of reserved send buffers (across all QPs) */ + unsigned int reserved_send_bufs; + + /** I2C bit-bashing interface */ + struct i2c_bit_basher i2c; + /** I2C serial EEPROM */ + struct i2c_device eeprom; + + /** Subnet management agent */ + struct ib_sma sma; +}; + +/*************************************************************************** + * + * Linda register access + * + *************************************************************************** + * + * This card requires atomic 64-bit accesses. Strange things happen + * if you try to use 32-bit accesses; sometimes they work, sometimes + * they don't, sometimes you get random data. + * + * These accessors use the "movq" MMX instruction, and so won't work + * on really old Pentiums (which won't have PCIe anyway, so this is + * something of a moot point). + */ + +/** + * Read Linda qword register + * + * @v linda Linda device + * @v dwords Register buffer to read into + * @v offset Register offset + */ +static void linda_readq ( struct linda *linda, uint32_t *dwords, + unsigned long offset ) { + void *addr = ( linda->regs + offset ); + + __asm__ __volatile__ ( "movq (%1), %%mm0\n\t" + "movq %%mm0, (%0)\n\t" + : : "r" ( dwords ), "r" ( addr ) : "memory" ); + + DBGIO ( "[%08lx] => %08lx%08lx\n", + virt_to_phys ( addr ), dwords[1], dwords[0] ); +} +#define linda_readq( _linda, _ptr, _offset ) \ + linda_readq ( (_linda), (_ptr)->u.dwords, (_offset) ) +#define linda_readq_array8b( _linda, _ptr, _offset, _idx ) \ + linda_readq ( (_linda), (_ptr), ( (_offset) + ( (_idx) * 8 ) ) ) +#define linda_readq_array64k( _linda, _ptr, _offset, _idx ) \ + linda_readq ( (_linda), (_ptr), ( (_offset) + ( (_idx) * 65536 ) ) ) + +/** + * Write Linda qword register + * + * @v linda Linda device + * @v dwords Register buffer to write + * @v offset Register offset + */ +static void linda_writeq ( struct linda *linda, const uint32_t *dwords, + unsigned long offset ) { + void *addr = ( linda->regs + offset ); + + DBGIO ( "[%08lx] <= %08lx%08lx\n", + virt_to_phys ( addr ), dwords[1], dwords[0] ); + + __asm__ __volatile__ ( "movq (%0), %%mm0\n\t" + "movq %%mm0, (%1)\n\t" + : : "r" ( dwords ), "r" ( addr ) : "memory" ); +} +#define linda_writeq( _linda, _ptr, _offset ) \ + linda_writeq ( (_linda), (_ptr)->u.dwords, (_offset) ) +#define linda_writeq_array8b( _linda, _ptr, _offset, _idx ) \ + linda_writeq ( (_linda), (_ptr), ( (_offset) + ( (_idx) * 8 ) ) ) +#define linda_writeq_array64k( _linda, _ptr, _offset, _idx ) \ + linda_writeq ( (_linda), (_ptr), ( (_offset) + ( (_idx) * 65536 ) ) ) + +/** + * Write Linda dword register + * + * @v linda Linda device + * @v dword Value to write + * @v offset Register offset + */ +static void linda_writel ( struct linda *linda, uint32_t dword, + unsigned long offset ) { + writel ( dword, ( linda->regs + offset ) ); +} + +/*************************************************************************** + * + * Link state management + * + *************************************************************************** + */ + +/** + * Textual representation of link state + * + * @v link_state Link state + * @ret link_text Link state text + */ +static const char * linda_link_state_text ( unsigned int link_state ) { + switch ( link_state ) { + case LINDA_LINK_STATE_DOWN: return "DOWN"; + case LINDA_LINK_STATE_INIT: return "INIT"; + case LINDA_LINK_STATE_ARM: return "ARM"; + case LINDA_LINK_STATE_ACTIVE: return "ACTIVE"; + case LINDA_LINK_STATE_ACT_DEFER:return "ACT_DEFER"; + default: return "UNKNOWN"; + } +} + +/** + * Handle link state change + * + * @v linda Linda device + */ +static void linda_link_state_changed ( struct ib_device *ibdev ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct QIB_7220_IBCStatus ibcstatus; + struct QIB_7220_EXTCtrl extctrl; + unsigned int link_state; + unsigned int link_width; + unsigned int link_speed; + + /* Read link state */ + linda_readq ( linda, &ibcstatus, QIB_7220_IBCStatus_offset ); + link_state = BIT_GET ( &ibcstatus, LinkState ); + link_width = BIT_GET ( &ibcstatus, LinkWidthActive ); + link_speed = BIT_GET ( &ibcstatus, LinkSpeedActive ); + DBGC ( linda, "Linda %p link state %s (%s %s)\n", linda, + linda_link_state_text ( link_state ), + ( link_speed ? "DDR" : "SDR" ), ( link_width ? "x4" : "x1" ) ); + + /* Set LEDs according to link state */ + linda_readq ( linda, &extctrl, QIB_7220_EXTCtrl_offset ); + BIT_SET ( &extctrl, LEDPriPortGreenOn, + ( ( link_state >= LINDA_LINK_STATE_INIT ) ? 1 : 0 ) ); + BIT_SET ( &extctrl, LEDPriPortYellowOn, + ( ( link_state >= LINDA_LINK_STATE_ACTIVE ) ? 1 : 0 ) ); + linda_writeq ( linda, &extctrl, QIB_7220_EXTCtrl_offset ); + + /* Notify Infiniband core of link state change */ + ibdev->port_state = ( link_state + 1 ); + ibdev->link_width = + ( link_width ? IB_LINK_WIDTH_4X : IB_LINK_WIDTH_1X ); + ibdev->link_speed = + ( link_speed ? IB_LINK_SPEED_DDR : IB_LINK_SPEED_SDR ); + ib_link_state_changed ( ibdev ); +} + +/** + * Set port information + * + * @v ibdev Infiniband device + * @v port_info New port information + */ +static int linda_set_port_info ( struct ib_device *ibdev, + const struct ib_port_info *port_info ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct QIB_7220_IBCCtrl ibcctrl; + unsigned int port_state; + unsigned int link_state; + + /* Set new link state */ + port_state = ( port_info->link_speed_supported__port_state & 0xf ); + if ( port_state ) { + link_state = ( port_state - 1 ); + DBGC ( linda, "Linda %p set link state to %s (%x)\n", linda, + linda_link_state_text ( link_state ), link_state ); + linda_readq ( linda, &ibcctrl, QIB_7220_IBCCtrl_offset ); + BIT_SET ( &ibcctrl, LinkCmd, link_state ); + linda_writeq ( linda, &ibcctrl, QIB_7220_IBCCtrl_offset ); + } + + /* Detect and report link state change */ + linda_link_state_changed ( ibdev ); + + return 0; +} + +/** Linda subnet management operations */ +static struct ib_sma_operations linda_sma_operations = { + .set_port_info = linda_set_port_info, +}; + +/*************************************************************************** + * + * Context allocation + * + *************************************************************************** + */ + +/** + * Map context number to QPN + * + * @v ctx Context index + * @ret qpn Queue pair number + */ +static int linda_ctx_to_qpn ( unsigned int ctx ) { + /* This mapping is fixed by hardware */ + return ( ctx * 2 ); +} + +/** + * Map QPN to context number + * + * @v qpn Queue pair number + * @ret ctx Context index + */ +static int linda_qpn_to_ctx ( unsigned int qpn ) { + /* This mapping is fixed by hardware */ + return ( qpn / 2 ); +} + +/** + * Allocate a context + * + * @v linda Linda device + * @ret ctx Context index, or negative error + */ +static int linda_alloc_ctx ( struct linda *linda ) { + unsigned int ctx; + + for ( ctx = 0 ; ctx < LINDA_NUM_CONTEXTS ; ctx++ ) { + + if ( ! linda->used_ctx[ctx] ) { + linda->used_ctx[ctx ] = 1; + DBGC2 ( linda, "Linda %p CTX %d allocated\n", + linda, ctx ); + return ctx; + } + } + + DBGC ( linda, "Linda %p out of available contexts\n", linda ); + return -ENOENT; +} + +/** + * Free a context + * + * @v linda Linda device + * @v ctx Context index + */ +static void linda_free_ctx ( struct linda *linda, unsigned int ctx ) { + + linda->used_ctx[ctx] = 0; + DBGC2 ( linda, "Linda %p CTX %d freed\n", linda, ctx ); +} + +/*************************************************************************** + * + * Send datapath + * + *************************************************************************** + */ + +/** Send buffer toggle bit + * + * We encode send buffers as 7 bits of send buffer index plus a single + * bit which should match the "check" bit in the SendBufAvail array. + */ +#define LINDA_SEND_BUF_TOGGLE 0x80 + +/** + * Allocate a send buffer + * + * @v linda Linda device + * @ret send_buf Send buffer + * + * You must guarantee that a send buffer is available. This is done + * by refusing to allocate more TX WQEs in total than the number of + * available send buffers. + */ +static unsigned int linda_alloc_send_buf ( struct linda *linda ) { + unsigned int send_buf; + + send_buf = linda->send_buf[linda->send_buf_cons]; + send_buf ^= LINDA_SEND_BUF_TOGGLE; + linda->send_buf_cons = ( ( linda->send_buf_cons + 1 ) % + LINDA_MAX_SEND_BUFS ); + return send_buf; +} + +/** + * Free a send buffer + * + * @v linda Linda device + * @v send_buf Send buffer + */ +static void linda_free_send_buf ( struct linda *linda, + unsigned int send_buf ) { + linda->send_buf[linda->send_buf_prod] = send_buf; + linda->send_buf_prod = ( ( linda->send_buf_prod + 1 ) % + LINDA_MAX_SEND_BUFS ); +} + +/** + * Check to see if send buffer is in use + * + * @v linda Linda device + * @v send_buf Send buffer + * @ret in_use Send buffer is in use + */ +static int linda_send_buf_in_use ( struct linda *linda, + unsigned int send_buf ) { + unsigned int send_idx; + unsigned int send_check; + unsigned int inusecheck; + unsigned int inuse; + unsigned int check; + + send_idx = ( send_buf & ~LINDA_SEND_BUF_TOGGLE ); + send_check = ( !! ( send_buf & LINDA_SEND_BUF_TOGGLE ) ); + inusecheck = BIT_GET ( linda->sendbufavail, InUseCheck[send_idx] ); + inuse = ( !! ( inusecheck & 0x02 ) ); + check = ( !! ( inusecheck & 0x01 ) ); + return ( inuse || ( check != send_check ) ); +} + +/** + * Calculate starting offset for send buffer + * + * @v linda Linda device + * @v send_buf Send buffer + * @ret offset Starting offset + */ +static unsigned long linda_send_buffer_offset ( struct linda *linda, + unsigned int send_buf ) { + return ( linda->send_buffer_base + + ( ( send_buf & ~LINDA_SEND_BUF_TOGGLE ) * + LINDA_SEND_BUF_SIZE ) ); +} + +/** + * Create send work queue + * + * @v linda Linda device + * @v qp Queue pair + */ +static int linda_create_send_wq ( struct linda *linda, + struct ib_queue_pair *qp ) { + struct ib_work_queue *wq = &qp->send; + struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq ); + int rc; + + /* Reserve send buffers */ + if ( ( linda->reserved_send_bufs + qp->send.num_wqes ) > + LINDA_MAX_SEND_BUFS ) { + DBGC ( linda, "Linda %p out of send buffers (have %d, used " + "%d, need %d)\n", linda, LINDA_MAX_SEND_BUFS, + linda->reserved_send_bufs, qp->send.num_wqes ); + rc = -ENOBUFS; + goto err_reserve_bufs; + } + linda->reserved_send_bufs += qp->send.num_wqes; + + /* Reset work queue */ + linda_wq->prod = 0; + linda_wq->cons = 0; + + /* Allocate space for send buffer uasge list */ + linda_wq->send_buf = zalloc ( qp->send.num_wqes * + sizeof ( linda_wq->send_buf[0] ) ); + if ( ! linda_wq->send_buf ) { + rc = -ENOBUFS; + goto err_alloc_send_buf; + } + + return 0; + + free ( linda_wq->send_buf ); + err_alloc_send_buf: + linda->reserved_send_bufs -= qp->send.num_wqes; + err_reserve_bufs: + return rc; +} + +/** + * Destroy send work queue + * + * @v linda Linda device + * @v qp Queue pair + */ +static void linda_destroy_send_wq ( struct linda *linda, + struct ib_queue_pair *qp ) { + struct ib_work_queue *wq = &qp->send; + struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq ); + + free ( linda_wq->send_buf ); + linda->reserved_send_bufs -= qp->send.num_wqes; +} + +/** + * Initialise send datapath + * + * @v linda Linda device + * @ret rc Return status code + */ +static int linda_init_send ( struct linda *linda ) { + struct QIB_7220_SendBufBase sendbufbase; + struct QIB_7220_SendBufAvailAddr sendbufavailaddr; + struct QIB_7220_SendCtrl sendctrl; + unsigned int i; + int rc; + + /* Retrieve SendBufBase */ + linda_readq ( linda, &sendbufbase, QIB_7220_SendBufBase_offset ); + linda->send_buffer_base = BIT_GET ( &sendbufbase, + BaseAddr_SmallPIO ); + DBGC ( linda, "Linda %p send buffers at %lx\n", + linda, linda->send_buffer_base ); + + /* Initialise the send_buf[] array */ + for ( i = 0 ; i < LINDA_MAX_SEND_BUFS ; i++ ) + linda->send_buf[i] = i; + + /* Allocate space for the SendBufAvail array */ + linda->sendbufavail = malloc_dma ( sizeof ( *linda->sendbufavail ), + LINDA_SENDBUFAVAIL_ALIGN ); + if ( ! linda->sendbufavail ) { + rc = -ENOMEM; + goto err_alloc_sendbufavail; + } + memset ( linda->sendbufavail, 0, sizeof ( linda->sendbufavail ) ); + + /* Program SendBufAvailAddr into the hardware */ + memset ( &sendbufavailaddr, 0, sizeof ( sendbufavailaddr ) ); + BIT_FILL_1 ( &sendbufavailaddr, SendBufAvailAddr, + ( virt_to_bus ( linda->sendbufavail ) >> 6 ) ); + linda_writeq ( linda, &sendbufavailaddr, + QIB_7220_SendBufAvailAddr_offset ); + + /* Enable sending and DMA of SendBufAvail */ + memset ( &sendctrl, 0, sizeof ( sendctrl ) ); + BIT_FILL_2 ( &sendctrl, + SendBufAvailUpd, 1, + SPioEnable, 1 ); + linda_writeq ( linda, &sendctrl, QIB_7220_SendCtrl_offset ); + + return 0; + + free_dma ( linda->sendbufavail, sizeof ( *linda->sendbufavail ) ); + err_alloc_sendbufavail: + return rc; +} + +/** + * Shut down send datapath + * + * @v linda Linda device + */ +static void linda_fini_send ( struct linda *linda ) { + struct QIB_7220_SendCtrl sendctrl; + + /* Disable sending and DMA of SendBufAvail */ + memset ( &sendctrl, 0, sizeof ( sendctrl ) ); + linda_writeq ( linda, &sendctrl, QIB_7220_SendCtrl_offset ); + mb(); + + /* Ensure hardware has seen this disable */ + linda_readq ( linda, &sendctrl, QIB_7220_SendCtrl_offset ); + + free_dma ( linda->sendbufavail, sizeof ( *linda->sendbufavail ) ); +} + +/*************************************************************************** + * + * Receive datapath + * + *************************************************************************** + */ + +/** + * Create receive work queue + * + * @v linda Linda device + * @v qp Queue pair + * @ret rc Return status code + */ +static int linda_create_recv_wq ( struct linda *linda, + struct ib_queue_pair *qp ) { + struct ib_work_queue *wq = &qp->recv; + struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq ); + struct QIB_7220_RcvHdrAddr0 rcvhdraddr; + struct QIB_7220_RcvHdrTailAddr0 rcvhdrtailaddr; + struct QIB_7220_RcvHdrHead0 rcvhdrhead; + struct QIB_7220_scalar rcvegrindexhead; + struct QIB_7220_RcvCtrl rcvctrl; + unsigned int ctx = linda_qpn_to_ctx ( qp->qpn ); + int rc; + + /* Reset context information */ + memset ( &linda_wq->header_prod, 0, + sizeof ( linda_wq->header_prod ) ); + linda_wq->header_cons = 0; + linda_wq->eager_prod = 0; + linda_wq->eager_cons = 0; + + /* Allocate receive header buffer */ + linda_wq->header = malloc_dma ( LINDA_RECV_HEADERS_SIZE, + LINDA_RECV_HEADERS_ALIGN ); + if ( ! linda_wq->header ) { + rc = -ENOMEM; + goto err_alloc_header; + } + + /* Enable context in hardware */ + memset ( &rcvhdraddr, 0, sizeof ( rcvhdraddr ) ); + BIT_FILL_1 ( &rcvhdraddr, RcvHdrAddr0, + ( virt_to_bus ( linda_wq->header ) >> 2 ) ); + linda_writeq_array8b ( linda, &rcvhdraddr, + QIB_7220_RcvHdrAddr0_offset, ctx ); + memset ( &rcvhdrtailaddr, 0, sizeof ( rcvhdrtailaddr ) ); + BIT_FILL_1 ( &rcvhdrtailaddr, RcvHdrTailAddr0, + ( virt_to_bus ( &linda_wq->header_prod ) >> 2 ) ); + linda_writeq_array8b ( linda, &rcvhdrtailaddr, + QIB_7220_RcvHdrTailAddr0_offset, ctx ); + memset ( &rcvhdrhead, 0, sizeof ( rcvhdrhead ) ); + BIT_FILL_1 ( &rcvhdrhead, counter, 1 ); + linda_writeq_array64k ( linda, &rcvhdrhead, + QIB_7220_RcvHdrHead0_offset, ctx ); + memset ( &rcvegrindexhead, 0, sizeof ( rcvegrindexhead ) ); + BIT_FILL_1 ( &rcvegrindexhead, Value, 1 ); + linda_writeq_array64k ( linda, &rcvegrindexhead, + QIB_7220_RcvEgrIndexHead0_offset, ctx ); + linda_readq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset ); + BIT_SET ( &rcvctrl, PortEnable[ctx], 1 ); + BIT_SET ( &rcvctrl, IntrAvail[ctx], 1 ); + linda_writeq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset ); + + DBGC ( linda, "Linda %p QPN %ld CTX %d hdrs [%lx,%lx) prod %lx\n", + linda, qp->qpn, ctx, virt_to_bus ( linda_wq->header ), + ( virt_to_bus ( linda_wq->header ) + LINDA_RECV_HEADERS_SIZE ), + virt_to_bus ( &linda_wq->header_prod ) ); + return 0; + + free_dma ( linda_wq->header, LINDA_RECV_HEADERS_SIZE ); + err_alloc_header: + return rc; +} + +/** + * Destroy receive work queue + * + * @v linda Linda device + * @v qp Queue pair + */ +static void linda_destroy_recv_wq ( struct linda *linda, + struct ib_queue_pair *qp ) { + struct ib_work_queue *wq = &qp->recv; + struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq ); + struct QIB_7220_RcvCtrl rcvctrl; + unsigned int ctx = linda_qpn_to_ctx ( qp->qpn ); + + /* Disable context in hardware */ + linda_readq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset ); + BIT_SET ( &rcvctrl, PortEnable[ctx], 0 ); + BIT_SET ( &rcvctrl, IntrAvail[ctx], 0 ); + linda_writeq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset ); + + /* Make sure the hardware has seen that the context is disabled */ + linda_readq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset ); + mb(); + + /* Free headers ring */ + free_dma ( linda_wq->header, LINDA_RECV_HEADERS_SIZE ); + + /* Free context */ + linda_free_ctx ( linda, ctx ); +} + +/** + * Initialise receive datapath + * + * @v linda Linda device + * @ret rc Return status code + */ +static int linda_init_recv ( struct linda *linda ) { + struct QIB_7220_RcvCtrl rcvctrl; + struct QIB_7220_scalar rcvegrbase; + struct QIB_7220_scalar rcvhdrentsize; + struct QIB_7220_scalar rcvhdrcnt; + struct QIB_7220_RcvBTHQP rcvbthqp; + unsigned int portcfg; + unsigned long egrbase; + unsigned int eager_array_size_0; + unsigned int eager_array_size_other; + unsigned int ctx; + + /* Select configuration based on number of contexts */ + switch ( LINDA_NUM_CONTEXTS ) { + case 5: + portcfg = LINDA_PORTCFG_5CTX; + eager_array_size_0 = LINDA_EAGER_ARRAY_SIZE_5CTX_0; + eager_array_size_other = LINDA_EAGER_ARRAY_SIZE_5CTX_OTHER; + break; + case 9: + portcfg = LINDA_PORTCFG_9CTX; + eager_array_size_0 = LINDA_EAGER_ARRAY_SIZE_9CTX_0; + eager_array_size_other = LINDA_EAGER_ARRAY_SIZE_9CTX_OTHER; + break; + case 17: + portcfg = LINDA_PORTCFG_17CTX; + eager_array_size_0 = LINDA_EAGER_ARRAY_SIZE_17CTX_0; + eager_array_size_other = LINDA_EAGER_ARRAY_SIZE_17CTX_OTHER; + break; + default: + linker_assert ( 0, invalid_LINDA_NUM_CONTEXTS ); + return -EINVAL; + } + + /* Configure number of contexts */ + memset ( &rcvctrl, 0, sizeof ( rcvctrl ) ); + BIT_FILL_3 ( &rcvctrl, + TailUpd, 1, + PortCfg, portcfg, + RcvQPMapEnable, 1 ); + linda_writeq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset ); + + /* Configure receive header buffer sizes */ + memset ( &rcvhdrcnt, 0, sizeof ( rcvhdrcnt ) ); + BIT_FILL_1 ( &rcvhdrcnt, Value, LINDA_RECV_HEADER_COUNT ); + linda_writeq ( linda, &rcvhdrcnt, QIB_7220_RcvHdrCnt_offset ); + memset ( &rcvhdrentsize, 0, sizeof ( rcvhdrentsize ) ); + BIT_FILL_1 ( &rcvhdrentsize, Value, ( LINDA_RECV_HEADER_SIZE >> 2 ) ); + linda_writeq ( linda, &rcvhdrentsize, QIB_7220_RcvHdrEntSize_offset ); + + /* Calculate eager array start addresses for each context */ + linda_readq ( linda, &rcvegrbase, QIB_7220_RcvEgrBase_offset ); + egrbase = BIT_GET ( &rcvegrbase, Value ); + linda->recv_wq[0].eager_array = egrbase; + linda->recv_wq[0].eager_entries = eager_array_size_0; + egrbase += ( eager_array_size_0 * sizeof ( struct QIB_7220_RcvEgr ) ); + for ( ctx = 1 ; ctx < LINDA_NUM_CONTEXTS ; ctx++ ) { + linda->recv_wq[ctx].eager_array = egrbase; + linda->recv_wq[ctx].eager_entries = eager_array_size_other; + egrbase += ( eager_array_size_other * + sizeof ( struct QIB_7220_RcvEgr ) ); + } + for ( ctx = 0 ; ctx < LINDA_NUM_CONTEXTS ; ctx++ ) { + DBGC ( linda, "Linda %p CTX %d eager array at %lx (%d " + "entries)\n", linda, ctx, + linda->recv_wq[ctx].eager_array, + linda->recv_wq[ctx].eager_entries ); + } + + /* Set the BTH QP for Infinipath packets to an unused value */ + memset ( &rcvbthqp, 0, sizeof ( rcvbthqp ) ); + BIT_FILL_1 ( &rcvbthqp, RcvBTHQP, LINDA_QP_IDETH ); + linda_writeq ( linda, &rcvbthqp, QIB_7220_RcvBTHQP_offset ); + + return 0; +} + +/** + * Shut down receive datapath + * + * @v linda Linda device + */ +static void linda_fini_recv ( struct linda *linda __unused ) { + /* Nothing to do; all contexts were already disabled when the + * queue pairs were destroyed + */ +} + +/*************************************************************************** + * + * Completion queue operations + * + *************************************************************************** + */ + +/** + * Create completion queue + * + * @v ibdev Infiniband device + * @v cq Completion queue + * @ret rc Return status code + */ +static int linda_create_cq ( struct ib_device *ibdev, + struct ib_completion_queue *cq ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + static int cqn; + + /* The hardware has no concept of completion queues. We + * simply use the association between CQs and WQs (already + * handled by the IB core) to decide which WQs to poll. + * + * We do set a CQN, just to avoid confusing debug messages + * from the IB core. + */ + cq->cqn = ++cqn; + DBGC ( linda, "Linda %p CQN %ld created\n", linda, cq->cqn ); + + return 0; +} + +/** + * Destroy completion queue + * + * @v ibdev Infiniband device + * @v cq Completion queue + */ +static void linda_destroy_cq ( struct ib_device *ibdev, + struct ib_completion_queue *cq ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + + /* Nothing to do */ + DBGC ( linda, "Linda %p CQN %ld destroyed\n", linda, cq->cqn ); +} + +/*************************************************************************** + * + * Queue pair operations + * + *************************************************************************** + */ + +/** + * Create queue pair + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @ret rc Return status code + */ +static int linda_create_qp ( struct ib_device *ibdev, + struct ib_queue_pair *qp ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + int ctx; + int rc; + + /* Locate an available context */ + ctx = linda_alloc_ctx ( linda ); + if ( ctx < 0 ) { + rc = ctx; + goto err_alloc_ctx; + } + + /* Set queue pair number based on context index */ + qp->qpn = linda_ctx_to_qpn ( ctx ); + + /* Set work-queue private data pointers */ + ib_wq_set_drvdata ( &qp->send, &linda->send_wq[ctx] ); + ib_wq_set_drvdata ( &qp->recv, &linda->recv_wq[ctx] ); + + /* Create receive work queue */ + if ( ( rc = linda_create_recv_wq ( linda, qp ) ) != 0 ) + goto err_create_recv_wq; + + /* Create send work queue */ + if ( ( rc = linda_create_send_wq ( linda, qp ) ) != 0 ) + goto err_create_send_wq; + + return 0; + + linda_destroy_send_wq ( linda, qp ); + err_create_send_wq: + linda_destroy_recv_wq ( linda, qp ); + err_create_recv_wq: + linda_free_ctx ( linda, ctx ); + err_alloc_ctx: + return rc; +} + +/** + * Modify queue pair + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v mod_list Modification list + * @ret rc Return status code + */ +static int linda_modify_qp ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + unsigned long mod_list __unused ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + + /* Nothing to do; the hardware doesn't have a notion of queue + * keys + */ + DBGC ( linda, "Linda %p QPN %ld modified\n", linda, qp->qpn ); + return 0; +} + +/** + * Destroy queue pair + * + * @v ibdev Infiniband device + * @v qp Queue pair + */ +static void linda_destroy_qp ( struct ib_device *ibdev, + struct ib_queue_pair *qp ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + + linda_destroy_send_wq ( linda, qp ); + linda_destroy_recv_wq ( linda, qp ); +} + +/*************************************************************************** + * + * Work request operations + * + *************************************************************************** + */ + +/** + * Post send work queue entry + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v av Address vector + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int linda_post_send ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + struct ib_address_vector *av, + struct io_buffer *iobuf ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct ib_work_queue *wq = &qp->send; + struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq ); + struct QIB_7220_SendPbc sendpbc; + uint8_t header_buf[IB_MAX_HEADER_SIZE]; + struct io_buffer headers; + unsigned int send_buf; + unsigned long start_offset; + unsigned long offset; + size_t len; + ssize_t frag_len; + uint32_t *data; + + /* Allocate send buffer and calculate offset */ + send_buf = linda_alloc_send_buf ( linda ); + start_offset = offset = linda_send_buffer_offset ( linda, send_buf ); + + /* Store I/O buffer and send buffer index */ + assert ( wq->iobufs[linda_wq->prod] == NULL ); + wq->iobufs[linda_wq->prod] = iobuf; + linda_wq->send_buf[linda_wq->prod] = send_buf; + + /* Construct headers */ + iob_populate ( &headers, header_buf, 0, sizeof ( header_buf ) ); + iob_reserve ( &headers, sizeof ( header_buf ) ); + ib_push ( ibdev, &headers, qp, iob_len ( iobuf ), av ); + + /* Calculate packet length */ + len = ( ( sizeof ( sendpbc ) + iob_len ( &headers ) + + iob_len ( iobuf ) + 3 ) & ~3 ); + + /* Construct send per-buffer control word */ + memset ( &sendpbc, 0, sizeof ( sendpbc ) ); + BIT_FILL_2 ( &sendpbc, + LengthP1_toibc, ( ( len >> 2 ) - 1 ), + VL15, 1 ); + + /* Write SendPbc */ + DBG_DISABLE ( DBGLVL_IO ); + linda_writeq ( linda, &sendpbc, offset ); + offset += sizeof ( sendpbc ); + + /* Write headers */ + for ( data = headers.data, frag_len = iob_len ( &headers ) ; + frag_len > 0 ; data++, offset += 4, frag_len -= 4 ) { + linda_writel ( linda, *data, offset ); + } + + /* Write data */ + for ( data = iobuf->data, frag_len = iob_len ( iobuf ) ; + frag_len > 0 ; data++, offset += 4, frag_len -= 4 ) { + linda_writel ( linda, *data, offset ); + } + DBG_ENABLE ( DBGLVL_IO ); + + assert ( ( start_offset + len ) == offset ); + DBGC2 ( linda, "Linda %p QPN %ld TX %d(%d) posted [%lx,%lx)\n", + linda, qp->qpn, send_buf, linda_wq->prod, + start_offset, offset ); + + /* Increment producer counter */ + linda_wq->prod = ( ( linda_wq->prod + 1 ) & ( wq->num_wqes - 1 ) ); + + return 0; +} + +/** + * Complete send work queue entry + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v wqe_idx Work queue entry index + */ +static void linda_complete_send ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + unsigned int wqe_idx ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct ib_work_queue *wq = &qp->send; + struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq ); + struct io_buffer *iobuf; + unsigned int send_buf; + + /* Parse completion */ + send_buf = linda_wq->send_buf[wqe_idx]; + DBGC2 ( linda, "Linda %p QPN %ld TX %d(%d) complete\n", + linda, qp->qpn, send_buf, wqe_idx ); + + /* Complete work queue entry */ + iobuf = wq->iobufs[wqe_idx]; + assert ( iobuf != NULL ); + ib_complete_send ( ibdev, qp, iobuf, 0 ); + wq->iobufs[wqe_idx] = NULL; + + /* Free send buffer */ + linda_free_send_buf ( linda, send_buf ); +} + +/** + * Poll send work queue + * + * @v ibdev Infiniband device + * @v qp Queue pair + */ +static void linda_poll_send_wq ( struct ib_device *ibdev, + struct ib_queue_pair *qp ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct ib_work_queue *wq = &qp->send; + struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq ); + unsigned int send_buf; + + /* Look for completions */ + while ( wq->fill ) { + + /* Check to see if send buffer has completed */ + send_buf = linda_wq->send_buf[linda_wq->cons]; + if ( linda_send_buf_in_use ( linda, send_buf ) ) + break; + + /* Complete this buffer */ + linda_complete_send ( ibdev, qp, linda_wq->cons ); + + /* Increment consumer counter */ + linda_wq->cons = ( ( linda_wq->cons + 1 ) & + ( wq->num_wqes - 1 ) ); + } +} + +/** + * Post receive work queue entry + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int linda_post_recv ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + struct io_buffer *iobuf ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct ib_work_queue *wq = &qp->recv; + struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq ); + struct QIB_7220_RcvEgr rcvegr; + struct QIB_7220_scalar rcvegrindexhead; + unsigned int ctx = linda_qpn_to_ctx ( qp->qpn ); + physaddr_t addr; + size_t len; + unsigned int wqe_idx; + unsigned int bufsize; + + /* Sanity checks */ + addr = virt_to_bus ( iobuf->data ); + len = iob_tailroom ( iobuf ); + if ( addr & ( LINDA_EAGER_BUFFER_ALIGN - 1 ) ) { + DBGC ( linda, "Linda %p QPN %ld misaligned RX buffer " + "(%08lx)\n", linda, qp->qpn, addr ); + return -EINVAL; + } + if ( len != LINDA_RECV_PAYLOAD_SIZE ) { + DBGC ( linda, "Linda %p QPN %ld wrong RX buffer size (%d)\n", + linda, qp->qpn, len ); + return -EINVAL; + } + + /* Calculate eager producer index and WQE index */ + wqe_idx = ( linda_wq->eager_prod & ( wq->num_wqes - 1 ) ); + assert ( wq->iobufs[wqe_idx] == NULL ); + + /* Store I/O buffer */ + wq->iobufs[wqe_idx] = iobuf; + + /* Calculate buffer size */ + switch ( LINDA_RECV_PAYLOAD_SIZE ) { + case 2048: bufsize = LINDA_EAGER_BUFFER_2K; break; + case 4096: bufsize = LINDA_EAGER_BUFFER_4K; break; + case 8192: bufsize = LINDA_EAGER_BUFFER_8K; break; + case 16384: bufsize = LINDA_EAGER_BUFFER_16K; break; + case 32768: bufsize = LINDA_EAGER_BUFFER_32K; break; + case 65536: bufsize = LINDA_EAGER_BUFFER_64K; break; + default: linker_assert ( 0, invalid_rx_payload_size ); + bufsize = LINDA_EAGER_BUFFER_NONE; + } + + /* Post eager buffer */ + memset ( &rcvegr, 0, sizeof ( rcvegr ) ); + BIT_FILL_2 ( &rcvegr, + Addr, ( addr >> 11 ), + BufSize, bufsize ); + linda_writeq_array8b ( linda, &rcvegr, + linda_wq->eager_array, linda_wq->eager_prod ); + DBGC2 ( linda, "Linda %p QPN %ld RX egr %d(%d) posted [%lx,%lx)\n", + linda, qp->qpn, linda_wq->eager_prod, wqe_idx, + addr, ( addr + len ) ); + + /* Increment producer index */ + linda_wq->eager_prod = ( ( linda_wq->eager_prod + 1 ) & + ( linda_wq->eager_entries - 1 ) ); + + /* Update head index */ + memset ( &rcvegrindexhead, 0, sizeof ( rcvegrindexhead ) ); + BIT_FILL_1 ( &rcvegrindexhead, + Value, ( ( linda_wq->eager_prod + 1 ) & + ( linda_wq->eager_entries - 1 ) ) ); + linda_writeq_array64k ( linda, &rcvegrindexhead, + QIB_7220_RcvEgrIndexHead0_offset, ctx ); + + return 0; +} + +/** + * Complete receive work queue entry + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v header_offs Header offset + */ +static void linda_complete_recv ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + unsigned int header_offs ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct ib_work_queue *wq = &qp->recv; + struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq ); + struct QIB_7220_RcvHdrFlags *rcvhdrflags; + struct QIB_7220_RcvEgr rcvegr; + struct io_buffer headers; + struct io_buffer *iobuf; + struct ib_queue_pair *intended_qp; + struct ib_address_vector av; + unsigned int rcvtype; + unsigned int pktlen; + unsigned int egrindex; + unsigned int useegrbfr; + unsigned int iberr, mkerr, tiderr, khdrerr, mtuerr; + unsigned int lenerr, parityerr, vcrcerr, icrcerr; + unsigned int err; + unsigned int hdrqoffset; + unsigned int header_len; + unsigned int padded_payload_len; + unsigned int wqe_idx; + size_t payload_len; + int qp0; + int rc; + + /* RcvHdrFlags are at the end of the header entry */ + rcvhdrflags = ( linda_wq->header + header_offs + + LINDA_RECV_HEADER_SIZE - sizeof ( *rcvhdrflags ) ); + rcvtype = BIT_GET ( rcvhdrflags, RcvType ); + pktlen = ( BIT_GET ( rcvhdrflags, PktLen ) << 2 ); + egrindex = BIT_GET ( rcvhdrflags, EgrIndex ); + useegrbfr = BIT_GET ( rcvhdrflags, UseEgrBfr ); + hdrqoffset = ( BIT_GET ( rcvhdrflags, HdrqOffset ) << 2 ); + iberr = BIT_GET ( rcvhdrflags, IBErr ); + mkerr = BIT_GET ( rcvhdrflags, MKErr ); + tiderr = BIT_GET ( rcvhdrflags, TIDErr ); + khdrerr = BIT_GET ( rcvhdrflags, KHdrErr ); + mtuerr = BIT_GET ( rcvhdrflags, MTUErr ); + lenerr = BIT_GET ( rcvhdrflags, LenErr ); + parityerr = BIT_GET ( rcvhdrflags, ParityErr ); + vcrcerr = BIT_GET ( rcvhdrflags, VCRCErr ); + icrcerr = BIT_GET ( rcvhdrflags, ICRCErr ); + header_len = ( LINDA_RECV_HEADER_SIZE - hdrqoffset - + sizeof ( *rcvhdrflags ) ); + padded_payload_len = ( pktlen - header_len - 4 /* ICRC */ ); + err = ( iberr | mkerr | tiderr | khdrerr | mtuerr | + lenerr | parityerr | vcrcerr | icrcerr ); + /* IB header is placed immediately before RcvHdrFlags */ + iob_populate ( &headers, ( ( ( void * ) rcvhdrflags ) - header_len ), + header_len, header_len ); + + /* Dump diagnostic information */ + if ( err || ( ! useegrbfr ) ) { + DBGC ( linda, "Linda %p QPN %ld RX egr %d%s hdr %d type %d " + "len %d(%d+%d+4)%s%s%s%s%s%s%s%s%s%s%s\n", linda, + qp->qpn, egrindex, ( useegrbfr ? "" : "(unused)" ), + ( header_offs / LINDA_RECV_HEADER_SIZE ), rcvtype, + pktlen, header_len, padded_payload_len, + ( err ? " [Err" : "" ), ( iberr ? " IB" : "" ), + ( mkerr ? " MK" : "" ), ( tiderr ? " TID" : "" ), + ( khdrerr ? " KHdr" : "" ), ( mtuerr ? " MTU" : "" ), + ( lenerr ? " Len" : "" ), ( parityerr ? " Parity" : ""), + ( vcrcerr ? " VCRC" : "" ), ( icrcerr ? " ICRC" : "" ), + ( err ? "]" : "" ) ); + } else { + DBGC2 ( linda, "Linda %p QPN %ld RX egr %d hdr %d type %d " + "len %d(%d+%d+4)\n", linda, qp->qpn, egrindex, + ( header_offs / LINDA_RECV_HEADER_SIZE ), rcvtype, + pktlen, header_len, padded_payload_len ); + } + DBGCP_HDA ( linda, hdrqoffset, headers.data, + ( header_len + sizeof ( *rcvhdrflags ) ) ); + + /* Parse header to generate address vector */ + qp0 = ( qp->qpn == 0 ); + intended_qp = NULL; + if ( ( rc = ib_pull ( ibdev, &headers, ( qp0 ? &intended_qp : NULL ), + &payload_len, &av ) ) != 0 ) { + DBGC ( linda, "Linda %p could not parse headers: %s\n", + linda, strerror ( rc ) ); + err = 1; + } + if ( ! intended_qp ) + intended_qp = qp; + + /* Complete this buffer and any skipped buffers. Note that + * when the hardware runs out of buffers, it will repeatedly + * report the same buffer (the tail) as a TID error, and that + * it also has a habit of sometimes skipping over several + * buffers at once. + */ + while ( 1 ) { + + /* If we have caught up to the producer counter, stop. + * This will happen when the hardware first runs out + * of buffers and starts reporting TID errors against + * the eager buffer it wants to use next. + */ + if ( linda_wq->eager_cons == linda_wq->eager_prod ) + break; + + /* If we have caught up to where we should be after + * completing this egrindex, stop. We phrase the test + * this way to avoid completing the entire ring when + * we receive the same egrindex twice in a row. + */ + if ( ( linda_wq->eager_cons == + ( ( egrindex + 1 ) & ( linda_wq->eager_entries - 1 ) ))) + break; + + /* Identify work queue entry and corresponding I/O + * buffer. + */ + wqe_idx = ( linda_wq->eager_cons & ( wq->num_wqes - 1 ) ); + iobuf = wq->iobufs[wqe_idx]; + assert ( iobuf != NULL ); + wq->iobufs[wqe_idx] = NULL; + + /* Complete the eager buffer */ + if ( linda_wq->eager_cons == egrindex ) { + /* Completing the eager buffer described in + * this header entry. + */ + iob_put ( iobuf, payload_len ); + rc = ( err ? -EIO : ( useegrbfr ? 0 : -ECANCELED ) ); + /* Redirect to target QP if necessary */ + if ( qp != intended_qp ) { + DBGC ( linda, "Linda %p redirecting QPN %ld " + "=> %ld\n", + linda, qp->qpn, intended_qp->qpn ); + /* Compensate for incorrect fill levels */ + qp->recv.fill--; + intended_qp->recv.fill++; + } + ib_complete_recv ( ibdev, intended_qp, &av, iobuf, rc); + } else { + /* Completing on a skipped-over eager buffer */ + ib_complete_recv ( ibdev, qp, &av, iobuf, -ECANCELED ); + } + + /* Clear eager buffer */ + memset ( &rcvegr, 0, sizeof ( rcvegr ) ); + linda_writeq_array8b ( linda, &rcvegr, linda_wq->eager_array, + linda_wq->eager_cons ); + + /* Increment consumer index */ + linda_wq->eager_cons = ( ( linda_wq->eager_cons + 1 ) & + ( linda_wq->eager_entries - 1 ) ); + } +} + +/** + * Poll receive work queue + * + * @v ibdev Infiniband device + * @v qp Queue pair + */ +static void linda_poll_recv_wq ( struct ib_device *ibdev, + struct ib_queue_pair *qp ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct ib_work_queue *wq = &qp->recv; + struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq ); + struct QIB_7220_RcvHdrHead0 rcvhdrhead; + unsigned int ctx = linda_qpn_to_ctx ( qp->qpn ); + unsigned int header_prod; + + /* Check for received packets */ + header_prod = ( BIT_GET ( &linda_wq->header_prod, Value ) << 2 ); + if ( header_prod == linda_wq->header_cons ) + return; + + /* Process all received packets */ + while ( linda_wq->header_cons != header_prod ) { + + /* Complete the receive */ + linda_complete_recv ( ibdev, qp, linda_wq->header_cons ); + + /* Increment the consumer offset */ + linda_wq->header_cons += LINDA_RECV_HEADER_SIZE; + linda_wq->header_cons %= LINDA_RECV_HEADERS_SIZE; + } + + /* Update consumer offset */ + memset ( &rcvhdrhead, 0, sizeof ( rcvhdrhead ) ); + BIT_FILL_2 ( &rcvhdrhead, + RcvHeadPointer, ( linda_wq->header_cons >> 2 ), + counter, 1 ); + linda_writeq_array64k ( linda, &rcvhdrhead, + QIB_7220_RcvHdrHead0_offset, ctx ); +} + +/** + * Poll completion queue + * + * @v ibdev Infiniband device + * @v cq Completion queue + */ +static void linda_poll_cq ( struct ib_device *ibdev, + struct ib_completion_queue *cq ) { + struct ib_work_queue *wq; + + /* Poll associated send and receive queues */ + list_for_each_entry ( wq, &cq->work_queues, list ) { + if ( wq->is_send ) { + linda_poll_send_wq ( ibdev, wq->qp ); + } else { + linda_poll_recv_wq ( ibdev, wq->qp ); + } + } +} + +/*************************************************************************** + * + * Event queues + * + *************************************************************************** + */ + +/** + * Poll event queue + * + * @v ibdev Infiniband device + */ +static void linda_poll_eq ( struct ib_device *ibdev ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct QIB_7220_ErrStatus errstatus; + struct QIB_7220_ErrClear errclear; + + /* Check for link status changes */ + DBG_DISABLE ( DBGLVL_IO ); + linda_readq ( linda, &errstatus, QIB_7220_ErrStatus_offset ); + DBG_ENABLE ( DBGLVL_IO ); + if ( BIT_GET ( &errstatus, IBStatusChanged ) ) { + linda_link_state_changed ( ibdev ); + memset ( &errclear, 0, sizeof ( errclear ) ); + BIT_FILL_1 ( &errclear, IBStatusChangedClear, 1 ); + linda_writeq ( linda, &errclear, QIB_7220_ErrClear_offset ); + } +} + +/*************************************************************************** + * + * Infiniband link-layer operations + * + *************************************************************************** + */ + +/** + * Initialise Infiniband link + * + * @v ibdev Infiniband device + * @ret rc Return status code + */ +static int linda_open ( struct ib_device *ibdev ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct QIB_7220_Control control; + + /* Disable link */ + linda_readq ( linda, &control, QIB_7220_Control_offset ); + BIT_SET ( &control, LinkEn, 1 ); + linda_writeq ( linda, &control, QIB_7220_Control_offset ); + return 0; +} + +/** + * Close Infiniband link + * + * @v ibdev Infiniband device + */ +static void linda_close ( struct ib_device *ibdev ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct QIB_7220_Control control; + + /* Disable link */ + linda_readq ( linda, &control, QIB_7220_Control_offset ); + BIT_SET ( &control, LinkEn, 0 ); + linda_writeq ( linda, &control, QIB_7220_Control_offset ); +} + +/*************************************************************************** + * + * Multicast group operations + * + *************************************************************************** + */ + +/** + * Attach to multicast group + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v gid Multicast GID + * @ret rc Return status code + */ +static int linda_mcast_attach ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + struct ib_gid *gid ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + + ( void ) linda; + ( void ) qp; + ( void ) gid; + return 0; +} + +/** + * Detach from multicast group + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v gid Multicast GID + */ +static void linda_mcast_detach ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + struct ib_gid *gid ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + + ( void ) linda; + ( void ) qp; + ( void ) gid; +} + +/** Linda Infiniband operations */ +static struct ib_device_operations linda_ib_operations = { + .create_cq = linda_create_cq, + .destroy_cq = linda_destroy_cq, + .create_qp = linda_create_qp, + .modify_qp = linda_modify_qp, + .destroy_qp = linda_destroy_qp, + .post_send = linda_post_send, + .post_recv = linda_post_recv, + .poll_cq = linda_poll_cq, + .poll_eq = linda_poll_eq, + .open = linda_open, + .close = linda_close, + .mcast_attach = linda_mcast_attach, + .mcast_detach = linda_mcast_detach, +}; + +/*************************************************************************** + * + * I2C bus operations + * + *************************************************************************** + */ + +/** Linda I2C bit to GPIO mappings */ +static unsigned int linda_i2c_bits[] = { + [I2C_BIT_SCL] = ( 1 << LINDA_GPIO_SCL ), + [I2C_BIT_SDA] = ( 1 << LINDA_GPIO_SDA ), +}; + +/** + * Read Linda I2C line status + * + * @v basher Bit-bashing interface + * @v bit_id Bit number + * @ret zero Input is a logic 0 + * @ret non-zero Input is a logic 1 + */ +static int linda_i2c_read_bit ( struct bit_basher *basher, + unsigned int bit_id ) { + struct linda *linda = + container_of ( basher, struct linda, i2c.basher ); + struct QIB_7220_EXTStatus extstatus; + unsigned int status; + + DBG_DISABLE ( DBGLVL_IO ); + + linda_readq ( linda, &extstatus, QIB_7220_EXTStatus_offset ); + status = ( BIT_GET ( &extstatus, GPIOIn ) & linda_i2c_bits[bit_id] ); + + DBG_ENABLE ( DBGLVL_IO ); + + return status; +} + +/** + * Write Linda I2C line status + * + * @v basher Bit-bashing interface + * @v bit_id Bit number + * @v data Value to write + */ +static void linda_i2c_write_bit ( struct bit_basher *basher, + unsigned int bit_id, unsigned long data ) { + struct linda *linda = + container_of ( basher, struct linda, i2c.basher ); + struct QIB_7220_EXTCtrl extctrl; + struct QIB_7220_GPIO gpioout; + unsigned int bit = linda_i2c_bits[bit_id]; + unsigned int outputs = 0; + unsigned int output_enables = 0; + + DBG_DISABLE ( DBGLVL_IO ); + + /* Read current GPIO mask and outputs */ + linda_readq ( linda, &extctrl, QIB_7220_EXTCtrl_offset ); + linda_readq ( linda, &gpioout, QIB_7220_GPIOOut_offset ); + + /* Update outputs and output enables. I2C lines are tied + * high, so we always set the output to 0 and use the output + * enable to control the line. + */ + output_enables = BIT_GET ( &extctrl, GPIOOe ); + output_enables = ( ( output_enables & ~bit ) | ( ~data & bit ) ); + outputs = BIT_GET ( &gpioout, GPIO ); + outputs = ( outputs & ~bit ); + BIT_SET ( &extctrl, GPIOOe, output_enables ); + BIT_SET ( &gpioout, GPIO, outputs ); + + /* Write the output enable first; that way we avoid logic + * hazards. + */ + linda_writeq ( linda, &extctrl, QIB_7220_EXTCtrl_offset ); + linda_writeq ( linda, &gpioout, QIB_7220_GPIOOut_offset ); + mb(); + + DBG_ENABLE ( DBGLVL_IO ); +} + +/** Linda I2C bit-bashing interface operations */ +static struct bit_basher_operations linda_i2c_basher_ops = { + .read = linda_i2c_read_bit, + .write = linda_i2c_write_bit, +}; + +/** + * Initialise Linda I2C subsystem + * + * @v linda Linda device + * @ret rc Return status code + */ +static int linda_init_i2c ( struct linda *linda ) { + static int try_eeprom_address[] = { 0x51, 0x50 }; + unsigned int i; + int rc; + + /* Initialise bus */ + if ( ( rc = init_i2c_bit_basher ( &linda->i2c, + &linda_i2c_basher_ops ) ) != 0 ) { + DBGC ( linda, "Linda %p could not initialise I2C bus: %s\n", + linda, strerror ( rc ) ); + return rc; + } + + /* Probe for devices */ + for ( i = 0 ; i < ( sizeof ( try_eeprom_address ) / + sizeof ( try_eeprom_address[0] ) ) ; i++ ) { + init_i2c_eeprom ( &linda->eeprom, try_eeprom_address[i] ); + if ( ( rc = i2c_check_presence ( &linda->i2c.i2c, + &linda->eeprom ) ) == 0 ) { + DBGC2 ( linda, "Linda %p found EEPROM at %02x\n", + linda, try_eeprom_address[i] ); + return 0; + } + } + + DBGC ( linda, "Linda %p could not find EEPROM\n", linda ); + return -ENODEV; +} + +/** + * Read EEPROM parameters + * + * @v linda Linda device + * @v guid GUID to fill in + * @ret rc Return status code + */ +static int linda_read_eeprom ( struct linda *linda, + struct ib_gid_half *guid ) { + struct i2c_interface *i2c = &linda->i2c.i2c; + int rc; + + /* Read GUID */ + if ( ( rc = i2c->read ( i2c, &linda->eeprom, LINDA_EEPROM_GUID_OFFSET, + guid->bytes, sizeof ( *guid ) ) ) != 0 ) { + DBGC ( linda, "Linda %p could not read GUID: %s\n", + linda, strerror ( rc ) ); + return rc; + } + DBGC2 ( linda, "Linda %p has GUID %02x:%02x:%02x:%02x:%02x:%02x:" + "%02x:%02x\n", linda, guid->bytes[0], guid->bytes[1], + guid->bytes[2], guid->bytes[3], guid->bytes[4], + guid->bytes[5], guid->bytes[6], guid->bytes[7] ); + + /* Read serial number (debug only) */ + if ( DBG_LOG ) { + uint8_t serial[LINDA_EEPROM_SERIAL_SIZE + 1]; + + serial[ sizeof ( serial ) - 1 ] = '\0'; + if ( ( rc = i2c->read ( i2c, &linda->eeprom, + LINDA_EEPROM_SERIAL_OFFSET, serial, + ( sizeof ( serial ) - 1 ) ) ) != 0 ) { + DBGC ( linda, "Linda %p could not read serial: %s\n", + linda, strerror ( rc ) ); + return rc; + } + DBGC2 ( linda, "Linda %p has serial number \"%s\"\n", + linda, serial ); + } + + return 0; +} + +/*************************************************************************** + * + * External parallel bus access + * + *************************************************************************** + */ + +/** + * Request ownership of the IB external parallel bus + * + * @v linda Linda device + * @ret rc Return status code + */ +static int linda_ib_epb_request ( struct linda *linda ) { + struct QIB_7220_ibsd_epb_access_ctrl access; + unsigned int i; + + /* Request ownership */ + memset ( &access, 0, sizeof ( access ) ); + BIT_FILL_1 ( &access, sw_ib_epb_req, 1 ); + linda_writeq ( linda, &access, QIB_7220_ibsd_epb_access_ctrl_offset ); + + /* Wait for ownership to be granted */ + for ( i = 0 ; i < LINDA_EPB_REQUEST_MAX_WAIT_US ; i++ ) { + linda_readq ( linda, &access, + QIB_7220_ibsd_epb_access_ctrl_offset ); + if ( BIT_GET ( &access, sw_ib_epb_req_granted ) ) + return 0; + udelay ( 1 ); + } + + DBGC ( linda, "Linda %p timed out waiting for IB EPB request\n", + linda ); + return -ETIMEDOUT; +} + +/** + * Wait for IB external parallel bus transaction to complete + * + * @v linda Linda device + * @v xact Buffer to hold transaction result + * @ret rc Return status code + */ +static int linda_ib_epb_wait ( struct linda *linda, + struct QIB_7220_ibsd_epb_transaction_reg *xact ) { + unsigned int i; + + /* Discard first read to allow for signals crossing clock domains */ + linda_readq ( linda, xact, QIB_7220_ibsd_epb_transaction_reg_offset ); + + for ( i = 0 ; i < LINDA_EPB_XACT_MAX_WAIT_US ; i++ ) { + linda_readq ( linda, xact, + QIB_7220_ibsd_epb_transaction_reg_offset ); + if ( BIT_GET ( xact, ib_epb_rdy ) ) { + if ( BIT_GET ( xact, ib_epb_req_error ) ) { + DBGC ( linda, "Linda %p EPB transaction " + "failed\n", linda ); + return -EIO; + } else { + return 0; + } + } + udelay ( 1 ); + } + + DBGC ( linda, "Linda %p timed out waiting for IB EPB transaction\n", + linda ); + return -ETIMEDOUT; +} + +/** + * Release ownership of the IB external parallel bus + * + * @v linda Linda device + */ +static void linda_ib_epb_release ( struct linda *linda ) { + struct QIB_7220_ibsd_epb_access_ctrl access; + + memset ( &access, 0, sizeof ( access ) ); + BIT_FILL_1 ( &access, sw_ib_epb_req, 0 ); + linda_writeq ( linda, &access, QIB_7220_ibsd_epb_access_ctrl_offset ); +} + +/** + * Read data via IB external parallel bus + * + * @v linda Linda device + * @v location EPB location + * @ret data Data read, or negative error + * + * You must have already acquired ownership of the IB external + * parallel bus. + */ +static int linda_ib_epb_read ( struct linda *linda, unsigned int location ) { + struct QIB_7220_ibsd_epb_transaction_reg xact; + unsigned int data; + int rc; + + /* Ensure no transaction is currently in progress */ + if ( ( rc = linda_ib_epb_wait ( linda, &xact ) ) != 0 ) + return rc; + + /* Process data */ + memset ( &xact, 0, sizeof ( xact ) ); + BIT_FILL_3 ( &xact, + ib_epb_address, LINDA_EPB_LOC_ADDRESS ( location ), + ib_epb_read_write, LINDA_EPB_READ, + ib_epb_cs, LINDA_EPB_LOC_CS ( location ) ); + linda_writeq ( linda, &xact, + QIB_7220_ibsd_epb_transaction_reg_offset ); + + /* Wait for transaction to complete */ + if ( ( rc = linda_ib_epb_wait ( linda, &xact ) ) != 0 ) + return rc; + + data = BIT_GET ( &xact, ib_epb_data ); + return data; +} + +/** + * Write data via IB external parallel bus + * + * @v linda Linda device + * @v location EPB location + * @v data Data to write + * @ret rc Return status code + * + * You must have already acquired ownership of the IB external + * parallel bus. + */ +static int linda_ib_epb_write ( struct linda *linda, unsigned int location, + unsigned int data ) { + struct QIB_7220_ibsd_epb_transaction_reg xact; + int rc; + + /* Ensure no transaction is currently in progress */ + if ( ( rc = linda_ib_epb_wait ( linda, &xact ) ) != 0 ) + return rc; + + /* Process data */ + memset ( &xact, 0, sizeof ( xact ) ); + BIT_FILL_4 ( &xact, + ib_epb_data, data, + ib_epb_address, LINDA_EPB_LOC_ADDRESS ( location ), + ib_epb_read_write, LINDA_EPB_WRITE, + ib_epb_cs, LINDA_EPB_LOC_CS ( location ) ); + linda_writeq ( linda, &xact, + QIB_7220_ibsd_epb_transaction_reg_offset ); + + /* Wait for transaction to complete */ + if ( ( rc = linda_ib_epb_wait ( linda, &xact ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Read/modify/write EPB register + * + * @v linda Linda device + * @v cs Chip select + * @v channel Channel + * @v element Element + * @v reg Register + * @v value Value to set + * @v mask Mask to apply to old value + * @ret rc Return status code + */ +static int linda_ib_epb_mod_reg ( struct linda *linda, unsigned int cs, + unsigned int channel, unsigned int element, + unsigned int reg, unsigned int value, + unsigned int mask ) { + unsigned int location; + int old_value; + int rc; + + DBG_DISABLE ( DBGLVL_IO ); + + /* Sanity check */ + assert ( ( value & mask ) == value ); + + /* Acquire bus ownership */ + if ( ( rc = linda_ib_epb_request ( linda ) ) != 0 ) + goto out; + + /* Read existing value, if necessary */ + location = LINDA_EPB_LOC ( cs, channel, element, reg ); + if ( (~mask) & 0xff ) { + old_value = linda_ib_epb_read ( linda, location ); + if ( old_value < 0 ) { + rc = old_value; + goto out_release; + } + } else { + old_value = 0; + } + + /* Update value */ + value = ( ( old_value & ~mask ) | value ); + DBGCP ( linda, "Linda %p CS %d EPB(%d,%d,%#02x) %#02x => %#02x\n", + linda, cs, channel, element, reg, old_value, value ); + if ( ( rc = linda_ib_epb_write ( linda, location, value ) ) != 0 ) + goto out_release; + + out_release: + /* Release bus */ + linda_ib_epb_release ( linda ); + out: + DBG_ENABLE ( DBGLVL_IO ); + return rc; +} + +/** + * Transfer data to/from microcontroller RAM + * + * @v linda Linda device + * @v address Starting address + * @v write Data to write, or NULL + * @v read Data to read, or NULL + * @v len Length of data + * @ret rc Return status code + */ +static int linda_ib_epb_ram_xfer ( struct linda *linda, unsigned int address, + const void *write, void *read, + size_t len ) { + unsigned int control; + unsigned int address_hi; + unsigned int address_lo; + int data; + int rc; + + DBG_DISABLE ( DBGLVL_IO ); + + assert ( ! ( write && read ) ); + assert ( ( address % LINDA_EPB_UC_CHUNK_SIZE ) == 0 ); + assert ( ( len % LINDA_EPB_UC_CHUNK_SIZE ) == 0 ); + + /* Acquire bus ownership */ + if ( ( rc = linda_ib_epb_request ( linda ) ) != 0 ) + goto out; + + /* Process data */ + while ( len ) { + + /* Reset the address for each new chunk */ + if ( ( address % LINDA_EPB_UC_CHUNK_SIZE ) == 0 ) { + + /* Write the control register */ + control = ( read ? LINDA_EPB_UC_CTL_READ : + LINDA_EPB_UC_CTL_WRITE ); + if ( ( rc = linda_ib_epb_write ( linda, + LINDA_EPB_UC_CTL, + control ) ) != 0 ) + break; + + /* Write the address registers */ + address_hi = ( address >> 8 ); + if ( ( rc = linda_ib_epb_write ( linda, + LINDA_EPB_UC_ADDR_HI, + address_hi ) ) != 0 ) + break; + address_lo = ( address & 0xff ); + if ( ( rc = linda_ib_epb_write ( linda, + LINDA_EPB_UC_ADDR_LO, + address_lo ) ) != 0 ) + break; + } + + /* Read or write the data */ + if ( read ) { + data = linda_ib_epb_read ( linda, LINDA_EPB_UC_DATA ); + if ( data < 0 ) { + rc = data; + break; + } + *( ( uint8_t * ) read++ ) = data; + } else { + data = *( ( uint8_t * ) write++ ); + if ( ( rc = linda_ib_epb_write ( linda, + LINDA_EPB_UC_DATA, + data ) ) != 0 ) + break; + } + address++; + len--; + + /* Reset the control byte after each chunk */ + if ( ( address % LINDA_EPB_UC_CHUNK_SIZE ) == 0 ) { + if ( ( rc = linda_ib_epb_write ( linda, + LINDA_EPB_UC_CTL, + 0 ) ) != 0 ) + break; + } + } + + /* Release bus */ + linda_ib_epb_release ( linda ); + + out: + DBG_ENABLE ( DBGLVL_IO ); + return rc; +} + +/*************************************************************************** + * + * Infiniband SerDes initialisation + * + *************************************************************************** + */ + +/** A Linda SerDes parameter */ +struct linda_serdes_param { + /** EPB address as constructed by LINDA_EPB_ADDRESS() */ + uint16_t address; + /** Value to set */ + uint8_t value; + /** Mask to apply to old value */ + uint8_t mask; +} __packed; + +/** Magic "all channels" channel number */ +#define LINDA_EPB_ALL_CHANNELS 31 + +/** End of SerDes parameter list marker */ +#define LINDA_SERDES_PARAM_END { 0, 0, 0 } + +/** + * Program IB SerDes register(s) + * + * @v linda Linda device + * @v param SerDes parameter + * @ret rc Return status code + */ +static int linda_set_serdes_param ( struct linda *linda, + struct linda_serdes_param *param ) { + unsigned int channel; + unsigned int channel_start; + unsigned int channel_end; + unsigned int element; + unsigned int reg; + int rc; + + /* Break down the EPB address and determine channels */ + channel = LINDA_EPB_ADDRESS_CHANNEL ( param->address ); + element = LINDA_EPB_ADDRESS_ELEMENT ( param->address ); + reg = LINDA_EPB_ADDRESS_REG ( param->address ); + if ( channel == LINDA_EPB_ALL_CHANNELS ) { + channel_start = 0; + channel_end = 3; + } else { + channel_start = channel_end = channel; + } + + /* Modify register for each specified channel */ + for ( channel = channel_start ; channel <= channel_end ; channel++ ) { + if ( ( rc = linda_ib_epb_mod_reg ( linda, LINDA_EPB_CS_SERDES, + channel, element, reg, + param->value, + param->mask ) ) != 0 ) + return rc; + } + + return 0; +} + +/** + * Program IB SerDes registers + * + * @v linda Linda device + * @v param SerDes parameters + * @v count Number of parameters + * @ret rc Return status code + */ +static int linda_set_serdes_params ( struct linda *linda, + struct linda_serdes_param *params ) { + int rc; + + for ( ; params->mask != 0 ; params++ ){ + if ( ( rc = linda_set_serdes_param ( linda, + params ) ) != 0 ) + return rc; + } + + return 0; +} + +#define LINDA_DDS_VAL( amp_d, main_d, ipst_d, ipre_d, \ + amp_s, main_s, ipst_s, ipre_s ) \ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x00 ), \ + ( ( ( amp_d & 0x1f ) << 1 ) | 1 ), 0xff }, \ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x01 ), \ + ( ( ( amp_s & 0x1f ) << 1 ) | 1 ), 0xff }, \ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x09 ), \ + ( ( main_d << 3 ) | 4 | ( ipre_d >> 2 ) ), 0xff }, \ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x0a ), \ + ( ( main_s << 3 ) | 4 | ( ipre_s >> 2 ) ), 0xff }, \ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x06 ), \ + ( ( ( ipst_d & 0xf ) << 1 ) | \ + ( ( ipre_d & 3 ) << 6 ) | 0x21 ), 0xff }, \ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x07 ), \ + ( ( ( ipst_s & 0xf ) << 1 ) | \ + ( ( ipre_s & 3 ) << 6) | 0x21 ), 0xff } + +/** + * Linda SerDes default parameters + * + * These magic start-of-day values are taken from the Linux driver. + */ +static struct linda_serdes_param linda_serdes_defaults1[] = { + /* RXHSCTRL0 */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x00 ), 0xd4, 0xff }, + /* VCDL_DAC2 */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x05 ), 0x2d, 0xff }, + /* VCDL_CTRL2 */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x08 ), 0x03, 0x0f }, + /* START_EQ1 */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x27 ), 0x10, 0xff }, + /* START_EQ2 */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x28 ), 0x30, 0xff }, + /* BACTRL */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x0e ), 0x40, 0xff }, + /* LDOUTCTRL1 */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x06 ), 0x04, 0xff }, + /* RXHSSTATUS */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x0f ), 0x04, 0xff }, + /* End of this block */ + LINDA_SERDES_PARAM_END +}; +static struct linda_serdes_param linda_serdes_defaults2[] = { + /* LDOUTCTRL1 */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x06 ), 0x00, 0xff }, + /* DDS values */ + LINDA_DDS_VAL ( 31, 19, 12, 0, 29, 22, 9, 0 ), + /* Set Rcv Eq. to Preset node */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x27 ), 0x10, 0xff }, + /* DFELTHFDR */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x08 ), 0x00, 0xff }, + /* DFELTHHDR */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x21 ), 0x00, 0xff }, + /* TLTHFDR */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x09 ), 0x02, 0xff }, + /* TLTHHDR */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x23 ), 0x02, 0xff }, + /* ZFR */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x1b ), 0x0c, 0xff }, + /* ZCNT) */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x1c ), 0x0c, 0xff }, + /* GFR */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x1e ), 0x10, 0xff }, + /* GHR */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x1f ), 0x10, 0xff }, + /* VCDL_CTRL0 toggle */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x06 ), 0x20, 0xff }, + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x06 ), 0x00, 0xff }, + /* CMUCTRL5 */ + { LINDA_EPB_ADDRESS ( 7, 0, 0x15 ), 0x80, 0xff }, + /* End of this block */ + LINDA_SERDES_PARAM_END +}; +static struct linda_serdes_param linda_serdes_defaults3[] = { + /* START_EQ1 */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x27 ), 0x00, 0x38 }, + /* End of this block */ + LINDA_SERDES_PARAM_END +}; + +/** + * Program the microcontroller RAM + * + * @v linda Linda device + * @ret rc Return status code + */ +static int linda_program_uc_ram ( struct linda *linda ) { + int rc; + + if ( ( rc = linda_ib_epb_ram_xfer ( linda, 0, linda_ib_fw, NULL, + sizeof ( linda_ib_fw ) ) ) != 0 ){ + DBGC ( linda, "Linda %p could not load IB firmware: %s\n", + linda, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Verify the microcontroller RAM + * + * @v linda Linda device + * @ret rc Return status code + */ +static int linda_verify_uc_ram ( struct linda *linda ) { + uint8_t verify[LINDA_EPB_UC_CHUNK_SIZE]; + unsigned int offset; + int rc; + + for ( offset = 0 ; offset < sizeof ( linda_ib_fw ); + offset += sizeof ( verify ) ) { + if ( ( rc = linda_ib_epb_ram_xfer ( linda, offset, + NULL, verify, + sizeof (verify) )) != 0 ){ + DBGC ( linda, "Linda %p could not read back IB " + "firmware: %s\n", linda, strerror ( rc ) ); + return rc; + } + if ( memcmp ( ( linda_ib_fw + offset ), verify, + sizeof ( verify ) ) != 0 ) { + DBGC ( linda, "Linda %p firmware verification failed " + "at offset %#x\n", linda, offset ); + DBGC_HDA ( linda, offset, ( linda_ib_fw + offset ), + sizeof ( verify ) ); + DBGC_HDA ( linda, offset, verify, sizeof ( verify ) ); + return -EIO; + } + } + + DBGC2 ( linda, "Linda %p firmware verified ok\n", linda ); + return 0; +} + +/** + * Use the microcontroller to trim the IB link + * + * @v linda Linda device + * @ret rc Return status code + */ +static int linda_trim_ib ( struct linda *linda ) { + struct QIB_7220_IBSerDesCtrl ctrl; + struct QIB_7220_IntStatus intstatus; + unsigned int i; + int rc; + + /* Bring the microcontroller out of reset */ + linda_readq ( linda, &ctrl, QIB_7220_IBSerDesCtrl_offset ); + BIT_SET ( &ctrl, ResetIB_uC_Core, 0 ); + linda_writeq ( linda, &ctrl, QIB_7220_IBSerDesCtrl_offset ); + + /* Wait for the "trim done" signal */ + for ( i = 0 ; i < LINDA_TRIM_DONE_MAX_WAIT_MS ; i++ ) { + linda_readq ( linda, &intstatus, QIB_7220_IntStatus_offset ); + if ( BIT_GET ( &intstatus, IBSerdesTrimDone ) ) { + rc = 0; + goto out_reset; + } + mdelay ( 1 ); + } + + DBGC ( linda, "Linda %p timed out waiting for trim done\n", linda ); + rc = -ETIMEDOUT; + out_reset: + /* Put the microcontroller back into reset */ + BIT_SET ( &ctrl, ResetIB_uC_Core, 1 ); + linda_writeq ( linda, &ctrl, QIB_7220_IBSerDesCtrl_offset ); + + return rc; +} + +/** + * Initialise the IB SerDes + * + * @v linda Linda device + * @ret rc Return status code + */ +static int linda_init_ib_serdes ( struct linda *linda ) { + struct QIB_7220_Control control; + struct QIB_7220_IBCCtrl ibcctrl; + struct QIB_7220_IBCDDRCtrl ibcddrctrl; + struct QIB_7220_XGXSCfg xgxscfg; + int rc; + + /* Disable link */ + linda_readq ( linda, &control, QIB_7220_Control_offset ); + BIT_SET ( &control, LinkEn, 0 ); + linda_writeq ( linda, &control, QIB_7220_Control_offset ); + + /* Configure sensible defaults for IBC */ + memset ( &ibcctrl, 0, sizeof ( ibcctrl ) ); + BIT_FILL_6 ( &ibcctrl, /* Tuning values taken from Linux driver */ + FlowCtrlPeriod, 0x03, + FlowCtrlWaterMark, 0x05, + MaxPktLen, ( ( LINDA_RECV_HEADER_SIZE + + LINDA_RECV_PAYLOAD_SIZE + + 4 /* ICRC */ ) >> 2 ), + PhyerrThreshold, 0xf, + OverrunThreshold, 0xf, + CreditScale, 0x4 ); + linda_writeq ( linda, &ibcctrl, QIB_7220_IBCCtrl_offset ); + + /* Force SDR only to avoid needing all the DDR tuning, + * Mellanox compatibiltiy hacks etc. SDR is plenty for + * boot-time operation. + */ + linda_readq ( linda, &ibcddrctrl, QIB_7220_IBCDDRCtrl_offset ); + BIT_SET ( &ibcddrctrl, IB_ENHANCED_MODE, 0 ); + BIT_SET ( &ibcddrctrl, SD_SPEED_SDR, 1 ); + BIT_SET ( &ibcddrctrl, SD_SPEED_DDR, 0 ); + BIT_SET ( &ibcddrctrl, SD_SPEED_QDR, 0 ); + BIT_SET ( &ibcddrctrl, HRTBT_ENB, 0 ); + BIT_SET ( &ibcddrctrl, HRTBT_AUTO, 0 ); + linda_writeq ( linda, &ibcddrctrl, QIB_7220_IBCDDRCtrl_offset ); + + /* Set default SerDes parameters */ + if ( ( rc = linda_set_serdes_params ( linda, + linda_serdes_defaults1 ) ) != 0 ) + return rc; + udelay ( 415 ); /* Magic delay while SerDes sorts itself out */ + if ( ( rc = linda_set_serdes_params ( linda, + linda_serdes_defaults2 ) ) != 0 ) + return rc; + + /* Program the microcontroller RAM */ + if ( ( rc = linda_program_uc_ram ( linda ) ) != 0 ) + return rc; + + /* Verify the microcontroller RAM contents */ + if ( DBGLVL_LOG ) { + if ( ( rc = linda_verify_uc_ram ( linda ) ) != 0 ) + return rc; + } + + /* More SerDes tuning */ + if ( ( rc = linda_set_serdes_params ( linda, + linda_serdes_defaults3 ) ) != 0 ) + return rc; + + /* Use the microcontroller to trim the IB link */ + if ( ( rc = linda_trim_ib ( linda ) ) != 0 ) + return rc; + + /* Bring XGXS out of reset */ + linda_readq ( linda, &xgxscfg, QIB_7220_XGXSCfg_offset ); + BIT_SET ( &xgxscfg, tx_rx_reset, 0 ); + BIT_SET ( &xgxscfg, xcv_reset, 0 ); + linda_writeq ( linda, &xgxscfg, QIB_7220_XGXSCfg_offset ); + + return rc; +} + +/*************************************************************************** + * + * PCI layer interface + * + *************************************************************************** + */ + +/** + * Probe PCI device + * + * @v pci PCI device + * @v id PCI ID + * @ret rc Return status code + */ +static int linda_probe ( struct pci_device *pci, + const struct pci_device_id *id __unused ) { + struct ib_device *ibdev; + struct linda *linda; + struct QIB_7220_Revision revision; + int rc; + + /* Allocate Infiniband device */ + ibdev = alloc_ibdev ( sizeof ( *linda ) ); + if ( ! ibdev ) { + rc = -ENOMEM; + goto err_alloc_ibdev; + } + pci_set_drvdata ( pci, ibdev ); + linda = ib_get_drvdata ( ibdev ); + ibdev->op = &linda_ib_operations; + ibdev->dev = &pci->dev; + ibdev->port = 1; + + /* Fix up PCI device */ + adjust_pci_device ( pci ); + + /* Get PCI BARs */ + linda->regs = ioremap ( pci->membase, LINDA_BAR0_SIZE ); + DBGC2 ( linda, "Linda %p has BAR at %08lx\n", linda, pci->membase ); + + /* Print some general data */ + linda_readq ( linda, &revision, QIB_7220_Revision_offset ); + DBGC2 ( linda, "Linda %p board %02lx v%ld.%ld.%ld.%ld\n", linda, + BIT_GET ( &revision, BoardID ), + BIT_GET ( &revision, R_SW ), + BIT_GET ( &revision, R_Arch ), + BIT_GET ( &revision, R_ChipRevMajor ), + BIT_GET ( &revision, R_ChipRevMinor ) ); + + /* Initialise I2C subsystem */ + if ( ( rc = linda_init_i2c ( linda ) ) != 0 ) + goto err_init_i2c; + + /* Read EEPROM parameters */ + if ( ( rc = linda_read_eeprom ( linda, &ibdev->gid.u.half[1] ) ) != 0 ) + goto err_read_eeprom; + + /* Initialise send datapath */ + if ( ( rc = linda_init_send ( linda ) ) != 0 ) + goto err_init_send; + + /* Initialise receive datapath */ + if ( ( rc = linda_init_recv ( linda ) ) != 0 ) + goto err_init_recv; + + /* Initialise the IB SerDes */ + if ( ( rc = linda_init_ib_serdes ( linda ) ) != 0 ) + goto err_init_ib_serdes; + + /* Create the SMA */ + if ( ( rc = ib_create_sma ( &linda->sma, ibdev, + &linda_sma_operations ) ) != 0 ) + goto err_create_sma; + /* If the SMA doesn't get context 0, we're screwed */ + assert ( linda_qpn_to_ctx ( linda->sma.qp->qpn ) == 0 ); + + /* Register Infiniband device */ + if ( ( rc = register_ibdev ( ibdev ) ) != 0 ) { + DBGC ( linda, "Linda %p could not register IB " + "device: %s\n", linda, strerror ( rc ) ); + goto err_register_ibdev; + } + + return 0; + + unregister_ibdev ( ibdev ); + err_register_ibdev: + ib_destroy_sma ( &linda->sma ); + err_create_sma: + linda_fini_recv ( linda ); + err_init_recv: + linda_fini_send ( linda ); + err_init_send: + err_init_ib_serdes: + err_read_eeprom: + err_init_i2c: + ibdev_put ( ibdev ); + err_alloc_ibdev: + return rc; +} + +/** + * Remove PCI device + * + * @v pci PCI device + */ +static void linda_remove ( struct pci_device *pci ) { + struct ib_device *ibdev = pci_get_drvdata ( pci ); + struct linda *linda = ib_get_drvdata ( ibdev ); + + unregister_ibdev ( ibdev ); + ib_destroy_sma ( &linda->sma ); + linda_fini_recv ( linda ); + linda_fini_send ( linda ); + ibdev_put ( ibdev ); +} + +static struct pci_device_id linda_nics[] = { + PCI_ROM ( 0x1077, 0x7220, "iba7220", "QLE7240/7280 HCA driver" ), +}; + +struct pci_driver linda_driver __pci_driver = { + .ids = linda_nics, + .id_count = ( sizeof ( linda_nics ) / sizeof ( linda_nics[0] ) ), + .probe = linda_probe, + .remove = linda_remove, +}; diff --git a/gpxe/src/drivers/infiniband/linda.h b/gpxe/src/drivers/infiniband/linda.h new file mode 100644 index 00000000..dd1737a6 --- /dev/null +++ b/gpxe/src/drivers/infiniband/linda.h @@ -0,0 +1,271 @@ +#ifndef _LINDA_H +#define _LINDA_H + +/* + * Copyright (C) 2008 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/** + * @file + * + * QLogic Linda Infiniband HCA + * + */ + +#define BITOPS_LITTLE_ENDIAN +#include +#include "qib_7220_regs.h" + +struct ib_device; + +/** A Linda GPIO register */ +struct QIB_7220_GPIO_pb { + pseudo_bit_t GPIO[16]; + pseudo_bit_t Reserved[48]; +}; +struct QIB_7220_GPIO { + PSEUDO_BIT_STRUCT ( struct QIB_7220_GPIO_pb ); +}; + +/** A Linda general scalar register */ +struct QIB_7220_scalar_pb { + pseudo_bit_t Value[64]; +}; +struct QIB_7220_scalar { + PSEUDO_BIT_STRUCT ( struct QIB_7220_scalar_pb ); +}; + +/** Linda send per-buffer control word */ +struct QIB_7220_SendPbc_pb { + pseudo_bit_t LengthP1_toibc[11]; + pseudo_bit_t Reserved1[4]; + pseudo_bit_t LengthP1_trigger[11]; + pseudo_bit_t Reserved2[3]; + pseudo_bit_t TestEbp[1]; + pseudo_bit_t Test[1]; + pseudo_bit_t Intr[1]; + pseudo_bit_t Reserved3[31]; + pseudo_bit_t VL15[1]; +}; +struct QIB_7220_SendPbc { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendPbc_pb ); +}; + +/** Linda send buffer availability */ +struct QIB_7220_SendBufAvail_pb { + pseudo_bit_t InUseCheck[144][2]; + pseudo_bit_t Reserved[32]; +}; +struct QIB_7220_SendBufAvail { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufAvail_pb ); +}; + +/** DMA alignment for send buffer availability */ +#define LINDA_SENDBUFAVAIL_ALIGN 64 + +/** A Linda eager receive descriptor */ +struct QIB_7220_RcvEgr_pb { + pseudo_bit_t Addr[37]; + pseudo_bit_t BufSize[3]; + pseudo_bit_t Reserved[24]; +}; +struct QIB_7220_RcvEgr { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvEgr_pb ); +}; + +/** Linda receive header flags */ +struct QIB_7220_RcvHdrFlags_pb { + pseudo_bit_t PktLen[11]; + pseudo_bit_t RcvType[3]; + pseudo_bit_t SoftB[1]; + pseudo_bit_t SoftA[1]; + pseudo_bit_t EgrIndex[12]; + pseudo_bit_t Reserved1[3]; + pseudo_bit_t UseEgrBfr[1]; + pseudo_bit_t RcvSeq[4]; + pseudo_bit_t HdrqOffset[11]; + pseudo_bit_t Reserved2[8]; + pseudo_bit_t IBErr[1]; + pseudo_bit_t MKErr[1]; + pseudo_bit_t TIDErr[1]; + pseudo_bit_t KHdrErr[1]; + pseudo_bit_t MTUErr[1]; + pseudo_bit_t LenErr[1]; + pseudo_bit_t ParityErr[1]; + pseudo_bit_t VCRCErr[1]; + pseudo_bit_t ICRCErr[1]; +}; +struct QIB_7220_RcvHdrFlags { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrFlags_pb ); +}; + +/** Linda memory BAR size */ +#define LINDA_BAR0_SIZE 0x400000 + +/** Linda I2C SCL line GPIO number */ +#define LINDA_GPIO_SCL 0 + +/** Linda I2C SDA line GPIO number */ +#define LINDA_GPIO_SDA 1 + +/** GUID offset within EEPROM */ +#define LINDA_EEPROM_GUID_OFFSET 3 + +/** GUID size within EEPROM */ +#define LINDA_EEPROM_GUID_SIZE 8 + +/** Board serial number offset within EEPROM */ +#define LINDA_EEPROM_SERIAL_OFFSET 12 + +/** Board serial number size within EEPROM */ +#define LINDA_EEPROM_SERIAL_SIZE 12 + +/** Maximum number of send buffers used + * + * This is a policy decision. Must be less than or equal to the total + * number of send buffers supported by the hardware (128). + */ +#define LINDA_MAX_SEND_BUFS 32 + +/** Linda send buffer size */ +#define LINDA_SEND_BUF_SIZE 4096 + +/** Number of contexts (including kernel context) + * + * This is a policy decision. Must be 5, 9 or 17. + */ +#define LINDA_NUM_CONTEXTS 5 + +/** PortCfg values for different numbers of contexts */ +enum linda_portcfg { + LINDA_PORTCFG_5CTX = 0, + LINDA_PORTCFG_9CTX = 1, + LINDA_PORTCFG_17CTX = 2, +}; + +/** PortCfg values for different numbers of contexts */ +#define LINDA_EAGER_ARRAY_SIZE_5CTX_0 2048 +#define LINDA_EAGER_ARRAY_SIZE_5CTX_OTHER 4096 +#define LINDA_EAGER_ARRAY_SIZE_9CTX_0 2048 +#define LINDA_EAGER_ARRAY_SIZE_9CTX_OTHER 2048 +#define LINDA_EAGER_ARRAY_SIZE_17CTX_0 2048 +#define LINDA_EAGER_ARRAY_SIZE_17CTX_OTHER 1024 + +/** Eager buffer required alignment */ +#define LINDA_EAGER_BUFFER_ALIGN 2048 + +/** Eager buffer size encodings */ +enum linda_eager_buffer_size { + LINDA_EAGER_BUFFER_NONE = 0, + LINDA_EAGER_BUFFER_2K = 1, + LINDA_EAGER_BUFFER_4K = 2, + LINDA_EAGER_BUFFER_8K = 3, + LINDA_EAGER_BUFFER_16K = 4, + LINDA_EAGER_BUFFER_32K = 5, + LINDA_EAGER_BUFFER_64K = 6, +}; + +/** Number of RX headers per context + * + * This is a policy decision. + */ +#define LINDA_RECV_HEADER_COUNT 8 + +/** Maximum size of each RX header + * + * This is a policy decision. Must be divisible by 4. + */ +#define LINDA_RECV_HEADER_SIZE 96 + +/** Total size of an RX header ring */ +#define LINDA_RECV_HEADERS_SIZE \ + ( LINDA_RECV_HEADER_SIZE * LINDA_RECV_HEADER_COUNT ) + +/** RX header alignment */ +#define LINDA_RECV_HEADERS_ALIGN 64 + +/** RX payload size + * + * This is a policy decision. Must be a valid eager buffer size. + */ +#define LINDA_RECV_PAYLOAD_SIZE 2048 + +/** QPN used for Infinipath Packets + * + * This is a policy decision. Must have bit 0 clear. Must not be a + * QPN that we will use. + */ +#define LINDA_QP_IDETH 0xdead0 + +/** Maximum time for wait for external parallel bus request, in us */ +#define LINDA_EPB_REQUEST_MAX_WAIT_US 500 + +/** Maximum time for wait for external parallel bus transaction, in us */ +#define LINDA_EPB_XACT_MAX_WAIT_US 500 + +/** Linda external parallel bus chip selects */ +#define LINDA_EPB_CS_SERDES 1 +#define LINDA_EPB_CS_UC 2 + +/** Linda external parallel bus read/write operations */ +#define LINDA_EPB_WRITE 0 +#define LINDA_EPB_READ 1 + +/** Linda external parallel bus register addresses */ +#define LINDA_EPB_ADDRESS( _channel, _element, _reg ) \ + ( (_element) | ( (_channel) << 4 ) | ( (_reg) << 9 ) ) +#define LINDA_EPB_ADDRESS_CHANNEL( _address ) ( ( (_address) >> 4 ) & 0x1f ) +#define LINDA_EPB_ADDRESS_ELEMENT( _address ) ( ( (_address) >> 0 ) & 0x0f ) +#define LINDA_EPB_ADDRESS_REG( _address ) ( ( (_address) >> 9 ) & 0x3f ) + +/** Linda external parallel bus locations + * + * The location is used by the driver to encode both the chip select + * and the EPB address. + */ +#define LINDA_EPB_LOC( _cs, _channel, _element, _reg) \ + ( ( (_cs) << 16 ) | LINDA_EPB_ADDRESS ( _channel, _element, _reg ) ) +#define LINDA_EPB_LOC_ADDRESS( _loc ) ( (_loc) & 0xffff ) +#define LINDA_EPB_LOC_CS( _loc ) ( (_loc) >> 16 ) + +/** Linda external parallel bus microcontroller register addresses */ +#define LINDA_EPB_UC_CHANNEL 6 +#define LINDA_EPB_UC_LOC( _reg ) \ + LINDA_EPB_LOC ( LINDA_EPB_CS_UC, LINDA_EPB_UC_CHANNEL, 0, (_reg) ) +#define LINDA_EPB_UC_CTL LINDA_EPB_UC_LOC ( 0 ) +#define LINDA_EPB_UC_CTL_WRITE 1 +#define LINDA_EPB_UC_CTL_READ 2 +#define LINDA_EPB_UC_ADDR_LO LINDA_EPB_UC_LOC ( 2 ) +#define LINDA_EPB_UC_ADDR_HI LINDA_EPB_UC_LOC ( 3 ) +#define LINDA_EPB_UC_DATA LINDA_EPB_UC_LOC ( 4 ) +#define LINDA_EPB_UC_CHUNK_SIZE 64 + +extern uint8_t linda_ib_fw[8192]; + +/** Maximum time to wait for "trim done" signal, in ms */ +#define LINDA_TRIM_DONE_MAX_WAIT_MS 1000 + +/** Linda link states */ +enum linda_link_state { + LINDA_LINK_STATE_DOWN = 0, + LINDA_LINK_STATE_INIT = 1, + LINDA_LINK_STATE_ARM = 2, + LINDA_LINK_STATE_ACTIVE = 3, + LINDA_LINK_STATE_ACT_DEFER = 4, +}; + +#endif /* _LINDA_H */ diff --git a/gpxe/src/drivers/infiniband/linda_fw.c b/gpxe/src/drivers/infiniband/linda_fw.c new file mode 100644 index 00000000..fc5ea077 --- /dev/null +++ b/gpxe/src/drivers/infiniband/linda_fw.c @@ -0,0 +1,1067 @@ +/* + * Copyright (c) 2007, 2008 QLogic Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * This file contains the memory image from the vendor, to be copied into + * the IB SERDES of the IBA7220 during initialization. + * The file also includes the two functions which use this image. + */ + +#include +#include "linda.h" + +uint8_t linda_ib_fw[8192] = { +/*0000*/0x02, 0x0A, 0x29, 0x02, 0x0A, 0x87, 0xE5, 0xE6, + 0x30, 0xE6, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, +/*0010*/0x00, 0xE5, 0xE2, 0x30, 0xE4, 0x04, 0x7E, 0x01, + 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x5F, 0x60, 0x08, +/*0020*/0x53, 0xF9, 0xF7, 0xE4, 0xF5, 0xFE, 0x80, 0x08, + 0x7F, 0x0A, 0x12, 0x17, 0x31, 0x12, 0x0E, 0xA2, +/*0030*/0x75, 0xFC, 0x08, 0xE4, 0xF5, 0xFD, 0xE5, 0xE7, + 0x20, 0xE7, 0x03, 0x43, 0xF9, 0x08, 0x22, 0x00, +/*0040*/0x01, 0x20, 0x11, 0x00, 0x04, 0x20, 0x00, 0x75, + 0x51, 0x01, 0xE4, 0xF5, 0x52, 0xF5, 0x53, 0xF5, +/*0050*/0x52, 0xF5, 0x7E, 0x7F, 0x04, 0x02, 0x04, 0x38, + 0xC2, 0x36, 0x05, 0x52, 0xE5, 0x52, 0xD3, 0x94, +/*0060*/0x0C, 0x40, 0x05, 0x75, 0x52, 0x01, 0xD2, 0x36, + 0x90, 0x07, 0x0C, 0x74, 0x07, 0xF0, 0xA3, 0x74, +/*0070*/0xFF, 0xF0, 0xE4, 0xF5, 0x0C, 0xA3, 0xF0, 0x90, + 0x07, 0x14, 0xF0, 0xA3, 0xF0, 0x75, 0x0B, 0x20, +/*0080*/0xF5, 0x09, 0xE4, 0xF5, 0x08, 0xE5, 0x08, 0xD3, + 0x94, 0x30, 0x40, 0x03, 0x02, 0x04, 0x04, 0x12, +/*0090*/0x00, 0x06, 0x15, 0x0B, 0xE5, 0x08, 0x70, 0x04, + 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x09, +/*00A0*/0x70, 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, + 0xEE, 0x5F, 0x60, 0x05, 0x12, 0x18, 0x71, 0xD2, +/*00B0*/0x35, 0x53, 0xE1, 0xF7, 0xE5, 0x08, 0x45, 0x09, + 0xFF, 0xE5, 0x0B, 0x25, 0xE0, 0x25, 0xE0, 0x24, +/*00C0*/0x83, 0xF5, 0x82, 0xE4, 0x34, 0x07, 0xF5, 0x83, + 0xEF, 0xF0, 0x85, 0xE2, 0x20, 0xE5, 0x52, 0xD3, +/*00D0*/0x94, 0x01, 0x40, 0x0D, 0x12, 0x19, 0xF3, 0xE0, + 0x54, 0xA0, 0x64, 0x40, 0x70, 0x03, 0x02, 0x03, +/*00E0*/0xFB, 0x53, 0xF9, 0xF8, 0x90, 0x94, 0x70, 0xE4, + 0xF0, 0xE0, 0xF5, 0x10, 0xAF, 0x09, 0x12, 0x1E, +/*00F0*/0xB3, 0xAF, 0x08, 0xEF, 0x44, 0x08, 0xF5, 0x82, + 0x75, 0x83, 0x80, 0xE0, 0xF5, 0x29, 0xEF, 0x44, +/*0100*/0x07, 0x12, 0x1A, 0x3C, 0xF5, 0x22, 0x54, 0x40, + 0xD3, 0x94, 0x00, 0x40, 0x1E, 0xE5, 0x29, 0x54, +/*0110*/0xF0, 0x70, 0x21, 0x12, 0x19, 0xF3, 0xE0, 0x44, + 0x80, 0xF0, 0xE5, 0x22, 0x54, 0x30, 0x65, 0x08, +/*0120*/0x70, 0x09, 0x12, 0x19, 0xF3, 0xE0, 0x54, 0xBF, + 0xF0, 0x80, 0x09, 0x12, 0x19, 0xF3, 0x74, 0x40, +/*0130*/0xF0, 0x02, 0x03, 0xFB, 0x12, 0x1A, 0x12, 0x75, + 0x83, 0xAE, 0x74, 0xFF, 0xF0, 0xAF, 0x08, 0x7E, +/*0140*/0x00, 0xEF, 0x44, 0x07, 0xF5, 0x82, 0xE0, 0xFD, + 0xE5, 0x0B, 0x25, 0xE0, 0x25, 0xE0, 0x24, 0x81, +/*0150*/0xF5, 0x82, 0xE4, 0x34, 0x07, 0xF5, 0x83, 0xED, + 0xF0, 0x90, 0x07, 0x0E, 0xE0, 0x04, 0xF0, 0xEF, +/*0160*/0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0x98, 0xE0, + 0xF5, 0x28, 0x12, 0x1A, 0x23, 0x40, 0x0C, 0x12, +/*0170*/0x19, 0xF3, 0xE0, 0x44, 0x01, 0x12, 0x1A, 0x32, + 0x02, 0x03, 0xF6, 0xAF, 0x08, 0x7E, 0x00, 0x74, +/*0180*/0x80, 0xCD, 0xEF, 0xCD, 0x8D, 0x82, 0xF5, 0x83, + 0xE0, 0x30, 0xE0, 0x0A, 0x12, 0x19, 0xF3, 0xE0, +/*0190*/0x44, 0x20, 0xF0, 0x02, 0x03, 0xFB, 0x12, 0x19, + 0xF3, 0xE0, 0x54, 0xDF, 0xF0, 0xEE, 0x44, 0xAE, +/*01A0*/0x12, 0x1A, 0x43, 0x30, 0xE4, 0x03, 0x02, 0x03, + 0xFB, 0x74, 0x9E, 0x12, 0x1A, 0x05, 0x20, 0xE0, +/*01B0*/0x03, 0x02, 0x03, 0xFB, 0x8F, 0x82, 0x8E, 0x83, + 0xE0, 0x20, 0xE0, 0x03, 0x02, 0x03, 0xFB, 0x12, +/*01C0*/0x19, 0xF3, 0xE0, 0x44, 0x10, 0xF0, 0xE5, 0xE3, + 0x20, 0xE7, 0x08, 0xE5, 0x08, 0x12, 0x1A, 0x3A, +/*01D0*/0x44, 0x04, 0xF0, 0xAF, 0x08, 0x7E, 0x00, 0xEF, + 0x12, 0x1A, 0x3A, 0x20, 0xE2, 0x34, 0x12, 0x19, +/*01E0*/0xF3, 0xE0, 0x44, 0x08, 0xF0, 0xE5, 0xE4, 0x30, + 0xE6, 0x04, 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00, +/*01F0*/0xE5, 0x7E, 0xC3, 0x94, 0x04, 0x50, 0x04, 0x7C, + 0x01, 0x80, 0x02, 0x7C, 0x00, 0xEC, 0x4D, 0x60, +/*0200*/0x05, 0xC2, 0x35, 0x02, 0x03, 0xFB, 0xEE, 0x44, + 0xD2, 0x12, 0x1A, 0x43, 0x44, 0x40, 0xF0, 0x02, +/*0210*/0x03, 0xFB, 0x12, 0x19, 0xF3, 0xE0, 0x54, 0xF7, + 0xF0, 0x12, 0x1A, 0x12, 0x75, 0x83, 0xD2, 0xE0, +/*0220*/0x54, 0xBF, 0xF0, 0x90, 0x07, 0x14, 0xE0, 0x04, + 0xF0, 0xE5, 0x7E, 0x70, 0x03, 0x75, 0x7E, 0x01, +/*0230*/0xAF, 0x08, 0x7E, 0x00, 0x12, 0x1A, 0x23, 0x40, + 0x12, 0x12, 0x19, 0xF3, 0xE0, 0x44, 0x01, 0x12, +/*0240*/0x19, 0xF2, 0xE0, 0x54, 0x02, 0x12, 0x1A, 0x32, + 0x02, 0x03, 0xFB, 0x12, 0x19, 0xF3, 0xE0, 0x44, +/*0250*/0x02, 0x12, 0x19, 0xF2, 0xE0, 0x54, 0xFE, 0xF0, + 0xC2, 0x35, 0xEE, 0x44, 0x8A, 0x8F, 0x82, 0xF5, +/*0260*/0x83, 0xE0, 0xF5, 0x17, 0x54, 0x8F, 0x44, 0x40, + 0xF0, 0x74, 0x90, 0xFC, 0xE5, 0x08, 0x44, 0x07, +/*0270*/0xFD, 0xF5, 0x82, 0x8C, 0x83, 0xE0, 0x54, 0x3F, + 0x90, 0x07, 0x02, 0xF0, 0xE0, 0x54, 0xC0, 0x8D, +/*0280*/0x82, 0x8C, 0x83, 0xF0, 0x74, 0x92, 0x12, 0x1A, + 0x05, 0x90, 0x07, 0x03, 0x12, 0x1A, 0x19, 0x74, +/*0290*/0x82, 0x12, 0x1A, 0x05, 0x90, 0x07, 0x04, 0x12, + 0x1A, 0x19, 0x74, 0xB4, 0x12, 0x1A, 0x05, 0x90, +/*02A0*/0x07, 0x05, 0x12, 0x1A, 0x19, 0x74, 0x94, 0xFE, + 0xE5, 0x08, 0x44, 0x06, 0x12, 0x1A, 0x0A, 0xF5, +/*02B0*/0x10, 0x30, 0xE0, 0x04, 0xD2, 0x37, 0x80, 0x02, + 0xC2, 0x37, 0xE5, 0x10, 0x54, 0x7F, 0x8F, 0x82, +/*02C0*/0x8E, 0x83, 0xF0, 0x30, 0x44, 0x30, 0x12, 0x1A, + 0x03, 0x54, 0x80, 0xD3, 0x94, 0x00, 0x40, 0x04, +/*02D0*/0xD2, 0x39, 0x80, 0x02, 0xC2, 0x39, 0x8F, 0x82, + 0x8E, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0x12, 0x1A, +/*02E0*/0x03, 0x54, 0x40, 0xD3, 0x94, 0x00, 0x40, 0x04, + 0xD2, 0x3A, 0x80, 0x02, 0xC2, 0x3A, 0x8F, 0x82, +/*02F0*/0x8E, 0x83, 0xE0, 0x44, 0x40, 0xF0, 0x74, 0x92, + 0xFE, 0xE5, 0x08, 0x44, 0x06, 0x12, 0x1A, 0x0A, +/*0300*/0x30, 0xE7, 0x04, 0xD2, 0x38, 0x80, 0x02, 0xC2, + 0x38, 0x8F, 0x82, 0x8E, 0x83, 0xE0, 0x54, 0x7F, +/*0310*/0xF0, 0x12, 0x1E, 0x46, 0xE4, 0xF5, 0x0A, 0x20, + 0x03, 0x02, 0x80, 0x03, 0x30, 0x43, 0x03, 0x12, +/*0320*/0x19, 0x95, 0x20, 0x02, 0x02, 0x80, 0x03, 0x30, + 0x42, 0x03, 0x12, 0x0C, 0x8F, 0x30, 0x30, 0x06, +/*0330*/0x12, 0x19, 0x95, 0x12, 0x0C, 0x8F, 0x12, 0x0D, + 0x47, 0x12, 0x19, 0xF3, 0xE0, 0x54, 0xFB, 0xF0, +/*0340*/0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x40, 0x46, 0x43, + 0xE1, 0x08, 0x12, 0x19, 0xF3, 0xE0, 0x44, 0x04, +/*0350*/0xF0, 0xE5, 0xE4, 0x20, 0xE7, 0x2A, 0x12, 0x1A, + 0x12, 0x75, 0x83, 0xD2, 0xE0, 0x54, 0x08, 0xD3, +/*0360*/0x94, 0x00, 0x40, 0x04, 0x7F, 0x01, 0x80, 0x02, + 0x7F, 0x00, 0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x40, +/*0370*/0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEF, + 0x5E, 0x60, 0x05, 0x12, 0x1D, 0xD7, 0x80, 0x17, +/*0380*/0x12, 0x1A, 0x12, 0x75, 0x83, 0xD2, 0xE0, 0x44, + 0x08, 0xF0, 0x02, 0x03, 0xFB, 0x12, 0x1A, 0x12, +/*0390*/0x75, 0x83, 0xD2, 0xE0, 0x54, 0xF7, 0xF0, 0x12, + 0x1E, 0x46, 0x7F, 0x08, 0x12, 0x17, 0x31, 0x74, +/*03A0*/0x8E, 0xFE, 0x12, 0x1A, 0x12, 0x8E, 0x83, 0xE0, + 0xF5, 0x10, 0x54, 0xFE, 0xF0, 0xE5, 0x10, 0x44, +/*03B0*/0x01, 0xFF, 0xE5, 0x08, 0xFD, 0xED, 0x44, 0x07, + 0xF5, 0x82, 0xEF, 0xF0, 0xE5, 0x10, 0x54, 0xFE, +/*03C0*/0xFF, 0xED, 0x44, 0x07, 0xF5, 0x82, 0xEF, 0x12, + 0x1A, 0x11, 0x75, 0x83, 0x86, 0xE0, 0x44, 0x10, +/*03D0*/0x12, 0x1A, 0x11, 0xE0, 0x44, 0x10, 0xF0, 0x12, + 0x19, 0xF3, 0xE0, 0x54, 0xFD, 0x44, 0x01, 0xFF, +/*03E0*/0x12, 0x19, 0xF3, 0xEF, 0x12, 0x1A, 0x32, 0x30, + 0x32, 0x0C, 0xE5, 0x08, 0x44, 0x08, 0xF5, 0x82, +/*03F0*/0x75, 0x83, 0x82, 0x74, 0x05, 0xF0, 0xAF, 0x0B, + 0x12, 0x18, 0xD7, 0x74, 0x10, 0x25, 0x08, 0xF5, +/*0400*/0x08, 0x02, 0x00, 0x85, 0x05, 0x09, 0xE5, 0x09, + 0xD3, 0x94, 0x07, 0x50, 0x03, 0x02, 0x00, 0x82, +/*0410*/0xE5, 0x7E, 0xD3, 0x94, 0x00, 0x40, 0x04, 0x7F, + 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x7E, 0xC3, +/*0420*/0x94, 0xFA, 0x50, 0x04, 0x7E, 0x01, 0x80, 0x02, + 0x7E, 0x00, 0xEE, 0x5F, 0x60, 0x02, 0x05, 0x7E, +/*0430*/0x30, 0x35, 0x0B, 0x43, 0xE1, 0x01, 0x7F, 0x09, + 0x12, 0x17, 0x31, 0x02, 0x00, 0x58, 0x53, 0xE1, +/*0440*/0xFE, 0x02, 0x00, 0x58, 0x8E, 0x6A, 0x8F, 0x6B, + 0x8C, 0x6C, 0x8D, 0x6D, 0x75, 0x6E, 0x01, 0x75, +/*0450*/0x6F, 0x01, 0x75, 0x70, 0x01, 0xE4, 0xF5, 0x73, + 0xF5, 0x74, 0xF5, 0x75, 0x90, 0x07, 0x2F, 0xF0, +/*0460*/0xF5, 0x3C, 0xF5, 0x3E, 0xF5, 0x46, 0xF5, 0x47, + 0xF5, 0x3D, 0xF5, 0x3F, 0xF5, 0x6F, 0xE5, 0x6F, +/*0470*/0x70, 0x0F, 0xE5, 0x6B, 0x45, 0x6A, 0x12, 0x07, + 0x2A, 0x75, 0x83, 0x80, 0x74, 0x3A, 0xF0, 0x80, +/*0480*/0x09, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x80, 0x74, + 0x1A, 0xF0, 0xE4, 0xF5, 0x6E, 0xC3, 0x74, 0x3F, +/*0490*/0x95, 0x6E, 0xFF, 0x12, 0x08, 0x65, 0x75, 0x83, + 0x82, 0xEF, 0xF0, 0x12, 0x1A, 0x4D, 0x12, 0x08, +/*04A0*/0xC6, 0xE5, 0x33, 0xF0, 0x12, 0x08, 0xFA, 0x12, + 0x08, 0xB1, 0x40, 0xE1, 0xE5, 0x6F, 0x70, 0x0B, +/*04B0*/0x12, 0x07, 0x2A, 0x75, 0x83, 0x80, 0x74, 0x36, + 0xF0, 0x80, 0x09, 0x12, 0x07, 0x2A, 0x75, 0x83, +/*04C0*/0x80, 0x74, 0x16, 0xF0, 0x75, 0x6E, 0x01, 0x12, + 0x07, 0x2A, 0x75, 0x83, 0xB4, 0xE5, 0x6E, 0xF0, +/*04D0*/0x12, 0x1A, 0x4D, 0x74, 0x3F, 0x25, 0x6E, 0xF5, + 0x82, 0xE4, 0x34, 0x00, 0xF5, 0x83, 0xE5, 0x33, +/*04E0*/0xF0, 0x74, 0xBF, 0x25, 0x6E, 0xF5, 0x82, 0xE4, + 0x34, 0x00, 0x12, 0x08, 0xB1, 0x40, 0xD8, 0xE4, +/*04F0*/0xF5, 0x70, 0xF5, 0x46, 0xF5, 0x47, 0xF5, 0x6E, + 0x12, 0x08, 0xFA, 0xF5, 0x83, 0xE0, 0xFE, 0x12, +/*0500*/0x08, 0xC6, 0xE0, 0x7C, 0x00, 0x24, 0x00, 0xFF, + 0xEC, 0x3E, 0xFE, 0xAD, 0x3B, 0xD3, 0xEF, 0x9D, +/*0510*/0xEE, 0x9C, 0x50, 0x04, 0x7B, 0x01, 0x80, 0x02, + 0x7B, 0x00, 0xE5, 0x70, 0x70, 0x04, 0x7A, 0x01, +/*0520*/0x80, 0x02, 0x7A, 0x00, 0xEB, 0x5A, 0x60, 0x06, + 0x85, 0x6E, 0x46, 0x75, 0x70, 0x01, 0xD3, 0xEF, +/*0530*/0x9D, 0xEE, 0x9C, 0x50, 0x04, 0x7F, 0x01, 0x80, + 0x02, 0x7F, 0x00, 0xE5, 0x70, 0xB4, 0x01, 0x04, +/*0540*/0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEF, 0x5E, + 0x60, 0x03, 0x85, 0x6E, 0x47, 0x05, 0x6E, 0xE5, +/*0550*/0x6E, 0x64, 0x7F, 0x70, 0xA3, 0xE5, 0x46, 0x60, + 0x05, 0xE5, 0x47, 0xB4, 0x7E, 0x03, 0x85, 0x46, +/*0560*/0x47, 0xE5, 0x6F, 0x70, 0x08, 0x85, 0x46, 0x76, + 0x85, 0x47, 0x77, 0x80, 0x0E, 0xC3, 0x74, 0x7F, +/*0570*/0x95, 0x46, 0xF5, 0x78, 0xC3, 0x74, 0x7F, 0x95, + 0x47, 0xF5, 0x79, 0xE5, 0x6F, 0x70, 0x37, 0xE5, +/*0580*/0x46, 0x65, 0x47, 0x70, 0x0C, 0x75, 0x73, 0x01, + 0x75, 0x74, 0x01, 0xF5, 0x3C, 0xF5, 0x3D, 0x80, +/*0590*/0x35, 0xE4, 0xF5, 0x4E, 0xC3, 0xE5, 0x47, 0x95, + 0x46, 0xF5, 0x3C, 0xC3, 0x13, 0xF5, 0x71, 0x25, +/*05A0*/0x46, 0xF5, 0x72, 0xC3, 0x94, 0x3F, 0x40, 0x05, + 0xE4, 0xF5, 0x3D, 0x80, 0x40, 0xC3, 0x74, 0x3F, +/*05B0*/0x95, 0x72, 0xF5, 0x3D, 0x80, 0x37, 0xE5, 0x46, + 0x65, 0x47, 0x70, 0x0F, 0x75, 0x73, 0x01, 0x75, +/*05C0*/0x75, 0x01, 0xF5, 0x3E, 0xF5, 0x3F, 0x75, 0x4E, + 0x01, 0x80, 0x22, 0xE4, 0xF5, 0x4E, 0xC3, 0xE5, +/*05D0*/0x47, 0x95, 0x46, 0xF5, 0x3E, 0xC3, 0x13, 0xF5, + 0x71, 0x25, 0x46, 0xF5, 0x72, 0xD3, 0x94, 0x3F, +/*05E0*/0x50, 0x05, 0xE4, 0xF5, 0x3F, 0x80, 0x06, 0xE5, + 0x72, 0x24, 0xC1, 0xF5, 0x3F, 0x05, 0x6F, 0xE5, +/*05F0*/0x6F, 0xC3, 0x94, 0x02, 0x50, 0x03, 0x02, 0x04, + 0x6E, 0xE5, 0x6D, 0x45, 0x6C, 0x70, 0x02, 0x80, +/*0600*/0x04, 0xE5, 0x74, 0x45, 0x75, 0x90, 0x07, 0x2F, + 0xF0, 0x7F, 0x01, 0xE5, 0x3E, 0x60, 0x04, 0xE5, +/*0610*/0x3C, 0x70, 0x14, 0xE4, 0xF5, 0x3C, 0xF5, 0x3D, + 0xF5, 0x3E, 0xF5, 0x3F, 0x12, 0x08, 0xD2, 0x70, +/*0620*/0x04, 0xF0, 0x02, 0x06, 0xA4, 0x80, 0x7A, 0xE5, + 0x3C, 0xC3, 0x95, 0x3E, 0x40, 0x07, 0xE5, 0x3C, +/*0630*/0x95, 0x3E, 0xFF, 0x80, 0x06, 0xC3, 0xE5, 0x3E, + 0x95, 0x3C, 0xFF, 0xE5, 0x76, 0xD3, 0x95, 0x79, +/*0640*/0x40, 0x05, 0x85, 0x76, 0x7A, 0x80, 0x03, 0x85, + 0x79, 0x7A, 0xE5, 0x77, 0xC3, 0x95, 0x78, 0x50, +/*0650*/0x05, 0x85, 0x77, 0x7B, 0x80, 0x03, 0x85, 0x78, + 0x7B, 0xE5, 0x7B, 0xD3, 0x95, 0x7A, 0x40, 0x30, +/*0660*/0xE5, 0x7B, 0x95, 0x7A, 0xF5, 0x3C, 0xF5, 0x3E, + 0xC3, 0xE5, 0x7B, 0x95, 0x7A, 0x90, 0x07, 0x19, +/*0670*/0xF0, 0xE5, 0x3C, 0xC3, 0x13, 0xF5, 0x71, 0x25, + 0x7A, 0xF5, 0x72, 0xC3, 0x94, 0x3F, 0x40, 0x05, +/*0680*/0xE4, 0xF5, 0x3D, 0x80, 0x1F, 0xC3, 0x74, 0x3F, + 0x95, 0x72, 0xF5, 0x3D, 0xF5, 0x3F, 0x80, 0x14, +/*0690*/0xE4, 0xF5, 0x3C, 0xF5, 0x3E, 0x90, 0x07, 0x19, + 0xF0, 0x12, 0x08, 0xD2, 0x70, 0x03, 0xF0, 0x80, +/*06A0*/0x03, 0x74, 0x01, 0xF0, 0x12, 0x08, 0x65, 0x75, + 0x83, 0xD0, 0xE0, 0x54, 0x0F, 0xFE, 0xAD, 0x3C, +/*06B0*/0x70, 0x02, 0x7E, 0x07, 0xBE, 0x0F, 0x02, 0x7E, + 0x80, 0xEE, 0xFB, 0xEF, 0xD3, 0x9B, 0x74, 0x80, +/*06C0*/0xF8, 0x98, 0x40, 0x1F, 0xE4, 0xF5, 0x3C, 0xF5, + 0x3E, 0x12, 0x08, 0xD2, 0x70, 0x03, 0xF0, 0x80, +/*06D0*/0x12, 0x74, 0x01, 0xF0, 0xE5, 0x08, 0xFB, 0xEB, + 0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0xD2, 0xE0, +/*06E0*/0x44, 0x10, 0xF0, 0xE5, 0x08, 0xFB, 0xEB, 0x44, + 0x09, 0xF5, 0x82, 0x75, 0x83, 0x9E, 0xED, 0xF0, +/*06F0*/0xEB, 0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0xCA, + 0xED, 0xF0, 0x12, 0x08, 0x65, 0x75, 0x83, 0xCC, +/*0700*/0xEF, 0xF0, 0x22, 0xE5, 0x08, 0x44, 0x07, 0xF5, + 0x82, 0x75, 0x83, 0xBC, 0xE0, 0x54, 0xF0, 0xF0, +/*0710*/0xE5, 0x08, 0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, + 0xBE, 0xE0, 0x54, 0xF0, 0xF0, 0xE5, 0x08, 0x44, +/*0720*/0x07, 0xF5, 0x82, 0x75, 0x83, 0xC0, 0xE0, 0x54, + 0xF0, 0xF0, 0xE5, 0x08, 0x44, 0x07, 0xF5, 0x82, +/*0730*/0x22, 0xF0, 0x90, 0x07, 0x28, 0xE0, 0xFE, 0xA3, + 0xE0, 0xF5, 0x82, 0x8E, 0x83, 0x22, 0x85, 0x42, +/*0740*/0x42, 0x85, 0x41, 0x41, 0x85, 0x40, 0x40, 0x74, + 0xC0, 0x2F, 0xF5, 0x82, 0x74, 0x02, 0x3E, 0xF5, +/*0750*/0x83, 0xE5, 0x42, 0xF0, 0x74, 0xE0, 0x2F, 0xF5, + 0x82, 0x74, 0x02, 0x3E, 0xF5, 0x83, 0x22, 0xE5, +/*0760*/0x42, 0x29, 0xFD, 0xE4, 0x33, 0xFC, 0xE5, 0x3C, + 0xC3, 0x9D, 0xEC, 0x64, 0x80, 0xF8, 0x74, 0x80, +/*0770*/0x98, 0x22, 0xF5, 0x83, 0xE0, 0x90, 0x07, 0x22, + 0x54, 0x1F, 0xFD, 0xE0, 0xFA, 0xA3, 0xE0, 0xF5, +/*0780*/0x82, 0x8A, 0x83, 0xED, 0xF0, 0x22, 0x90, 0x07, + 0x22, 0xE0, 0xFC, 0xA3, 0xE0, 0xF5, 0x82, 0x8C, +/*0790*/0x83, 0x22, 0x90, 0x07, 0x24, 0xFF, 0xED, 0x44, + 0x07, 0xCF, 0xF0, 0xA3, 0xEF, 0xF0, 0x22, 0x85, +/*07A0*/0x38, 0x38, 0x85, 0x39, 0x39, 0x85, 0x3A, 0x3A, + 0x74, 0xC0, 0x2F, 0xF5, 0x82, 0x74, 0x02, 0x3E, +/*07B0*/0xF5, 0x83, 0x22, 0x90, 0x07, 0x26, 0xFF, 0xED, + 0x44, 0x07, 0xCF, 0xF0, 0xA3, 0xEF, 0xF0, 0x22, +/*07C0*/0xF0, 0x74, 0xA0, 0x2F, 0xF5, 0x82, 0x74, 0x02, + 0x3E, 0xF5, 0x83, 0x22, 0x74, 0xC0, 0x25, 0x11, +/*07D0*/0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0x22, + 0x74, 0x00, 0x25, 0x11, 0xF5, 0x82, 0xE4, 0x34, +/*07E0*/0x02, 0xF5, 0x83, 0x22, 0x74, 0x60, 0x25, 0x11, + 0xF5, 0x82, 0xE4, 0x34, 0x03, 0xF5, 0x83, 0x22, +/*07F0*/0x74, 0x80, 0x25, 0x11, 0xF5, 0x82, 0xE4, 0x34, + 0x03, 0xF5, 0x83, 0x22, 0x74, 0xE0, 0x25, 0x11, +/*0800*/0xF5, 0x82, 0xE4, 0x34, 0x03, 0xF5, 0x83, 0x22, + 0x74, 0x40, 0x25, 0x11, 0xF5, 0x82, 0xE4, 0x34, +/*0810*/0x06, 0xF5, 0x83, 0x22, 0x74, 0x80, 0x2F, 0xF5, + 0x82, 0x74, 0x02, 0x3E, 0xF5, 0x83, 0x22, 0xAF, +/*0820*/0x08, 0x7E, 0x00, 0xEF, 0x44, 0x07, 0xF5, 0x82, + 0x22, 0xF5, 0x83, 0xE5, 0x82, 0x44, 0x07, 0xF5, +/*0830*/0x82, 0xE5, 0x40, 0xF0, 0x22, 0x74, 0x40, 0x25, + 0x11, 0xF5, 0x82, 0xE4, 0x34, 0x02, 0xF5, 0x83, +/*0840*/0x22, 0x74, 0xC0, 0x25, 0x11, 0xF5, 0x82, 0xE4, + 0x34, 0x03, 0xF5, 0x83, 0x22, 0x74, 0x00, 0x25, +/*0850*/0x11, 0xF5, 0x82, 0xE4, 0x34, 0x06, 0xF5, 0x83, + 0x22, 0x74, 0x20, 0x25, 0x11, 0xF5, 0x82, 0xE4, +/*0860*/0x34, 0x06, 0xF5, 0x83, 0x22, 0xE5, 0x08, 0xFD, + 0xED, 0x44, 0x07, 0xF5, 0x82, 0x22, 0xE5, 0x41, +/*0870*/0xF0, 0xE5, 0x65, 0x64, 0x01, 0x45, 0x64, 0x22, + 0x7E, 0x00, 0xFB, 0x7A, 0x00, 0xFD, 0x7C, 0x00, +/*0880*/0x22, 0x74, 0x20, 0x25, 0x11, 0xF5, 0x82, 0xE4, + 0x34, 0x02, 0x22, 0x74, 0xA0, 0x25, 0x11, 0xF5, +/*0890*/0x82, 0xE4, 0x34, 0x03, 0x22, 0x85, 0x3E, 0x42, + 0x85, 0x3F, 0x41, 0x8F, 0x40, 0x22, 0x85, 0x3C, +/*08A0*/0x42, 0x85, 0x3D, 0x41, 0x8F, 0x40, 0x22, 0x75, + 0x45, 0x3F, 0x90, 0x07, 0x20, 0xE4, 0xF0, 0xA3, +/*08B0*/0x22, 0xF5, 0x83, 0xE5, 0x32, 0xF0, 0x05, 0x6E, + 0xE5, 0x6E, 0xC3, 0x94, 0x40, 0x22, 0xF0, 0xE5, +/*08C0*/0x08, 0x44, 0x06, 0xF5, 0x82, 0x22, 0x74, 0x00, + 0x25, 0x6E, 0xF5, 0x82, 0xE4, 0x34, 0x00, 0xF5, +/*08D0*/0x83, 0x22, 0xE5, 0x6D, 0x45, 0x6C, 0x90, 0x07, + 0x2F, 0x22, 0xE4, 0xF9, 0xE5, 0x3C, 0xD3, 0x95, +/*08E0*/0x3E, 0x22, 0x74, 0x80, 0x2E, 0xF5, 0x82, 0xE4, + 0x34, 0x02, 0xF5, 0x83, 0xE0, 0x22, 0x74, 0xA0, +/*08F0*/0x2E, 0xF5, 0x82, 0xE4, 0x34, 0x02, 0xF5, 0x83, + 0xE0, 0x22, 0x74, 0x80, 0x25, 0x6E, 0xF5, 0x82, +/*0900*/0xE4, 0x34, 0x00, 0x22, 0x25, 0x42, 0xFD, 0xE4, + 0x33, 0xFC, 0x22, 0x85, 0x42, 0x42, 0x85, 0x41, +/*0910*/0x41, 0x85, 0x40, 0x40, 0x22, 0xED, 0x4C, 0x60, + 0x03, 0x02, 0x09, 0xE5, 0xEF, 0x4E, 0x70, 0x37, +/*0920*/0x90, 0x07, 0x26, 0x12, 0x07, 0x89, 0xE0, 0xFD, + 0x12, 0x07, 0xCC, 0xED, 0xF0, 0x90, 0x07, 0x28, +/*0930*/0x12, 0x07, 0x89, 0xE0, 0xFD, 0x12, 0x07, 0xD8, + 0xED, 0xF0, 0x12, 0x07, 0x86, 0xE0, 0x54, 0x1F, +/*0940*/0xFD, 0x12, 0x08, 0x81, 0xF5, 0x83, 0xED, 0xF0, + 0x90, 0x07, 0x24, 0x12, 0x07, 0x89, 0xE0, 0x54, +/*0950*/0x1F, 0xFD, 0x12, 0x08, 0x35, 0xED, 0xF0, 0xEF, + 0x64, 0x04, 0x4E, 0x70, 0x37, 0x90, 0x07, 0x26, +/*0960*/0x12, 0x07, 0x89, 0xE0, 0xFD, 0x12, 0x07, 0xE4, + 0xED, 0xF0, 0x90, 0x07, 0x28, 0x12, 0x07, 0x89, +/*0970*/0xE0, 0xFD, 0x12, 0x07, 0xF0, 0xED, 0xF0, 0x12, + 0x07, 0x86, 0xE0, 0x54, 0x1F, 0xFD, 0x12, 0x08, +/*0980*/0x8B, 0xF5, 0x83, 0xED, 0xF0, 0x90, 0x07, 0x24, + 0x12, 0x07, 0x89, 0xE0, 0x54, 0x1F, 0xFD, 0x12, +/*0990*/0x08, 0x41, 0xED, 0xF0, 0xEF, 0x64, 0x01, 0x4E, + 0x70, 0x04, 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00, +/*09A0*/0xEF, 0x64, 0x02, 0x4E, 0x70, 0x04, 0x7F, 0x01, + 0x80, 0x02, 0x7F, 0x00, 0xEF, 0x4D, 0x60, 0x78, +/*09B0*/0x90, 0x07, 0x26, 0x12, 0x07, 0x35, 0xE0, 0xFF, + 0x12, 0x07, 0xFC, 0xEF, 0x12, 0x07, 0x31, 0xE0, +/*09C0*/0xFF, 0x12, 0x08, 0x08, 0xEF, 0xF0, 0x90, 0x07, + 0x22, 0x12, 0x07, 0x35, 0xE0, 0x54, 0x1F, 0xFF, +/*09D0*/0x12, 0x08, 0x4D, 0xEF, 0xF0, 0x90, 0x07, 0x24, + 0x12, 0x07, 0x35, 0xE0, 0x54, 0x1F, 0xFF, 0x12, +/*09E0*/0x08, 0x59, 0xEF, 0xF0, 0x22, 0x12, 0x07, 0xCC, + 0xE4, 0xF0, 0x12, 0x07, 0xD8, 0xE4, 0xF0, 0x12, +/*09F0*/0x08, 0x81, 0xF5, 0x83, 0xE4, 0xF0, 0x12, 0x08, + 0x35, 0x74, 0x14, 0xF0, 0x12, 0x07, 0xE4, 0xE4, +/*0A00*/0xF0, 0x12, 0x07, 0xF0, 0xE4, 0xF0, 0x12, 0x08, + 0x8B, 0xF5, 0x83, 0xE4, 0xF0, 0x12, 0x08, 0x41, +/*0A10*/0x74, 0x14, 0xF0, 0x12, 0x07, 0xFC, 0xE4, 0xF0, + 0x12, 0x08, 0x08, 0xE4, 0xF0, 0x12, 0x08, 0x4D, +/*0A20*/0xE4, 0xF0, 0x12, 0x08, 0x59, 0x74, 0x14, 0xF0, + 0x22, 0x53, 0xF9, 0xF7, 0x75, 0xFC, 0x10, 0xE4, +/*0A30*/0xF5, 0xFD, 0x75, 0xFE, 0x30, 0xF5, 0xFF, 0xE5, + 0xE7, 0x20, 0xE7, 0x03, 0x43, 0xF9, 0x08, 0xE5, +/*0A40*/0xE6, 0x20, 0xE7, 0x0B, 0x78, 0xFF, 0xE4, 0xF6, + 0xD8, 0xFD, 0x53, 0xE6, 0xFE, 0x80, 0x09, 0x78, +/*0A50*/0x08, 0xE4, 0xF6, 0xD8, 0xFD, 0x53, 0xE6, 0xFE, + 0x75, 0x81, 0x80, 0xE4, 0xF5, 0xA8, 0xD2, 0xA8, +/*0A60*/0xC2, 0xA9, 0xD2, 0xAF, 0xE5, 0xE2, 0x20, 0xE5, + 0x05, 0x20, 0xE6, 0x02, 0x80, 0x03, 0x43, 0xE1, +/*0A70*/0x02, 0xE5, 0xE2, 0x20, 0xE0, 0x0E, 0x90, 0x00, + 0x00, 0x7F, 0x00, 0x7E, 0x08, 0xE4, 0xF0, 0xA3, +/*0A80*/0xDF, 0xFC, 0xDE, 0xFA, 0x02, 0x0A, 0xDB, 0x43, + 0xFA, 0x01, 0xC0, 0xE0, 0xC0, 0xF0, 0xC0, 0x83, +/*0A90*/0xC0, 0x82, 0xC0, 0xD0, 0x12, 0x1C, 0xE7, 0xD0, + 0xD0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xF0, 0xD0, +/*0AA0*/0xE0, 0x53, 0xFA, 0xFE, 0x32, 0x02, 0x1B, 0x55, + 0xE4, 0x93, 0xA3, 0xF8, 0xE4, 0x93, 0xA3, 0xF6, +/*0AB0*/0x08, 0xDF, 0xF9, 0x80, 0x29, 0xE4, 0x93, 0xA3, + 0xF8, 0x54, 0x07, 0x24, 0x0C, 0xC8, 0xC3, 0x33, +/*0AC0*/0xC4, 0x54, 0x0F, 0x44, 0x20, 0xC8, 0x83, 0x40, + 0x04, 0xF4, 0x56, 0x80, 0x01, 0x46, 0xF6, 0xDF, +/*0AD0*/0xE4, 0x80, 0x0B, 0x01, 0x02, 0x04, 0x08, 0x10, + 0x20, 0x40, 0x80, 0x90, 0x00, 0x3F, 0xE4, 0x7E, +/*0AE0*/0x01, 0x93, 0x60, 0xC1, 0xA3, 0xFF, 0x54, 0x3F, + 0x30, 0xE5, 0x09, 0x54, 0x1F, 0xFE, 0xE4, 0x93, +/*0AF0*/0xA3, 0x60, 0x01, 0x0E, 0xCF, 0x54, 0xC0, 0x25, + 0xE0, 0x60, 0xAD, 0x40, 0xB8, 0x80, 0xFE, 0x8C, +/*0B00*/0x64, 0x8D, 0x65, 0x8A, 0x66, 0x8B, 0x67, 0xE4, + 0xF5, 0x69, 0xEF, 0x4E, 0x70, 0x03, 0x02, 0x1D, +/*0B10*/0x55, 0xE4, 0xF5, 0x68, 0xE5, 0x67, 0x45, 0x66, + 0x70, 0x32, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x90, +/*0B20*/0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, 0xE4, + 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0xE4, 0x12, +/*0B30*/0x08, 0x70, 0x70, 0x29, 0x12, 0x07, 0x2A, 0x75, + 0x83, 0x92, 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, +/*0B40*/0xC6, 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC8, + 0xE4, 0xF0, 0x80, 0x11, 0x90, 0x07, 0x26, 0x12, +/*0B50*/0x07, 0x35, 0xE4, 0x12, 0x08, 0x70, 0x70, 0x05, + 0x12, 0x07, 0x32, 0xE4, 0xF0, 0x12, 0x1D, 0x55, +/*0B60*/0x12, 0x1E, 0xBF, 0xE5, 0x67, 0x45, 0x66, 0x70, + 0x33, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x90, 0xE5, +/*0B70*/0x41, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, 0xE5, + 0x41, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0x12, +/*0B80*/0x08, 0x6E, 0x70, 0x29, 0x12, 0x07, 0x2A, 0x75, + 0x83, 0x92, 0xE5, 0x40, 0x12, 0x07, 0x29, 0x75, +/*0B90*/0x83, 0xC6, 0xE5, 0x40, 0x12, 0x07, 0x29, 0x75, + 0x83, 0xC8, 0x80, 0x0E, 0x90, 0x07, 0x26, 0x12, +/*0BA0*/0x07, 0x35, 0x12, 0x08, 0x6E, 0x70, 0x06, 0x12, + 0x07, 0x32, 0xE5, 0x40, 0xF0, 0xAF, 0x69, 0x7E, +/*0BB0*/0x00, 0xAD, 0x67, 0xAC, 0x66, 0x12, 0x04, 0x44, + 0x12, 0x07, 0x2A, 0x75, 0x83, 0xCA, 0xE0, 0xD3, +/*0BC0*/0x94, 0x00, 0x50, 0x0C, 0x05, 0x68, 0xE5, 0x68, + 0xC3, 0x94, 0x05, 0x50, 0x03, 0x02, 0x0B, 0x14, +/*0BD0*/0x22, 0x8C, 0x60, 0x8D, 0x61, 0x12, 0x08, 0xDA, + 0x74, 0x20, 0x40, 0x0D, 0x2F, 0xF5, 0x82, 0x74, +/*0BE0*/0x03, 0x3E, 0xF5, 0x83, 0xE5, 0x3E, 0xF0, 0x80, + 0x0B, 0x2F, 0xF5, 0x82, 0x74, 0x03, 0x3E, 0xF5, +/*0BF0*/0x83, 0xE5, 0x3C, 0xF0, 0xE5, 0x3C, 0xD3, 0x95, + 0x3E, 0x40, 0x3C, 0xE5, 0x61, 0x45, 0x60, 0x70, +/*0C00*/0x10, 0xE9, 0x12, 0x09, 0x04, 0xE5, 0x3E, 0x12, + 0x07, 0x68, 0x40, 0x3B, 0x12, 0x08, 0x95, 0x80, +/*0C10*/0x18, 0xE5, 0x3E, 0xC3, 0x95, 0x38, 0x40, 0x1D, + 0x85, 0x3E, 0x38, 0xE5, 0x3E, 0x60, 0x05, 0x85, +/*0C20*/0x3F, 0x39, 0x80, 0x03, 0x85, 0x39, 0x39, 0x8F, + 0x3A, 0x12, 0x08, 0x14, 0xE5, 0x3E, 0x12, 0x07, +/*0C30*/0xC0, 0xE5, 0x3F, 0xF0, 0x22, 0x80, 0x43, 0xE5, + 0x61, 0x45, 0x60, 0x70, 0x19, 0x12, 0x07, 0x5F, +/*0C40*/0x40, 0x05, 0x12, 0x08, 0x9E, 0x80, 0x27, 0x12, + 0x09, 0x0B, 0x12, 0x08, 0x14, 0xE5, 0x42, 0x12, +/*0C50*/0x07, 0xC0, 0xE5, 0x41, 0xF0, 0x22, 0xE5, 0x3C, + 0xC3, 0x95, 0x38, 0x40, 0x1D, 0x85, 0x3C, 0x38, +/*0C60*/0xE5, 0x3C, 0x60, 0x05, 0x85, 0x3D, 0x39, 0x80, + 0x03, 0x85, 0x39, 0x39, 0x8F, 0x3A, 0x12, 0x08, +/*0C70*/0x14, 0xE5, 0x3C, 0x12, 0x07, 0xC0, 0xE5, 0x3D, + 0xF0, 0x22, 0x85, 0x38, 0x38, 0x85, 0x39, 0x39, +/*0C80*/0x85, 0x3A, 0x3A, 0x12, 0x08, 0x14, 0xE5, 0x38, + 0x12, 0x07, 0xC0, 0xE5, 0x39, 0xF0, 0x22, 0x7F, +/*0C90*/0x06, 0x12, 0x17, 0x31, 0x12, 0x1D, 0x23, 0x12, + 0x0E, 0x04, 0x12, 0x0E, 0x33, 0xE0, 0x44, 0x0A, +/*0CA0*/0xF0, 0x74, 0x8E, 0xFE, 0x12, 0x0E, 0x04, 0x12, + 0x0E, 0x0B, 0xEF, 0xF0, 0xE5, 0x28, 0x30, 0xE5, +/*0CB0*/0x03, 0xD3, 0x80, 0x01, 0xC3, 0x40, 0x05, 0x75, + 0x14, 0x20, 0x80, 0x03, 0x75, 0x14, 0x08, 0x12, +/*0CC0*/0x0E, 0x04, 0x75, 0x83, 0x8A, 0xE5, 0x14, 0xF0, + 0xB4, 0xFF, 0x05, 0x75, 0x12, 0x80, 0x80, 0x06, +/*0CD0*/0xE5, 0x14, 0xC3, 0x13, 0xF5, 0x12, 0xE4, 0xF5, + 0x16, 0xF5, 0x7F, 0x12, 0x19, 0x36, 0x12, 0x13, +/*0CE0*/0xA3, 0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x50, 0x09, + 0x05, 0x16, 0xE5, 0x16, 0xC3, 0x94, 0x14, 0x40, +/*0CF0*/0xEA, 0xE5, 0xE4, 0x20, 0xE7, 0x28, 0x12, 0x0E, + 0x04, 0x75, 0x83, 0xD2, 0xE0, 0x54, 0x08, 0xD3, +/*0D00*/0x94, 0x00, 0x40, 0x04, 0x7F, 0x01, 0x80, 0x02, + 0x7F, 0x00, 0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x40, +/*0D10*/0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEF, + 0x5E, 0x60, 0x03, 0x12, 0x1D, 0xD7, 0xE5, 0x7F, +/*0D20*/0xC3, 0x94, 0x11, 0x40, 0x14, 0x12, 0x0E, 0x04, + 0x75, 0x83, 0xD2, 0xE0, 0x44, 0x80, 0xF0, 0xE5, +/*0D30*/0xE4, 0x20, 0xE7, 0x0F, 0x12, 0x1D, 0xD7, 0x80, + 0x0A, 0x12, 0x0E, 0x04, 0x75, 0x83, 0xD2, 0xE0, +/*0D40*/0x54, 0x7F, 0xF0, 0x12, 0x1D, 0x23, 0x22, 0x74, + 0x8A, 0x85, 0x08, 0x82, 0xF5, 0x83, 0xE5, 0x17, +/*0D50*/0xF0, 0x12, 0x0E, 0x3A, 0xE4, 0xF0, 0x90, 0x07, + 0x02, 0xE0, 0x12, 0x0E, 0x17, 0x75, 0x83, 0x90, +/*0D60*/0xEF, 0xF0, 0x74, 0x92, 0xFE, 0xE5, 0x08, 0x44, + 0x07, 0xFF, 0xF5, 0x82, 0x8E, 0x83, 0xE0, 0x54, +/*0D70*/0xC0, 0xFD, 0x90, 0x07, 0x03, 0xE0, 0x54, 0x3F, + 0x4D, 0x8F, 0x82, 0x8E, 0x83, 0xF0, 0x90, 0x07, +/*0D80*/0x04, 0xE0, 0x12, 0x0E, 0x17, 0x75, 0x83, 0x82, + 0xEF, 0xF0, 0x90, 0x07, 0x05, 0xE0, 0xFF, 0xED, +/*0D90*/0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0xB4, 0xEF, + 0x12, 0x0E, 0x03, 0x75, 0x83, 0x80, 0xE0, 0x54, +/*0DA0*/0xBF, 0xF0, 0x30, 0x37, 0x0A, 0x12, 0x0E, 0x91, + 0x75, 0x83, 0x94, 0xE0, 0x44, 0x80, 0xF0, 0x30, +/*0DB0*/0x38, 0x0A, 0x12, 0x0E, 0x91, 0x75, 0x83, 0x92, + 0xE0, 0x44, 0x80, 0xF0, 0xE5, 0x28, 0x30, 0xE4, +/*0DC0*/0x1A, 0x20, 0x39, 0x0A, 0x12, 0x0E, 0x04, 0x75, + 0x83, 0x88, 0xE0, 0x54, 0x7F, 0xF0, 0x20, 0x3A, +/*0DD0*/0x0A, 0x12, 0x0E, 0x04, 0x75, 0x83, 0x88, 0xE0, + 0x54, 0xBF, 0xF0, 0x74, 0x8C, 0xFE, 0x12, 0x0E, +/*0DE0*/0x04, 0x8E, 0x83, 0xE0, 0x54, 0x0F, 0x12, 0x0E, + 0x03, 0x75, 0x83, 0x86, 0xE0, 0x54, 0xBF, 0xF0, +/*0DF0*/0xE5, 0x08, 0x44, 0x06, 0x12, 0x0D, 0xFD, 0x75, + 0x83, 0x8A, 0xE4, 0xF0, 0x22, 0xF5, 0x82, 0x75, +/*0E00*/0x83, 0x82, 0xE4, 0xF0, 0xE5, 0x08, 0x44, 0x07, + 0xF5, 0x82, 0x22, 0x8E, 0x83, 0xE0, 0xF5, 0x10, +/*0E10*/0x54, 0xFE, 0xF0, 0xE5, 0x10, 0x44, 0x01, 0xFF, + 0xE5, 0x08, 0xFD, 0xED, 0x44, 0x07, 0xF5, 0x82, +/*0E20*/0x22, 0xE5, 0x15, 0xC4, 0x54, 0x07, 0xFF, 0xE5, + 0x08, 0xFD, 0xED, 0x44, 0x08, 0xF5, 0x82, 0x75, +/*0E30*/0x83, 0x82, 0x22, 0x75, 0x83, 0x80, 0xE0, 0x44, + 0x40, 0xF0, 0xE5, 0x08, 0x44, 0x08, 0xF5, 0x82, +/*0E40*/0x75, 0x83, 0x8A, 0x22, 0xE5, 0x16, 0x25, 0xE0, + 0x25, 0xE0, 0x24, 0xAF, 0xF5, 0x82, 0xE4, 0x34, +/*0E50*/0x1A, 0xF5, 0x83, 0xE4, 0x93, 0xF5, 0x0D, 0x22, + 0x43, 0xE1, 0x10, 0x43, 0xE1, 0x80, 0x53, 0xE1, +/*0E60*/0xFD, 0x85, 0xE1, 0x10, 0x22, 0xE5, 0x16, 0x25, + 0xE0, 0x25, 0xE0, 0x24, 0xB2, 0xF5, 0x82, 0xE4, +/*0E70*/0x34, 0x1A, 0xF5, 0x83, 0xE4, 0x93, 0x22, 0x85, + 0x55, 0x82, 0x85, 0x54, 0x83, 0xE5, 0x15, 0xF0, +/*0E80*/0x22, 0xE5, 0xE2, 0x54, 0x20, 0xD3, 0x94, 0x00, + 0x22, 0xE5, 0xE2, 0x54, 0x40, 0xD3, 0x94, 0x00, +/*0E90*/0x22, 0xE5, 0x08, 0x44, 0x06, 0xF5, 0x82, 0x22, + 0xFD, 0xE5, 0x08, 0xFB, 0xEB, 0x44, 0x07, 0xF5, +/*0EA0*/0x82, 0x22, 0x53, 0xF9, 0xF7, 0x75, 0xFE, 0x30, + 0x22, 0xEF, 0x4E, 0x70, 0x26, 0x12, 0x07, 0xCC, +/*0EB0*/0xE0, 0xFD, 0x90, 0x07, 0x26, 0x12, 0x07, 0x7B, + 0x12, 0x07, 0xD8, 0xE0, 0xFD, 0x90, 0x07, 0x28, +/*0EC0*/0x12, 0x07, 0x7B, 0x12, 0x08, 0x81, 0x12, 0x07, + 0x72, 0x12, 0x08, 0x35, 0xE0, 0x90, 0x07, 0x24, +/*0ED0*/0x12, 0x07, 0x78, 0xEF, 0x64, 0x04, 0x4E, 0x70, + 0x29, 0x12, 0x07, 0xE4, 0xE0, 0xFD, 0x90, 0x07, +/*0EE0*/0x26, 0x12, 0x07, 0x7B, 0x12, 0x07, 0xF0, 0xE0, + 0xFD, 0x90, 0x07, 0x28, 0x12, 0x07, 0x7B, 0x12, +/*0EF0*/0x08, 0x8B, 0x12, 0x07, 0x72, 0x12, 0x08, 0x41, + 0xE0, 0x54, 0x1F, 0xFD, 0x90, 0x07, 0x24, 0x12, +/*0F00*/0x07, 0x7B, 0xEF, 0x64, 0x01, 0x4E, 0x70, 0x04, + 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00, 0xEF, 0x64, +/*0F10*/0x02, 0x4E, 0x70, 0x04, 0x7F, 0x01, 0x80, 0x02, + 0x7F, 0x00, 0xEF, 0x4D, 0x60, 0x35, 0x12, 0x07, +/*0F20*/0xFC, 0xE0, 0xFF, 0x90, 0x07, 0x26, 0x12, 0x07, + 0x89, 0xEF, 0xF0, 0x12, 0x08, 0x08, 0xE0, 0xFF, +/*0F30*/0x90, 0x07, 0x28, 0x12, 0x07, 0x89, 0xEF, 0xF0, + 0x12, 0x08, 0x4D, 0xE0, 0x54, 0x1F, 0xFF, 0x12, +/*0F40*/0x07, 0x86, 0xEF, 0xF0, 0x12, 0x08, 0x59, 0xE0, + 0x54, 0x1F, 0xFF, 0x90, 0x07, 0x24, 0x12, 0x07, +/*0F50*/0x89, 0xEF, 0xF0, 0x22, 0xE4, 0xF5, 0x53, 0x12, + 0x0E, 0x81, 0x40, 0x04, 0x7F, 0x01, 0x80, 0x02, +/*0F60*/0x7F, 0x00, 0x12, 0x0E, 0x89, 0x40, 0x04, 0x7E, + 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, 0x70, +/*0F70*/0x03, 0x02, 0x0F, 0xF6, 0x85, 0xE1, 0x10, 0x43, + 0xE1, 0x02, 0x53, 0xE1, 0x0F, 0x85, 0xE1, 0x10, +/*0F80*/0xE4, 0xF5, 0x51, 0xE5, 0xE3, 0x54, 0x3F, 0xF5, + 0x52, 0x12, 0x0E, 0x89, 0x40, 0x1D, 0xAD, 0x52, +/*0F90*/0xAF, 0x51, 0x12, 0x11, 0x18, 0xEF, 0x60, 0x08, + 0x85, 0xE1, 0x10, 0x43, 0xE1, 0x40, 0x80, 0x0B, +/*0FA0*/0x53, 0xE1, 0xBF, 0x12, 0x0E, 0x58, 0x12, 0x00, + 0x06, 0x80, 0xFB, 0xE5, 0xE3, 0x54, 0x3F, 0xF5, +/*0FB0*/0x51, 0xE5, 0xE4, 0x54, 0x3F, 0xF5, 0x52, 0x12, + 0x0E, 0x81, 0x40, 0x1D, 0xAD, 0x52, 0xAF, 0x51, +/*0FC0*/0x12, 0x11, 0x18, 0xEF, 0x60, 0x08, 0x85, 0xE1, + 0x10, 0x43, 0xE1, 0x20, 0x80, 0x0B, 0x53, 0xE1, +/*0FD0*/0xDF, 0x12, 0x0E, 0x58, 0x12, 0x00, 0x06, 0x80, + 0xFB, 0x12, 0x0E, 0x81, 0x40, 0x04, 0x7F, 0x01, +/*0FE0*/0x80, 0x02, 0x7F, 0x00, 0x12, 0x0E, 0x89, 0x40, + 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, +/*0FF0*/0x4F, 0x60, 0x03, 0x12, 0x0E, 0x5B, 0x22, 0x12, + 0x0E, 0x21, 0xEF, 0xF0, 0x12, 0x10, 0x91, 0x22, +/*1000*/0x02, 0x11, 0x00, 0x02, 0x10, 0x40, 0x02, 0x10, + 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1010*/0x01, 0x20, 0x01, 0x20, 0xE4, 0xF5, 0x57, 0x12, + 0x16, 0xBD, 0x12, 0x16, 0x44, 0xE4, 0x12, 0x10, +/*1020*/0x56, 0x12, 0x14, 0xB7, 0x90, 0x07, 0x26, 0x12, + 0x07, 0x35, 0xE4, 0x12, 0x07, 0x31, 0xE4, 0xF0, +/*1030*/0x12, 0x10, 0x56, 0x12, 0x14, 0xB7, 0x90, 0x07, + 0x26, 0x12, 0x07, 0x35, 0xE5, 0x41, 0x12, 0x07, +/*1040*/0x31, 0xE5, 0x40, 0xF0, 0xAF, 0x57, 0x7E, 0x00, + 0xAD, 0x56, 0x7C, 0x00, 0x12, 0x04, 0x44, 0xAF, +/*1050*/0x56, 0x7E, 0x00, 0x02, 0x11, 0xEE, 0xFF, 0x90, + 0x07, 0x20, 0xA3, 0xE0, 0xFD, 0xE4, 0xF5, 0x56, +/*1060*/0xF5, 0x40, 0xFE, 0xFC, 0xAB, 0x56, 0xFA, 0x12, + 0x11, 0x51, 0x7F, 0x0F, 0x7D, 0x18, 0xE4, 0xF5, +/*1070*/0x56, 0xF5, 0x40, 0xFE, 0xFC, 0xAB, 0x56, 0xFA, + 0x12, 0x15, 0x41, 0xAF, 0x56, 0x7E, 0x00, 0x12, +/*1080*/0x1A, 0xFF, 0xE4, 0xFF, 0xF5, 0x56, 0x7D, 0x1F, + 0xF5, 0x40, 0xFE, 0xFC, 0xAB, 0x56, 0xFA, 0x22, +/*1090*/0x22, 0xE4, 0xF5, 0x55, 0xE5, 0x08, 0xFD, 0x74, + 0xA0, 0xF5, 0x56, 0xED, 0x44, 0x07, 0xF5, 0x57, +/*10A0*/0xE5, 0x28, 0x30, 0xE5, 0x03, 0xD3, 0x80, 0x01, + 0xC3, 0x40, 0x05, 0x7F, 0x28, 0xEF, 0x80, 0x04, +/*10B0*/0x7F, 0x14, 0xEF, 0xC3, 0x13, 0xF5, 0x54, 0xE4, + 0xF9, 0x12, 0x0E, 0x18, 0x75, 0x83, 0x8E, 0xE0, +/*10C0*/0xF5, 0x10, 0xCE, 0xEF, 0xCE, 0xEE, 0xD3, 0x94, + 0x00, 0x40, 0x26, 0xE5, 0x10, 0x54, 0xFE, 0x12, +/*10D0*/0x0E, 0x98, 0x75, 0x83, 0x8E, 0xED, 0xF0, 0xE5, + 0x10, 0x44, 0x01, 0xFD, 0xEB, 0x44, 0x07, 0xF5, +/*10E0*/0x82, 0xED, 0xF0, 0x85, 0x57, 0x82, 0x85, 0x56, + 0x83, 0xE0, 0x30, 0xE3, 0x01, 0x09, 0x1E, 0x80, +/*10F0*/0xD4, 0xC2, 0x34, 0xE9, 0xC3, 0x95, 0x54, 0x40, + 0x02, 0xD2, 0x34, 0x22, 0x02, 0x00, 0x06, 0x22, +/*1100*/0x30, 0x30, 0x11, 0x90, 0x10, 0x00, 0xE4, 0x93, + 0xF5, 0x10, 0x90, 0x10, 0x10, 0xE4, 0x93, 0xF5, +/*1110*/0x10, 0x12, 0x10, 0x90, 0x12, 0x11, 0x50, 0x22, + 0xE4, 0xFC, 0xC3, 0xED, 0x9F, 0xFA, 0xEF, 0xF5, +/*1120*/0x83, 0x75, 0x82, 0x00, 0x79, 0xFF, 0xE4, 0x93, + 0xCC, 0x6C, 0xCC, 0xA3, 0xD9, 0xF8, 0xDA, 0xF6, +/*1130*/0xE5, 0xE2, 0x30, 0xE4, 0x02, 0x8C, 0xE5, 0xED, + 0x24, 0xFF, 0xFF, 0xEF, 0x75, 0x82, 0xFF, 0xF5, +/*1140*/0x83, 0xE4, 0x93, 0x6C, 0x70, 0x03, 0x7F, 0x01, + 0x22, 0x7F, 0x00, 0x22, 0x22, 0x11, 0x00, 0x00, +/*1150*/0x22, 0x8E, 0x58, 0x8F, 0x59, 0x8C, 0x5A, 0x8D, + 0x5B, 0x8A, 0x5C, 0x8B, 0x5D, 0x75, 0x5E, 0x01, +/*1160*/0xE4, 0xF5, 0x5F, 0xF5, 0x60, 0xF5, 0x62, 0x12, + 0x07, 0x2A, 0x75, 0x83, 0xD0, 0xE0, 0xFF, 0xC4, +/*1170*/0x54, 0x0F, 0xF5, 0x61, 0x12, 0x1E, 0xA5, 0x85, + 0x59, 0x5E, 0xD3, 0xE5, 0x5E, 0x95, 0x5B, 0xE5, +/*1180*/0x5A, 0x12, 0x07, 0x6B, 0x50, 0x4B, 0x12, 0x07, + 0x03, 0x75, 0x83, 0xBC, 0xE0, 0x45, 0x5E, 0x12, +/*1190*/0x07, 0x29, 0x75, 0x83, 0xBE, 0xE0, 0x45, 0x5E, + 0x12, 0x07, 0x29, 0x75, 0x83, 0xC0, 0xE0, 0x45, +/*11A0*/0x5E, 0xF0, 0xAF, 0x5F, 0xE5, 0x60, 0x12, 0x08, + 0x78, 0x12, 0x0A, 0xFF, 0xAF, 0x62, 0x7E, 0x00, +/*11B0*/0xAD, 0x5D, 0xAC, 0x5C, 0x12, 0x04, 0x44, 0xE5, + 0x61, 0xAF, 0x5E, 0x7E, 0x00, 0xB4, 0x03, 0x05, +/*11C0*/0x12, 0x1E, 0x21, 0x80, 0x07, 0xAD, 0x5D, 0xAC, + 0x5C, 0x12, 0x13, 0x17, 0x05, 0x5E, 0x02, 0x11, +/*11D0*/0x7A, 0x12, 0x07, 0x03, 0x75, 0x83, 0xBC, 0xE0, + 0x45, 0x40, 0x12, 0x07, 0x29, 0x75, 0x83, 0xBE, +/*11E0*/0xE0, 0x45, 0x40, 0x12, 0x07, 0x29, 0x75, 0x83, + 0xC0, 0xE0, 0x45, 0x40, 0xF0, 0x22, 0x8E, 0x58, +/*11F0*/0x8F, 0x59, 0x75, 0x5A, 0x01, 0x79, 0x01, 0x75, + 0x5B, 0x01, 0xE4, 0xFB, 0x12, 0x07, 0x2A, 0x75, +/*1200*/0x83, 0xAE, 0xE0, 0x54, 0x1A, 0xFF, 0x12, 0x08, + 0x65, 0xE0, 0xC4, 0x13, 0x54, 0x07, 0xFE, 0xEF, +/*1210*/0x70, 0x0C, 0xEE, 0x65, 0x35, 0x70, 0x07, 0x90, + 0x07, 0x2F, 0xE0, 0xB4, 0x01, 0x0D, 0xAF, 0x35, +/*1220*/0x7E, 0x00, 0x12, 0x0E, 0xA9, 0xCF, 0xEB, 0xCF, + 0x02, 0x1E, 0x60, 0xE5, 0x59, 0x64, 0x02, 0x45, +/*1230*/0x58, 0x70, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, + 0x00, 0xE5, 0x59, 0x45, 0x58, 0x70, 0x04, 0x7E, +/*1240*/0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, 0x60, + 0x23, 0x85, 0x41, 0x49, 0x85, 0x40, 0x4B, 0xE5, +/*1250*/0x59, 0x45, 0x58, 0x70, 0x2C, 0xAF, 0x5A, 0xFE, + 0xCD, 0xE9, 0xCD, 0xFC, 0xAB, 0x59, 0xAA, 0x58, +/*1260*/0x12, 0x0A, 0xFF, 0xAF, 0x5B, 0x7E, 0x00, 0x12, + 0x1E, 0x60, 0x80, 0x15, 0xAF, 0x5B, 0x7E, 0x00, +/*1270*/0x12, 0x1E, 0x60, 0x90, 0x07, 0x26, 0x12, 0x07, + 0x35, 0xE5, 0x49, 0x12, 0x07, 0x31, 0xE5, 0x4B, +/*1280*/0xF0, 0xE4, 0xFD, 0xAF, 0x35, 0xFE, 0xFC, 0x12, + 0x09, 0x15, 0x22, 0x8C, 0x64, 0x8D, 0x65, 0x12, +/*1290*/0x08, 0xDA, 0x40, 0x3C, 0xE5, 0x65, 0x45, 0x64, + 0x70, 0x10, 0x12, 0x09, 0x04, 0xC3, 0xE5, 0x3E, +/*12A0*/0x12, 0x07, 0x69, 0x40, 0x3B, 0x12, 0x08, 0x95, + 0x80, 0x18, 0xE5, 0x3E, 0xC3, 0x95, 0x38, 0x40, +/*12B0*/0x1D, 0x85, 0x3E, 0x38, 0xE5, 0x3E, 0x60, 0x05, + 0x85, 0x3F, 0x39, 0x80, 0x03, 0x85, 0x39, 0x39, +/*12C0*/0x8F, 0x3A, 0x12, 0x07, 0xA8, 0xE5, 0x3E, 0x12, + 0x07, 0x53, 0xE5, 0x3F, 0xF0, 0x22, 0x80, 0x3B, +/*12D0*/0xE5, 0x65, 0x45, 0x64, 0x70, 0x11, 0x12, 0x07, + 0x5F, 0x40, 0x05, 0x12, 0x08, 0x9E, 0x80, 0x1F, +/*12E0*/0x12, 0x07, 0x3E, 0xE5, 0x41, 0xF0, 0x22, 0xE5, + 0x3C, 0xC3, 0x95, 0x38, 0x40, 0x1D, 0x85, 0x3C, +/*12F0*/0x38, 0xE5, 0x3C, 0x60, 0x05, 0x85, 0x3D, 0x39, + 0x80, 0x03, 0x85, 0x39, 0x39, 0x8F, 0x3A, 0x12, +/*1300*/0x07, 0xA8, 0xE5, 0x3C, 0x12, 0x07, 0x53, 0xE5, + 0x3D, 0xF0, 0x22, 0x12, 0x07, 0x9F, 0xE5, 0x38, +/*1310*/0x12, 0x07, 0x53, 0xE5, 0x39, 0xF0, 0x22, 0x8C, + 0x63, 0x8D, 0x64, 0x12, 0x08, 0xDA, 0x40, 0x3C, +/*1320*/0xE5, 0x64, 0x45, 0x63, 0x70, 0x10, 0x12, 0x09, + 0x04, 0xC3, 0xE5, 0x3E, 0x12, 0x07, 0x69, 0x40, +/*1330*/0x3B, 0x12, 0x08, 0x95, 0x80, 0x18, 0xE5, 0x3E, + 0xC3, 0x95, 0x38, 0x40, 0x1D, 0x85, 0x3E, 0x38, +/*1340*/0xE5, 0x3E, 0x60, 0x05, 0x85, 0x3F, 0x39, 0x80, + 0x03, 0x85, 0x39, 0x39, 0x8F, 0x3A, 0x12, 0x07, +/*1350*/0xA8, 0xE5, 0x3E, 0x12, 0x07, 0x53, 0xE5, 0x3F, + 0xF0, 0x22, 0x80, 0x3B, 0xE5, 0x64, 0x45, 0x63, +/*1360*/0x70, 0x11, 0x12, 0x07, 0x5F, 0x40, 0x05, 0x12, + 0x08, 0x9E, 0x80, 0x1F, 0x12, 0x07, 0x3E, 0xE5, +/*1370*/0x41, 0xF0, 0x22, 0xE5, 0x3C, 0xC3, 0x95, 0x38, + 0x40, 0x1D, 0x85, 0x3C, 0x38, 0xE5, 0x3C, 0x60, +/*1380*/0x05, 0x85, 0x3D, 0x39, 0x80, 0x03, 0x85, 0x39, + 0x39, 0x8F, 0x3A, 0x12, 0x07, 0xA8, 0xE5, 0x3C, +/*1390*/0x12, 0x07, 0x53, 0xE5, 0x3D, 0xF0, 0x22, 0x12, + 0x07, 0x9F, 0xE5, 0x38, 0x12, 0x07, 0x53, 0xE5, +/*13A0*/0x39, 0xF0, 0x22, 0xE5, 0x0D, 0xFE, 0xE5, 0x08, + 0x8E, 0x54, 0x44, 0x05, 0xF5, 0x55, 0x75, 0x15, +/*13B0*/0x0F, 0xF5, 0x82, 0x12, 0x0E, 0x7A, 0x12, 0x17, + 0xA3, 0x20, 0x31, 0x05, 0x75, 0x15, 0x03, 0x80, +/*13C0*/0x03, 0x75, 0x15, 0x0B, 0xE5, 0x0A, 0xC3, 0x94, + 0x01, 0x50, 0x38, 0x12, 0x14, 0x20, 0x20, 0x31, +/*13D0*/0x06, 0x05, 0x15, 0x05, 0x15, 0x80, 0x04, 0x15, + 0x15, 0x15, 0x15, 0xE5, 0x0A, 0xC3, 0x94, 0x01, +/*13E0*/0x50, 0x21, 0x12, 0x14, 0x20, 0x20, 0x31, 0x04, + 0x05, 0x15, 0x80, 0x02, 0x15, 0x15, 0xE5, 0x0A, +/*13F0*/0xC3, 0x94, 0x01, 0x50, 0x0E, 0x12, 0x0E, 0x77, + 0x12, 0x17, 0xA3, 0x20, 0x31, 0x05, 0x05, 0x15, +/*1400*/0x12, 0x0E, 0x77, 0xE5, 0x15, 0xB4, 0x08, 0x04, + 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x15, +/*1410*/0xB4, 0x07, 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, + 0x00, 0xEE, 0x4F, 0x60, 0x02, 0x05, 0x7F, 0x22, +/*1420*/0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xE5, 0x15, + 0xF0, 0x12, 0x17, 0xA3, 0x22, 0x12, 0x07, 0x2A, +/*1430*/0x75, 0x83, 0xAE, 0x74, 0xFF, 0x12, 0x07, 0x29, + 0xE0, 0x54, 0x1A, 0xF5, 0x34, 0xE0, 0xC4, 0x13, +/*1440*/0x54, 0x07, 0xF5, 0x35, 0x24, 0xFE, 0x60, 0x24, + 0x24, 0xFE, 0x60, 0x3C, 0x24, 0x04, 0x70, 0x63, +/*1450*/0x75, 0x31, 0x2D, 0xE5, 0x08, 0xFD, 0x74, 0xB6, + 0x12, 0x07, 0x92, 0x74, 0xBC, 0x90, 0x07, 0x22, +/*1460*/0x12, 0x07, 0x95, 0x74, 0x90, 0x12, 0x07, 0xB3, + 0x74, 0x92, 0x80, 0x3C, 0x75, 0x31, 0x3A, 0xE5, +/*1470*/0x08, 0xFD, 0x74, 0xBA, 0x12, 0x07, 0x92, 0x74, + 0xC0, 0x90, 0x07, 0x22, 0x12, 0x07, 0xB6, 0x74, +/*1480*/0xC4, 0x12, 0x07, 0xB3, 0x74, 0xC8, 0x80, 0x20, + 0x75, 0x31, 0x35, 0xE5, 0x08, 0xFD, 0x74, 0xB8, +/*1490*/0x12, 0x07, 0x92, 0x74, 0xBE, 0xFF, 0xED, 0x44, + 0x07, 0x90, 0x07, 0x22, 0xCF, 0xF0, 0xA3, 0xEF, +/*14A0*/0xF0, 0x74, 0xC2, 0x12, 0x07, 0xB3, 0x74, 0xC6, + 0xFF, 0xED, 0x44, 0x07, 0xA3, 0xCF, 0xF0, 0xA3, +/*14B0*/0xEF, 0xF0, 0x22, 0x75, 0x34, 0x01, 0x22, 0x8E, + 0x58, 0x8F, 0x59, 0x8C, 0x5A, 0x8D, 0x5B, 0x8A, +/*14C0*/0x5C, 0x8B, 0x5D, 0x75, 0x5E, 0x01, 0xE4, 0xF5, + 0x5F, 0x12, 0x1E, 0xA5, 0x85, 0x59, 0x5E, 0xD3, +/*14D0*/0xE5, 0x5E, 0x95, 0x5B, 0xE5, 0x5A, 0x12, 0x07, + 0x6B, 0x50, 0x57, 0xE5, 0x5D, 0x45, 0x5C, 0x70, +/*14E0*/0x30, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x92, 0xE5, + 0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC6, 0xE5, +/*14F0*/0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC8, 0xE5, + 0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0x90, 0xE5, +/*1500*/0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, 0xE5, + 0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0x80, +/*1510*/0x03, 0x12, 0x07, 0x32, 0xE5, 0x5E, 0xF0, 0xAF, + 0x5F, 0x7E, 0x00, 0xAD, 0x5D, 0xAC, 0x5C, 0x12, +/*1520*/0x04, 0x44, 0xAF, 0x5E, 0x7E, 0x00, 0xAD, 0x5D, + 0xAC, 0x5C, 0x12, 0x0B, 0xD1, 0x05, 0x5E, 0x02, +/*1530*/0x14, 0xCF, 0xAB, 0x5D, 0xAA, 0x5C, 0xAD, 0x5B, + 0xAC, 0x5A, 0xAF, 0x59, 0xAE, 0x58, 0x02, 0x1B, +/*1540*/0xFB, 0x8C, 0x5C, 0x8D, 0x5D, 0x8A, 0x5E, 0x8B, + 0x5F, 0x75, 0x60, 0x01, 0xE4, 0xF5, 0x61, 0xF5, +/*1550*/0x62, 0xF5, 0x63, 0x12, 0x1E, 0xA5, 0x8F, 0x60, + 0xD3, 0xE5, 0x60, 0x95, 0x5D, 0xE5, 0x5C, 0x12, +/*1560*/0x07, 0x6B, 0x50, 0x61, 0xE5, 0x5F, 0x45, 0x5E, + 0x70, 0x27, 0x12, 0x07, 0x2A, 0x75, 0x83, 0xB6, +/*1570*/0xE5, 0x60, 0x12, 0x07, 0x29, 0x75, 0x83, 0xB8, + 0xE5, 0x60, 0x12, 0x07, 0x29, 0x75, 0x83, 0xBA, +/*1580*/0xE5, 0x60, 0xF0, 0xAF, 0x61, 0x7E, 0x00, 0xE5, + 0x62, 0x12, 0x08, 0x7A, 0x12, 0x0A, 0xFF, 0x80, +/*1590*/0x19, 0x90, 0x07, 0x24, 0x12, 0x07, 0x35, 0xE5, + 0x60, 0x12, 0x07, 0x29, 0x75, 0x83, 0x8E, 0xE4, +/*15A0*/0x12, 0x07, 0x29, 0x74, 0x01, 0x12, 0x07, 0x29, + 0xE4, 0xF0, 0xAF, 0x63, 0x7E, 0x00, 0xAD, 0x5F, +/*15B0*/0xAC, 0x5E, 0x12, 0x04, 0x44, 0xAF, 0x60, 0x7E, + 0x00, 0xAD, 0x5F, 0xAC, 0x5E, 0x12, 0x12, 0x8B, +/*15C0*/0x05, 0x60, 0x02, 0x15, 0x58, 0x22, 0x90, 0x11, + 0x4D, 0xE4, 0x93, 0x90, 0x07, 0x2E, 0xF0, 0x12, +/*15D0*/0x08, 0x1F, 0x75, 0x83, 0xAE, 0xE0, 0x54, 0x1A, + 0xF5, 0x34, 0x70, 0x67, 0xEF, 0x44, 0x07, 0xF5, +/*15E0*/0x82, 0x75, 0x83, 0xCE, 0xE0, 0xFF, 0x13, 0x13, + 0x13, 0x54, 0x07, 0xF5, 0x36, 0x54, 0x0F, 0xD3, +/*15F0*/0x94, 0x00, 0x40, 0x06, 0x12, 0x14, 0x2D, 0x12, + 0x1B, 0xA9, 0xE5, 0x36, 0x54, 0x0F, 0x24, 0xFE, +/*1600*/0x60, 0x0C, 0x14, 0x60, 0x0C, 0x14, 0x60, 0x19, + 0x24, 0x03, 0x70, 0x37, 0x80, 0x10, 0x02, 0x1E, +/*1610*/0x91, 0x12, 0x1E, 0x91, 0x12, 0x07, 0x2A, 0x75, + 0x83, 0xCE, 0xE0, 0x54, 0xEF, 0xF0, 0x02, 0x1D, +/*1620*/0xAE, 0x12, 0x10, 0x14, 0xE4, 0xF5, 0x55, 0x12, + 0x1D, 0x85, 0x05, 0x55, 0xE5, 0x55, 0xC3, 0x94, +/*1630*/0x05, 0x40, 0xF4, 0x12, 0x07, 0x2A, 0x75, 0x83, + 0xCE, 0xE0, 0x54, 0xC7, 0x12, 0x07, 0x29, 0xE0, +/*1640*/0x44, 0x08, 0xF0, 0x22, 0xE4, 0xF5, 0x58, 0xF5, + 0x59, 0xAF, 0x08, 0xEF, 0x44, 0x07, 0xF5, 0x82, +/*1650*/0x75, 0x83, 0xD0, 0xE0, 0xFD, 0xC4, 0x54, 0x0F, + 0xF5, 0x5A, 0xEF, 0x44, 0x07, 0xF5, 0x82, 0x75, +/*1660*/0x83, 0x80, 0x74, 0x01, 0xF0, 0x12, 0x08, 0x21, + 0x75, 0x83, 0x82, 0xE5, 0x45, 0xF0, 0xEF, 0x44, +/*1670*/0x07, 0xF5, 0x82, 0x75, 0x83, 0x8A, 0x74, 0xFF, + 0xF0, 0x12, 0x1A, 0x4D, 0x12, 0x07, 0x2A, 0x75, +/*1680*/0x83, 0xBC, 0xE0, 0x54, 0xEF, 0x12, 0x07, 0x29, + 0x75, 0x83, 0xBE, 0xE0, 0x54, 0xEF, 0x12, 0x07, +/*1690*/0x29, 0x75, 0x83, 0xC0, 0xE0, 0x54, 0xEF, 0x12, + 0x07, 0x29, 0x75, 0x83, 0xBC, 0xE0, 0x44, 0x10, +/*16A0*/0x12, 0x07, 0x29, 0x75, 0x83, 0xBE, 0xE0, 0x44, + 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC0, 0xE0, +/*16B0*/0x44, 0x10, 0xF0, 0xAF, 0x58, 0xE5, 0x59, 0x12, + 0x08, 0x78, 0x02, 0x0A, 0xFF, 0xE4, 0xF5, 0x58, +/*16C0*/0x7D, 0x01, 0xF5, 0x59, 0xAF, 0x35, 0xFE, 0xFC, + 0x12, 0x09, 0x15, 0x12, 0x07, 0x2A, 0x75, 0x83, +/*16D0*/0xB6, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, + 0xB8, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, +/*16E0*/0xBA, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, + 0xBC, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, +/*16F0*/0xBE, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, + 0xC0, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, +/*1700*/0x90, 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, + 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0xE4, +/*1710*/0x12, 0x07, 0x29, 0x75, 0x83, 0x92, 0xE4, 0x12, + 0x07, 0x29, 0x75, 0x83, 0xC6, 0xE4, 0x12, 0x07, +/*1720*/0x29, 0x75, 0x83, 0xC8, 0xE4, 0xF0, 0xAF, 0x58, + 0xFE, 0xE5, 0x59, 0x12, 0x08, 0x7A, 0x02, 0x0A, +/*1730*/0xFF, 0xE5, 0xE2, 0x30, 0xE4, 0x6C, 0xE5, 0xE7, + 0x54, 0xC0, 0x64, 0x40, 0x70, 0x64, 0xE5, 0x09, +/*1740*/0xC4, 0x54, 0x30, 0xFE, 0xE5, 0x08, 0x25, 0xE0, + 0x25, 0xE0, 0x54, 0xC0, 0x4E, 0xFE, 0xEF, 0x54, +/*1750*/0x3F, 0x4E, 0xFD, 0xE5, 0x2B, 0xAE, 0x2A, 0x78, + 0x02, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9, +/*1760*/0xF5, 0x82, 0x8E, 0x83, 0xED, 0xF0, 0xE5, 0x2B, + 0xAE, 0x2A, 0x78, 0x02, 0xC3, 0x33, 0xCE, 0x33, +/*1770*/0xCE, 0xD8, 0xF9, 0xFF, 0xF5, 0x82, 0x8E, 0x83, + 0xA3, 0xE5, 0xFE, 0xF0, 0x8F, 0x82, 0x8E, 0x83, +/*1780*/0xA3, 0xA3, 0xE5, 0xFD, 0xF0, 0x8F, 0x82, 0x8E, + 0x83, 0xA3, 0xA3, 0xA3, 0xE5, 0xFC, 0xF0, 0xC3, +/*1790*/0xE5, 0x2B, 0x94, 0xFA, 0xE5, 0x2A, 0x94, 0x00, + 0x50, 0x08, 0x05, 0x2B, 0xE5, 0x2B, 0x70, 0x02, +/*17A0*/0x05, 0x2A, 0x22, 0xE4, 0xFF, 0xE4, 0xF5, 0x58, + 0xF5, 0x56, 0xF5, 0x57, 0x74, 0x82, 0xFC, 0x12, +/*17B0*/0x0E, 0x04, 0x8C, 0x83, 0xE0, 0xF5, 0x10, 0x54, + 0x7F, 0xF0, 0xE5, 0x10, 0x44, 0x80, 0x12, 0x0E, +/*17C0*/0x98, 0xED, 0xF0, 0x7E, 0x0A, 0x12, 0x0E, 0x04, + 0x75, 0x83, 0xA0, 0xE0, 0x20, 0xE0, 0x26, 0xDE, +/*17D0*/0xF4, 0x05, 0x57, 0xE5, 0x57, 0x70, 0x02, 0x05, + 0x56, 0xE5, 0x14, 0x24, 0x01, 0xFD, 0xE4, 0x33, +/*17E0*/0xFC, 0xD3, 0xE5, 0x57, 0x9D, 0xE5, 0x56, 0x9C, + 0x40, 0xD9, 0xE5, 0x0A, 0x94, 0x20, 0x50, 0x02, +/*17F0*/0x05, 0x0A, 0x43, 0xE1, 0x08, 0xC2, 0x31, 0x12, + 0x0E, 0x04, 0x75, 0x83, 0xA6, 0xE0, 0x55, 0x12, +/*1800*/0x65, 0x12, 0x70, 0x03, 0xD2, 0x31, 0x22, 0xC2, + 0x31, 0x22, 0x90, 0x07, 0x26, 0xE0, 0xFA, 0xA3, +/*1810*/0xE0, 0xF5, 0x82, 0x8A, 0x83, 0xE0, 0xF5, 0x41, + 0xE5, 0x39, 0xC3, 0x95, 0x41, 0x40, 0x26, 0xE5, +/*1820*/0x39, 0x95, 0x41, 0xC3, 0x9F, 0xEE, 0x12, 0x07, + 0x6B, 0x40, 0x04, 0x7C, 0x01, 0x80, 0x02, 0x7C, +/*1830*/0x00, 0xE5, 0x41, 0x64, 0x3F, 0x60, 0x04, 0x7B, + 0x01, 0x80, 0x02, 0x7B, 0x00, 0xEC, 0x5B, 0x60, +/*1840*/0x29, 0x05, 0x41, 0x80, 0x28, 0xC3, 0xE5, 0x41, + 0x95, 0x39, 0xC3, 0x9F, 0xEE, 0x12, 0x07, 0x6B, +/*1850*/0x40, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, + 0xE5, 0x41, 0x60, 0x04, 0x7E, 0x01, 0x80, 0x02, +/*1860*/0x7E, 0x00, 0xEF, 0x5E, 0x60, 0x04, 0x15, 0x41, + 0x80, 0x03, 0x85, 0x39, 0x41, 0x85, 0x3A, 0x40, +/*1870*/0x22, 0xE5, 0xE2, 0x30, 0xE4, 0x60, 0xE5, 0xE1, + 0x30, 0xE2, 0x5B, 0xE5, 0x09, 0x70, 0x04, 0x7F, +/*1880*/0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x08, 0x70, + 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, +/*1890*/0x5F, 0x60, 0x43, 0x53, 0xF9, 0xF8, 0xE5, 0xE2, + 0x30, 0xE4, 0x3B, 0xE5, 0xE1, 0x30, 0xE2, 0x2E, +/*18A0*/0x43, 0xFA, 0x02, 0x53, 0xFA, 0xFB, 0xE4, 0xF5, + 0x10, 0x90, 0x94, 0x70, 0xE5, 0x10, 0xF0, 0xE5, +/*18B0*/0xE1, 0x30, 0xE2, 0xE7, 0x90, 0x94, 0x70, 0xE0, + 0x65, 0x10, 0x60, 0x03, 0x43, 0xFA, 0x04, 0x05, +/*18C0*/0x10, 0x90, 0x94, 0x70, 0xE5, 0x10, 0xF0, 0x70, + 0xE6, 0x12, 0x00, 0x06, 0x80, 0xE1, 0x53, 0xFA, +/*18D0*/0xFD, 0x53, 0xFA, 0xFB, 0x80, 0xC0, 0x22, 0x8F, + 0x54, 0x12, 0x00, 0x06, 0xE5, 0xE1, 0x30, 0xE0, +/*18E0*/0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, + 0x7E, 0xD3, 0x94, 0x05, 0x40, 0x04, 0x7E, 0x01, +/*18F0*/0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, 0x60, 0x3D, + 0x85, 0x54, 0x11, 0xE5, 0xE2, 0x20, 0xE1, 0x32, +/*1900*/0x74, 0xCE, 0x12, 0x1A, 0x05, 0x30, 0xE7, 0x04, + 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00, 0x8F, 0x82, +/*1910*/0x8E, 0x83, 0xE0, 0x30, 0xE6, 0x04, 0x7F, 0x01, + 0x80, 0x02, 0x7F, 0x00, 0xEF, 0x5D, 0x70, 0x15, +/*1920*/0x12, 0x15, 0xC6, 0x74, 0xCE, 0x12, 0x1A, 0x05, + 0x30, 0xE6, 0x07, 0xE0, 0x44, 0x80, 0xF0, 0x43, +/*1930*/0xF9, 0x80, 0x12, 0x18, 0x71, 0x22, 0x12, 0x0E, + 0x44, 0xE5, 0x16, 0x25, 0xE0, 0x25, 0xE0, 0x24, +/*1940*/0xB0, 0xF5, 0x82, 0xE4, 0x34, 0x1A, 0xF5, 0x83, + 0xE4, 0x93, 0xF5, 0x0F, 0xE5, 0x16, 0x25, 0xE0, +/*1950*/0x25, 0xE0, 0x24, 0xB1, 0xF5, 0x82, 0xE4, 0x34, + 0x1A, 0xF5, 0x83, 0xE4, 0x93, 0xF5, 0x0E, 0x12, +/*1960*/0x0E, 0x65, 0xF5, 0x10, 0xE5, 0x0F, 0x54, 0xF0, + 0x12, 0x0E, 0x17, 0x75, 0x83, 0x8C, 0xEF, 0xF0, +/*1970*/0xE5, 0x0F, 0x30, 0xE0, 0x0C, 0x12, 0x0E, 0x04, + 0x75, 0x83, 0x86, 0xE0, 0x44, 0x40, 0xF0, 0x80, +/*1980*/0x0A, 0x12, 0x0E, 0x04, 0x75, 0x83, 0x86, 0xE0, + 0x54, 0xBF, 0xF0, 0x12, 0x0E, 0x91, 0x75, 0x83, +/*1990*/0x82, 0xE5, 0x0E, 0xF0, 0x22, 0x7F, 0x05, 0x12, + 0x17, 0x31, 0x12, 0x0E, 0x04, 0x12, 0x0E, 0x33, +/*19A0*/0x74, 0x02, 0xF0, 0x74, 0x8E, 0xFE, 0x12, 0x0E, + 0x04, 0x12, 0x0E, 0x0B, 0xEF, 0xF0, 0x75, 0x15, +/*19B0*/0x70, 0x12, 0x0F, 0xF7, 0x20, 0x34, 0x05, 0x75, + 0x15, 0x10, 0x80, 0x03, 0x75, 0x15, 0x50, 0x12, +/*19C0*/0x0F, 0xF7, 0x20, 0x34, 0x04, 0x74, 0x10, 0x80, + 0x02, 0x74, 0xF0, 0x25, 0x15, 0xF5, 0x15, 0x12, +/*19D0*/0x0E, 0x21, 0xEF, 0xF0, 0x12, 0x10, 0x91, 0x20, + 0x34, 0x17, 0xE5, 0x15, 0x64, 0x30, 0x60, 0x0C, +/*19E0*/0x74, 0x10, 0x25, 0x15, 0xF5, 0x15, 0xB4, 0x80, + 0x03, 0xE4, 0xF5, 0x15, 0x12, 0x0E, 0x21, 0xEF, +/*19F0*/0xF0, 0x22, 0xF0, 0xE5, 0x0B, 0x25, 0xE0, 0x25, + 0xE0, 0x24, 0x82, 0xF5, 0x82, 0xE4, 0x34, 0x07, +/*1A00*/0xF5, 0x83, 0x22, 0x74, 0x88, 0xFE, 0xE5, 0x08, + 0x44, 0x07, 0xFF, 0xF5, 0x82, 0x8E, 0x83, 0xE0, +/*1A10*/0x22, 0xF0, 0xE5, 0x08, 0x44, 0x07, 0xF5, 0x82, + 0x22, 0xF0, 0xE0, 0x54, 0xC0, 0x8F, 0x82, 0x8E, +/*1A20*/0x83, 0xF0, 0x22, 0xEF, 0x44, 0x07, 0xF5, 0x82, + 0x75, 0x83, 0x86, 0xE0, 0x54, 0x10, 0xD3, 0x94, +/*1A30*/0x00, 0x22, 0xF0, 0x90, 0x07, 0x15, 0xE0, 0x04, + 0xF0, 0x22, 0x44, 0x06, 0xF5, 0x82, 0x75, 0x83, +/*1A40*/0x9E, 0xE0, 0x22, 0xFE, 0xEF, 0x44, 0x07, 0xF5, + 0x82, 0x8E, 0x83, 0xE0, 0x22, 0xE4, 0x90, 0x07, +/*1A50*/0x2A, 0xF0, 0xA3, 0xF0, 0x12, 0x07, 0x2A, 0x75, + 0x83, 0x82, 0xE0, 0x54, 0x7F, 0x12, 0x07, 0x29, +/*1A60*/0xE0, 0x44, 0x80, 0xF0, 0x12, 0x10, 0xFC, 0x12, + 0x08, 0x1F, 0x75, 0x83, 0xA0, 0xE0, 0x20, 0xE0, +/*1A70*/0x1A, 0x90, 0x07, 0x2B, 0xE0, 0x04, 0xF0, 0x70, + 0x06, 0x90, 0x07, 0x2A, 0xE0, 0x04, 0xF0, 0x90, +/*1A80*/0x07, 0x2A, 0xE0, 0xB4, 0x10, 0xE1, 0xA3, 0xE0, + 0xB4, 0x00, 0xDC, 0xEE, 0x44, 0xA6, 0xFC, 0xEF, +/*1A90*/0x44, 0x07, 0xF5, 0x82, 0x8C, 0x83, 0xE0, 0xF5, + 0x32, 0xEE, 0x44, 0xA8, 0xFE, 0xEF, 0x44, 0x07, +/*1AA0*/0xF5, 0x82, 0x8E, 0x83, 0xE0, 0xF5, 0x33, 0x22, + 0x01, 0x20, 0x11, 0x00, 0x04, 0x20, 0x00, 0x90, +/*1AB0*/0x00, 0x20, 0x0F, 0x92, 0x00, 0x21, 0x0F, 0x94, + 0x00, 0x22, 0x0F, 0x96, 0x00, 0x23, 0x0F, 0x98, +/*1AC0*/0x00, 0x24, 0x0F, 0x9A, 0x00, 0x25, 0x0F, 0x9C, + 0x00, 0x26, 0x0F, 0x9E, 0x00, 0x27, 0x0F, 0xA0, +/*1AD0*/0x01, 0x20, 0x01, 0xA2, 0x01, 0x21, 0x01, 0xA4, + 0x01, 0x22, 0x01, 0xA6, 0x01, 0x23, 0x01, 0xA8, +/*1AE0*/0x01, 0x24, 0x01, 0xAA, 0x01, 0x25, 0x01, 0xAC, + 0x01, 0x26, 0x01, 0xAE, 0x01, 0x27, 0x01, 0xB0, +/*1AF0*/0x01, 0x28, 0x01, 0xB4, 0x00, 0x28, 0x0F, 0xB6, + 0x40, 0x28, 0x0F, 0xB8, 0x61, 0x28, 0x01, 0xCB, +/*1B00*/0xEF, 0xCB, 0xCA, 0xEE, 0xCA, 0x7F, 0x01, 0xE4, + 0xFD, 0xEB, 0x4A, 0x70, 0x24, 0xE5, 0x08, 0xF5, +/*1B10*/0x82, 0x74, 0xB6, 0x12, 0x08, 0x29, 0xE5, 0x08, + 0xF5, 0x82, 0x74, 0xB8, 0x12, 0x08, 0x29, 0xE5, +/*1B20*/0x08, 0xF5, 0x82, 0x74, 0xBA, 0x12, 0x08, 0x29, + 0x7E, 0x00, 0x7C, 0x00, 0x12, 0x0A, 0xFF, 0x80, +/*1B30*/0x12, 0x90, 0x07, 0x26, 0x12, 0x07, 0x35, 0xE5, + 0x41, 0xF0, 0x90, 0x07, 0x24, 0x12, 0x07, 0x35, +/*1B40*/0xE5, 0x40, 0xF0, 0x12, 0x07, 0x2A, 0x75, 0x83, + 0x8E, 0xE4, 0x12, 0x07, 0x29, 0x74, 0x01, 0x12, +/*1B50*/0x07, 0x29, 0xE4, 0xF0, 0x22, 0xE4, 0xF5, 0x26, + 0xF5, 0x27, 0x53, 0xE1, 0xFE, 0xF5, 0x2A, 0x75, +/*1B60*/0x2B, 0x01, 0xF5, 0x08, 0x7F, 0x01, 0x12, 0x17, + 0x31, 0x30, 0x30, 0x1C, 0x90, 0x1A, 0xA9, 0xE4, +/*1B70*/0x93, 0xF5, 0x10, 0x90, 0x1F, 0xF9, 0xE4, 0x93, + 0xF5, 0x10, 0x90, 0x00, 0x41, 0xE4, 0x93, 0xF5, +/*1B80*/0x10, 0x90, 0x1E, 0xCA, 0xE4, 0x93, 0xF5, 0x10, + 0x7F, 0x02, 0x12, 0x17, 0x31, 0x12, 0x0F, 0x54, +/*1B90*/0x7F, 0x03, 0x12, 0x17, 0x31, 0x12, 0x00, 0x06, + 0xE5, 0xE2, 0x30, 0xE7, 0x09, 0x12, 0x10, 0x00, +/*1BA0*/0x30, 0x30, 0x03, 0x12, 0x11, 0x00, 0x02, 0x00, + 0x47, 0x12, 0x08, 0x1F, 0x75, 0x83, 0xD0, 0xE0, +/*1BB0*/0xC4, 0x54, 0x0F, 0xFD, 0x75, 0x43, 0x01, 0x75, + 0x44, 0xFF, 0x12, 0x08, 0xAA, 0x74, 0x04, 0xF0, +/*1BC0*/0x75, 0x3B, 0x01, 0xED, 0x14, 0x60, 0x0C, 0x14, + 0x60, 0x0B, 0x14, 0x60, 0x0F, 0x24, 0x03, 0x70, +/*1BD0*/0x0B, 0x80, 0x09, 0x80, 0x00, 0x12, 0x08, 0xA7, + 0x04, 0xF0, 0x80, 0x06, 0x12, 0x08, 0xA7, 0x74, +/*1BE0*/0x04, 0xF0, 0xEE, 0x44, 0x82, 0xFE, 0xEF, 0x44, + 0x07, 0xF5, 0x82, 0x8E, 0x83, 0xE5, 0x45, 0x12, +/*1BF0*/0x08, 0xBE, 0x75, 0x83, 0x82, 0xE5, 0x31, 0xF0, + 0x02, 0x11, 0x4C, 0x8E, 0x60, 0x8F, 0x61, 0x12, +/*1C00*/0x1E, 0xA5, 0xE4, 0xFF, 0xCE, 0xED, 0xCE, 0xEE, + 0xD3, 0x95, 0x61, 0xE5, 0x60, 0x12, 0x07, 0x6B, +/*1C10*/0x40, 0x39, 0x74, 0x20, 0x2E, 0xF5, 0x82, 0xE4, + 0x34, 0x03, 0xF5, 0x83, 0xE0, 0x70, 0x03, 0xFF, +/*1C20*/0x80, 0x26, 0x12, 0x08, 0xE2, 0xFD, 0xC3, 0x9F, + 0x40, 0x1E, 0xCF, 0xED, 0xCF, 0xEB, 0x4A, 0x70, +/*1C30*/0x0B, 0x8D, 0x42, 0x12, 0x08, 0xEE, 0xF5, 0x41, + 0x8E, 0x40, 0x80, 0x0C, 0x12, 0x08, 0xE2, 0xF5, +/*1C40*/0x38, 0x12, 0x08, 0xEE, 0xF5, 0x39, 0x8E, 0x3A, + 0x1E, 0x80, 0xBC, 0x22, 0x75, 0x58, 0x01, 0xE5, +/*1C50*/0x35, 0x70, 0x0C, 0x12, 0x07, 0xCC, 0xE0, 0xF5, + 0x4A, 0x12, 0x07, 0xD8, 0xE0, 0xF5, 0x4C, 0xE5, +/*1C60*/0x35, 0xB4, 0x04, 0x0C, 0x12, 0x07, 0xE4, 0xE0, + 0xF5, 0x4A, 0x12, 0x07, 0xF0, 0xE0, 0xF5, 0x4C, +/*1C70*/0xE5, 0x35, 0xB4, 0x01, 0x04, 0x7F, 0x01, 0x80, + 0x02, 0x7F, 0x00, 0xE5, 0x35, 0xB4, 0x02, 0x04, +/*1C80*/0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, + 0x60, 0x0C, 0x12, 0x07, 0xFC, 0xE0, 0xF5, 0x4A, +/*1C90*/0x12, 0x08, 0x08, 0xE0, 0xF5, 0x4C, 0x85, 0x41, + 0x49, 0x85, 0x40, 0x4B, 0x22, 0x75, 0x5B, 0x01, +/*1CA0*/0x90, 0x07, 0x24, 0x12, 0x07, 0x35, 0xE0, 0x54, + 0x1F, 0xFF, 0xD3, 0x94, 0x02, 0x50, 0x04, 0x8F, +/*1CB0*/0x58, 0x80, 0x05, 0xEF, 0x24, 0xFE, 0xF5, 0x58, + 0xEF, 0xC3, 0x94, 0x18, 0x40, 0x05, 0x75, 0x59, +/*1CC0*/0x18, 0x80, 0x04, 0xEF, 0x04, 0xF5, 0x59, 0x85, + 0x43, 0x5A, 0xAF, 0x58, 0x7E, 0x00, 0xAD, 0x59, +/*1CD0*/0x7C, 0x00, 0xAB, 0x5B, 0x7A, 0x00, 0x12, 0x15, + 0x41, 0xAF, 0x5A, 0x7E, 0x00, 0x12, 0x18, 0x0A, +/*1CE0*/0xAF, 0x5B, 0x7E, 0x00, 0x02, 0x1A, 0xFF, 0xE5, + 0xE2, 0x30, 0xE7, 0x0E, 0x12, 0x10, 0x03, 0xC2, +/*1CF0*/0x30, 0x30, 0x30, 0x03, 0x12, 0x10, 0xFF, 0x20, + 0x33, 0x28, 0xE5, 0xE7, 0x30, 0xE7, 0x05, 0x12, +/*1D00*/0x0E, 0xA2, 0x80, 0x0D, 0xE5, 0xFE, 0xC3, 0x94, + 0x20, 0x50, 0x06, 0x12, 0x0E, 0xA2, 0x43, 0xF9, +/*1D10*/0x08, 0xE5, 0xF2, 0x30, 0xE7, 0x03, 0x53, 0xF9, + 0x7F, 0xE5, 0xF1, 0x54, 0x70, 0xD3, 0x94, 0x00, +/*1D20*/0x50, 0xD8, 0x22, 0x12, 0x0E, 0x04, 0x75, 0x83, + 0x80, 0xE4, 0xF0, 0xE5, 0x08, 0x44, 0x07, 0x12, +/*1D30*/0x0D, 0xFD, 0x75, 0x83, 0x84, 0x12, 0x0E, 0x02, + 0x75, 0x83, 0x86, 0x12, 0x0E, 0x02, 0x75, 0x83, +/*1D40*/0x8C, 0xE0, 0x54, 0xF3, 0x12, 0x0E, 0x03, 0x75, + 0x83, 0x8E, 0x12, 0x0E, 0x02, 0x75, 0x83, 0x94, +/*1D50*/0xE0, 0x54, 0xFB, 0xF0, 0x22, 0x12, 0x07, 0x2A, + 0x75, 0x83, 0x8E, 0xE4, 0x12, 0x07, 0x29, 0x74, +/*1D60*/0x01, 0x12, 0x07, 0x29, 0xE4, 0x12, 0x08, 0xBE, + 0x75, 0x83, 0x8C, 0xE0, 0x44, 0x20, 0x12, 0x08, +/*1D70*/0xBE, 0xE0, 0x54, 0xDF, 0xF0, 0x74, 0x84, 0x85, + 0x08, 0x82, 0xF5, 0x83, 0xE0, 0x54, 0x7F, 0xF0, +/*1D80*/0xE0, 0x44, 0x80, 0xF0, 0x22, 0x75, 0x56, 0x01, + 0xE4, 0xFD, 0xF5, 0x57, 0xAF, 0x35, 0xFE, 0xFC, +/*1D90*/0x12, 0x09, 0x15, 0x12, 0x1C, 0x9D, 0x12, 0x1E, + 0x7A, 0x12, 0x1C, 0x4C, 0xAF, 0x57, 0x7E, 0x00, +/*1DA0*/0xAD, 0x56, 0x7C, 0x00, 0x12, 0x04, 0x44, 0xAF, + 0x56, 0x7E, 0x00, 0x02, 0x11, 0xEE, 0x75, 0x56, +/*1DB0*/0x01, 0xE4, 0xFD, 0xF5, 0x57, 0xAF, 0x35, 0xFE, + 0xFC, 0x12, 0x09, 0x15, 0x12, 0x1C, 0x9D, 0x12, +/*1DC0*/0x1E, 0x7A, 0x12, 0x1C, 0x4C, 0xAF, 0x57, 0x7E, + 0x00, 0xAD, 0x56, 0x7C, 0x00, 0x12, 0x04, 0x44, +/*1DD0*/0xAF, 0x56, 0x7E, 0x00, 0x02, 0x11, 0xEE, 0xE4, + 0xF5, 0x16, 0x12, 0x0E, 0x44, 0xFE, 0xE5, 0x08, +/*1DE0*/0x44, 0x05, 0xFF, 0x12, 0x0E, 0x65, 0x8F, 0x82, + 0x8E, 0x83, 0xF0, 0x05, 0x16, 0xE5, 0x16, 0xC3, +/*1DF0*/0x94, 0x14, 0x40, 0xE6, 0xE5, 0x08, 0x12, 0x0E, + 0x2B, 0xE4, 0xF0, 0x22, 0xE4, 0xF5, 0x58, 0xF5, +/*1E00*/0x59, 0xF5, 0x5A, 0xFF, 0xFE, 0xAD, 0x58, 0xFC, + 0x12, 0x09, 0x15, 0x7F, 0x04, 0x7E, 0x00, 0xAD, +/*1E10*/0x58, 0x7C, 0x00, 0x12, 0x09, 0x15, 0x7F, 0x02, + 0x7E, 0x00, 0xAD, 0x58, 0x7C, 0x00, 0x02, 0x09, +/*1E20*/0x15, 0xE5, 0x3C, 0x25, 0x3E, 0xFC, 0xE5, 0x42, + 0x24, 0x00, 0xFB, 0xE4, 0x33, 0xFA, 0xEC, 0xC3, +/*1E30*/0x9B, 0xEA, 0x12, 0x07, 0x6B, 0x40, 0x0B, 0x8C, + 0x42, 0xE5, 0x3D, 0x25, 0x3F, 0xF5, 0x41, 0x8F, +/*1E40*/0x40, 0x22, 0x12, 0x09, 0x0B, 0x22, 0x74, 0x84, + 0xF5, 0x18, 0x85, 0x08, 0x19, 0x85, 0x19, 0x82, +/*1E50*/0x85, 0x18, 0x83, 0xE0, 0x54, 0x7F, 0xF0, 0xE0, + 0x44, 0x80, 0xF0, 0xE0, 0x44, 0x80, 0xF0, 0x22, +/*1E60*/0xEF, 0x4E, 0x70, 0x0B, 0x12, 0x07, 0x2A, 0x75, + 0x83, 0xD2, 0xE0, 0x54, 0xDF, 0xF0, 0x22, 0x12, +/*1E70*/0x07, 0x2A, 0x75, 0x83, 0xD2, 0xE0, 0x44, 0x20, + 0xF0, 0x22, 0x75, 0x58, 0x01, 0x90, 0x07, 0x26, +/*1E80*/0x12, 0x07, 0x35, 0xE0, 0x54, 0x3F, 0xF5, 0x41, + 0x12, 0x07, 0x32, 0xE0, 0x54, 0x3F, 0xF5, 0x40, +/*1E90*/0x22, 0x75, 0x56, 0x02, 0xE4, 0xF5, 0x57, 0x12, + 0x1D, 0xFC, 0xAF, 0x57, 0x7E, 0x00, 0xAD, 0x56, +/*1EA0*/0x7C, 0x00, 0x02, 0x04, 0x44, 0xE4, 0xF5, 0x42, + 0xF5, 0x41, 0xF5, 0x40, 0xF5, 0x38, 0xF5, 0x39, +/*1EB0*/0xF5, 0x3A, 0x22, 0xEF, 0x54, 0x07, 0xFF, 0xE5, + 0xF9, 0x54, 0xF8, 0x4F, 0xF5, 0xF9, 0x22, 0x7F, +/*1EC0*/0x01, 0xE4, 0xFE, 0x0F, 0x0E, 0xBE, 0xFF, 0xFB, + 0x22, 0x01, 0x20, 0x00, 0x01, 0x04, 0x20, 0x00, +/*1ED0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1EE0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1EF0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1F00*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1F10*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1F20*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1F30*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1F40*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1F50*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1F60*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1F70*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1F80*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1F90*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1FA0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1FB0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1FC0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1FD0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1FE0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1FF0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x20, 0x11, 0x00, 0x04, 0x20, 0x00, 0x81 +}; diff --git a/gpxe/src/drivers/infiniband/qib_7220_regs.h b/gpxe/src/drivers/infiniband/qib_7220_regs.h new file mode 100644 index 00000000..0dd3c53d --- /dev/null +++ b/gpxe/src/drivers/infiniband/qib_7220_regs.h @@ -0,0 +1,1763 @@ +/* + * Copyright (c) 2008 QLogic Corporation. All rights reserved. + * + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * This file is mechanically generated. Any hand-edits will be lost. + * If not now, soon. + */ + +/* This file has been further processed by ./drivers/infiniband/qib_genbits.pl */ + + +#define QIB_7220_Revision_offset 0x00000000UL +struct QIB_7220_Revision_pb { + pseudo_bit_t R_ChipRevMinor[8]; + pseudo_bit_t R_ChipRevMajor[8]; + pseudo_bit_t R_Arch[8]; + pseudo_bit_t R_SW[8]; + pseudo_bit_t BoardID[8]; + pseudo_bit_t R_Palldium_Revcode[22]; + pseudo_bit_t R_Palladium[1]; + pseudo_bit_t R_Simulator[1]; +}; +struct QIB_7220_Revision { + PSEUDO_BIT_STRUCT ( struct QIB_7220_Revision_pb ); +}; + +#define QIB_7220_Control_offset 0x00000008UL +struct QIB_7220_Control_pb { + pseudo_bit_t SyncReset[1]; + pseudo_bit_t FreezeMode[1]; + pseudo_bit_t LinkEn[1]; + pseudo_bit_t PCIERetryBufDiagEn[1]; + pseudo_bit_t TxLatency[1]; + pseudo_bit_t Reserved[1]; + pseudo_bit_t PCIECplQDiagEn[1]; + pseudo_bit_t SyncResetExceptPcieIRAMRST[1]; + pseudo_bit_t _unused_0[56]; +}; +struct QIB_7220_Control { + PSEUDO_BIT_STRUCT ( struct QIB_7220_Control_pb ); +}; + +#define QIB_7220_PageAlign_offset 0x00000010UL + +#define QIB_7220_PortCnt_offset 0x00000018UL + +#define QIB_7220_DbgPortSel_offset 0x00000020UL +struct QIB_7220_DbgPortSel_pb { + pseudo_bit_t NibbleSel0[4]; + pseudo_bit_t NibbleSel1[4]; + pseudo_bit_t NibbleSel2[4]; + pseudo_bit_t NibbleSel3[4]; + pseudo_bit_t NibbleSel4[4]; + pseudo_bit_t NibbleSel5[4]; + pseudo_bit_t NibbleSel6[4]; + pseudo_bit_t NibbleSel7[4]; + pseudo_bit_t SrcMuxSel[14]; + pseudo_bit_t DbgClkPortSel[5]; + pseudo_bit_t EnDbgPort[1]; + pseudo_bit_t EnEnhancedDebugMode[1]; + pseudo_bit_t EnhMode_SrcMuxSelIndex[10]; + pseudo_bit_t EnhMode_SrcMuxSelWrEn[1]; +}; +struct QIB_7220_DbgPortSel { + PSEUDO_BIT_STRUCT ( struct QIB_7220_DbgPortSel_pb ); +}; + +#define QIB_7220_DebugSigsIntSel_offset 0x00000028UL +struct QIB_7220_DebugSigsIntSel_pb { + pseudo_bit_t debug_port_sel_pcs_pipe_lane07[3]; + pseudo_bit_t debug_port_sel_pcs_pipe_lane815[3]; + pseudo_bit_t debug_port_sel_pcs_sdout[1]; + pseudo_bit_t debug_port_sel_pcs_symlock_elfifo_lane[4]; + pseudo_bit_t debug_port_sel_pcs_rxdet_encdec_lane[4]; + pseudo_bit_t debug_port_sel_pcie_rx_tx[1]; + pseudo_bit_t debug_port_sel_xgxs[4]; + pseudo_bit_t debug_port_sel_epb_pcie[1]; + pseudo_bit_t _unused_0[43]; +}; +struct QIB_7220_DebugSigsIntSel { + PSEUDO_BIT_STRUCT ( struct QIB_7220_DebugSigsIntSel_pb ); +}; + +#define QIB_7220_SendRegBase_offset 0x00000030UL + +#define QIB_7220_UserRegBase_offset 0x00000038UL + +#define QIB_7220_CntrRegBase_offset 0x00000040UL + +#define QIB_7220_Scratch_offset 0x00000048UL + +#define QIB_7220_REG_000050_offset 0x00000050UL + +#define QIB_7220_IntBlocked_offset 0x00000060UL +struct QIB_7220_IntBlocked_pb { + pseudo_bit_t RcvAvail0IntBlocked[1]; + pseudo_bit_t RcvAvail1IntBlocked[1]; + pseudo_bit_t RcvAvail2IntBlocked[1]; + pseudo_bit_t RcvAvail3IntBlocked[1]; + pseudo_bit_t RcvAvail4IntBlocked[1]; + pseudo_bit_t RcvAvail5IntBlocked[1]; + pseudo_bit_t RcvAvail6IntBlocked[1]; + pseudo_bit_t RcvAvail7IntBlocked[1]; + pseudo_bit_t RcvAvail8IntBlocked[1]; + pseudo_bit_t RcvAvail9IntBlocked[1]; + pseudo_bit_t RcvAvail10IntBlocked[1]; + pseudo_bit_t RcvAvail11IntBlocked[1]; + pseudo_bit_t RcvAvail12IntBlocked[1]; + pseudo_bit_t RcvAvail13IntBlocked[1]; + pseudo_bit_t RcvAvail14IntBlocked[1]; + pseudo_bit_t RcvAvail15IntBlocked[1]; + pseudo_bit_t RcvAvail16IntBlocked[1]; + pseudo_bit_t Reserved1[9]; + pseudo_bit_t JIntBlocked[1]; + pseudo_bit_t IBSerdesTrimDoneIntBlocked[1]; + pseudo_bit_t assertGPIOIntBlocked[1]; + pseudo_bit_t PioBufAvailIntBlocked[1]; + pseudo_bit_t PioSetIntBlocked[1]; + pseudo_bit_t ErrorIntBlocked[1]; + pseudo_bit_t RcvUrg0IntBlocked[1]; + pseudo_bit_t RcvUrg1IntBlocked[1]; + pseudo_bit_t RcvUrg2IntBlocked[1]; + pseudo_bit_t RcvUrg3IntBlocked[1]; + pseudo_bit_t RcvUrg4IntBlocked[1]; + pseudo_bit_t RcvUrg5IntBlocked[1]; + pseudo_bit_t RcvUrg6IntBlocked[1]; + pseudo_bit_t RcvUrg7IntBlocked[1]; + pseudo_bit_t RcvUrg8IntBlocked[1]; + pseudo_bit_t RcvUrg9IntBlocked[1]; + pseudo_bit_t RcvUrg10IntBlocked[1]; + pseudo_bit_t RcvUrg11IntBlocked[1]; + pseudo_bit_t RcvUrg12IntBlocked[1]; + pseudo_bit_t RcvUrg13IntBlocked[1]; + pseudo_bit_t RcvUrg14IntBlocked[1]; + pseudo_bit_t RcvUrg15IntBlocked[1]; + pseudo_bit_t RcvUrg16IntBlocked[1]; + pseudo_bit_t Reserved[13]; + pseudo_bit_t SDmaDisabledBlocked[1]; + pseudo_bit_t SDmaIntBlocked[1]; +}; +struct QIB_7220_IntBlocked { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IntBlocked_pb ); +}; + +#define QIB_7220_IntMask_offset 0x00000068UL +struct QIB_7220_IntMask_pb { + pseudo_bit_t RcvAvail0IntMask[1]; + pseudo_bit_t RcvAvail1IntMask[1]; + pseudo_bit_t RcvAvail2IntMask[1]; + pseudo_bit_t RcvAvail3IntMask[1]; + pseudo_bit_t RcvAvail4IntMask[1]; + pseudo_bit_t RcvAvail5IntMask[1]; + pseudo_bit_t RcvAvail6IntMask[1]; + pseudo_bit_t RcvAvail7IntMask[1]; + pseudo_bit_t RcvAvail8IntMask[1]; + pseudo_bit_t RcvAvail9IntMask[1]; + pseudo_bit_t RcvAvail10IntMask[1]; + pseudo_bit_t RcvAvail11IntMask[1]; + pseudo_bit_t RcvAvail12IntMask[1]; + pseudo_bit_t RcvAvail13IntMask[1]; + pseudo_bit_t RcvAvail14IntMask[1]; + pseudo_bit_t RcvAvail15IntMask[1]; + pseudo_bit_t RcvAvail16IntMask[1]; + pseudo_bit_t Reserved1[9]; + pseudo_bit_t JIntMask[1]; + pseudo_bit_t IBSerdesTrimDoneIntMask[1]; + pseudo_bit_t assertGPIOIntMask[1]; + pseudo_bit_t PioBufAvailIntMask[1]; + pseudo_bit_t PioSetIntMask[1]; + pseudo_bit_t ErrorIntMask[1]; + pseudo_bit_t RcvUrg0IntMask[1]; + pseudo_bit_t RcvUrg1IntMask[1]; + pseudo_bit_t RcvUrg2IntMask[1]; + pseudo_bit_t RcvUrg3IntMask[1]; + pseudo_bit_t RcvUrg4IntMask[1]; + pseudo_bit_t RcvUrg5IntMask[1]; + pseudo_bit_t RcvUrg6IntMask[1]; + pseudo_bit_t RcvUrg7IntMask[1]; + pseudo_bit_t RcvUrg8IntMask[1]; + pseudo_bit_t RcvUrg9IntMask[1]; + pseudo_bit_t RcvUrg10IntMask[1]; + pseudo_bit_t RcvUrg11IntMask[1]; + pseudo_bit_t RcvUrg12IntMask[1]; + pseudo_bit_t RcvUrg13IntMask[1]; + pseudo_bit_t RcvUrg14IntMask[1]; + pseudo_bit_t RcvUrg15IntMask[1]; + pseudo_bit_t RcvUrg16IntMask[1]; + pseudo_bit_t Reserved[13]; + pseudo_bit_t SDmaDisabledMasked[1]; + pseudo_bit_t SDmaIntMask[1]; +}; +struct QIB_7220_IntMask { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IntMask_pb ); +}; + +#define QIB_7220_IntStatus_offset 0x00000070UL +struct QIB_7220_IntStatus_pb { + pseudo_bit_t RcvAvail0[1]; + pseudo_bit_t RcvAvail1[1]; + pseudo_bit_t RcvAvail2[1]; + pseudo_bit_t RcvAvail3[1]; + pseudo_bit_t RcvAvail4[1]; + pseudo_bit_t RcvAvail5[1]; + pseudo_bit_t RcvAvail6[1]; + pseudo_bit_t RcvAvail7[1]; + pseudo_bit_t RcvAvail8[1]; + pseudo_bit_t RcvAvail9[1]; + pseudo_bit_t RcvAvail10[1]; + pseudo_bit_t RcvAvail11[1]; + pseudo_bit_t RcvAvail12[1]; + pseudo_bit_t RcvAvail13[1]; + pseudo_bit_t RcvAvail14[1]; + pseudo_bit_t RcvAvail15[1]; + pseudo_bit_t RcvAvail16[1]; + pseudo_bit_t Reserved1[9]; + pseudo_bit_t JInt[1]; + pseudo_bit_t IBSerdesTrimDone[1]; + pseudo_bit_t assertGPIO[1]; + pseudo_bit_t PioBufAvail[1]; + pseudo_bit_t PioSent[1]; + pseudo_bit_t Error[1]; + pseudo_bit_t RcvUrg0[1]; + pseudo_bit_t RcvUrg1[1]; + pseudo_bit_t RcvUrg2[1]; + pseudo_bit_t RcvUrg3[1]; + pseudo_bit_t RcvUrg4[1]; + pseudo_bit_t RcvUrg5[1]; + pseudo_bit_t RcvUrg6[1]; + pseudo_bit_t RcvUrg7[1]; + pseudo_bit_t RcvUrg8[1]; + pseudo_bit_t RcvUrg9[1]; + pseudo_bit_t RcvUrg10[1]; + pseudo_bit_t RcvUrg11[1]; + pseudo_bit_t RcvUrg12[1]; + pseudo_bit_t RcvUrg13[1]; + pseudo_bit_t RcvUrg14[1]; + pseudo_bit_t RcvUrg15[1]; + pseudo_bit_t RcvUrg16[1]; + pseudo_bit_t Reserved[13]; + pseudo_bit_t SDmaDisabled[1]; + pseudo_bit_t SDmaInt[1]; +}; +struct QIB_7220_IntStatus { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IntStatus_pb ); +}; + +#define QIB_7220_IntClear_offset 0x00000078UL +struct QIB_7220_IntClear_pb { + pseudo_bit_t RcvAvail0IntClear[1]; + pseudo_bit_t RcvAvail1IntClear[1]; + pseudo_bit_t RcvAvail2IntClear[1]; + pseudo_bit_t RcvAvail3IntClear[1]; + pseudo_bit_t RcvAvail4IntClear[1]; + pseudo_bit_t RcvAvail5IntClear[1]; + pseudo_bit_t RcvAvail6IntClear[1]; + pseudo_bit_t RcvAvail7IntClear[1]; + pseudo_bit_t RcvAvail8IntClear[1]; + pseudo_bit_t RcvAvail9IntClear[1]; + pseudo_bit_t RcvAvail10IntClear[1]; + pseudo_bit_t RcvAvail11IntClear[1]; + pseudo_bit_t RcvAvail12IntClear[1]; + pseudo_bit_t RcvAvail13IntClear[1]; + pseudo_bit_t RcvAvail14IntClear[1]; + pseudo_bit_t RcvAvail15IntClear[1]; + pseudo_bit_t RcvAvail16IntClear[1]; + pseudo_bit_t Reserved1[9]; + pseudo_bit_t JIntClear[1]; + pseudo_bit_t IBSerdesTrimDoneClear[1]; + pseudo_bit_t assertGPIOIntClear[1]; + pseudo_bit_t PioBufAvailIntClear[1]; + pseudo_bit_t PioSetIntClear[1]; + pseudo_bit_t ErrorIntClear[1]; + pseudo_bit_t RcvUrg0IntClear[1]; + pseudo_bit_t RcvUrg1IntClear[1]; + pseudo_bit_t RcvUrg2IntClear[1]; + pseudo_bit_t RcvUrg3IntClear[1]; + pseudo_bit_t RcvUrg4IntClear[1]; + pseudo_bit_t RcvUrg5IntClear[1]; + pseudo_bit_t RcvUrg6IntClear[1]; + pseudo_bit_t RcvUrg7IntClear[1]; + pseudo_bit_t RcvUrg8IntClear[1]; + pseudo_bit_t RcvUrg9IntClear[1]; + pseudo_bit_t RcvUrg10IntClear[1]; + pseudo_bit_t RcvUrg11IntClear[1]; + pseudo_bit_t RcvUrg12IntClear[1]; + pseudo_bit_t RcvUrg13IntClear[1]; + pseudo_bit_t RcvUrg14IntClear[1]; + pseudo_bit_t RcvUrg15IntClear[1]; + pseudo_bit_t RcvUrg16IntClear[1]; + pseudo_bit_t Reserved[13]; + pseudo_bit_t SDmaDisabledClear[1]; + pseudo_bit_t SDmaIntClear[1]; +}; +struct QIB_7220_IntClear { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IntClear_pb ); +}; + +#define QIB_7220_ErrMask_offset 0x00000080UL +struct QIB_7220_ErrMask_pb { + pseudo_bit_t RcvFormatErrMask[1]; + pseudo_bit_t RcvVCRCErrMask[1]; + pseudo_bit_t RcvICRCErrMask[1]; + pseudo_bit_t RcvMinPktLenErrMask[1]; + pseudo_bit_t RcvMaxPktLenErrMask[1]; + pseudo_bit_t RcvLongPktLenErrMask[1]; + pseudo_bit_t RcvShortPktLenErrMask[1]; + pseudo_bit_t RcvUnexpectedCharErrMask[1]; + pseudo_bit_t RcvUnsupportedVLErrMask[1]; + pseudo_bit_t RcvEBPErrMask[1]; + pseudo_bit_t RcvIBFlowErrMask[1]; + pseudo_bit_t RcvBadVersionErrMask[1]; + pseudo_bit_t RcvEgrFullErrMask[1]; + pseudo_bit_t RcvHdrFullErrMask[1]; + pseudo_bit_t RcvBadTidErrMask[1]; + pseudo_bit_t RcvHdrLenErrMask[1]; + pseudo_bit_t RcvHdrErrMask[1]; + pseudo_bit_t RcvIBLostLinkErrMask[1]; + pseudo_bit_t Reserved1[9]; + pseudo_bit_t SendSpecialTriggerErrMask[1]; + pseudo_bit_t SDmaDisabledErrMask[1]; + pseudo_bit_t SendMinPktLenErrMask[1]; + pseudo_bit_t SendMaxPktLenErrMask[1]; + pseudo_bit_t SendUnderRunErrMask[1]; + pseudo_bit_t SendPktLenErrMask[1]; + pseudo_bit_t SendDroppedSmpPktErrMask[1]; + pseudo_bit_t SendDroppedDataPktErrMask[1]; + pseudo_bit_t SendPioArmLaunchErrMask[1]; + pseudo_bit_t SendUnexpectedPktNumErrMask[1]; + pseudo_bit_t SendUnsupportedVLErrMask[1]; + pseudo_bit_t SendBufMisuseErrMask[1]; + pseudo_bit_t SDmaGenMismatchErrMask[1]; + pseudo_bit_t SDmaOutOfBoundErrMask[1]; + pseudo_bit_t SDmaTailOutOfBoundErrMask[1]; + pseudo_bit_t SDmaBaseErrMask[1]; + pseudo_bit_t SDma1stDescErrMask[1]; + pseudo_bit_t SDmaRpyTagErrMask[1]; + pseudo_bit_t SDmaDwEnErrMask[1]; + pseudo_bit_t SDmaMissingDwErrMask[1]; + pseudo_bit_t SDmaUnexpDataErrMask[1]; + pseudo_bit_t IBStatusChangedMask[1]; + pseudo_bit_t InvalidAddrErrMask[1]; + pseudo_bit_t ResetNegatedMask[1]; + pseudo_bit_t HardwareErrMask[1]; + pseudo_bit_t SDmaDescAddrMisalignErrMask[1]; + pseudo_bit_t InvalidEEPCmdMask[1]; + pseudo_bit_t Reserved[10]; +}; +struct QIB_7220_ErrMask { + PSEUDO_BIT_STRUCT ( struct QIB_7220_ErrMask_pb ); +}; + +#define QIB_7220_ErrStatus_offset 0x00000088UL +struct QIB_7220_ErrStatus_pb { + pseudo_bit_t RcvFormatErr[1]; + pseudo_bit_t RcvVCRCErr[1]; + pseudo_bit_t RcvICRCErr[1]; + pseudo_bit_t RcvMinPktLenErr[1]; + pseudo_bit_t RcvMaxPktLenErr[1]; + pseudo_bit_t RcvLongPktLenErr[1]; + pseudo_bit_t RcvShortPktLenErr[1]; + pseudo_bit_t RcvUnexpectedCharErr[1]; + pseudo_bit_t RcvUnsupportedVLErr[1]; + pseudo_bit_t RcvEBPErr[1]; + pseudo_bit_t RcvIBFlowErr[1]; + pseudo_bit_t RcvBadVersionErr[1]; + pseudo_bit_t RcvEgrFullErr[1]; + pseudo_bit_t RcvHdrFullErr[1]; + pseudo_bit_t RcvBadTidErr[1]; + pseudo_bit_t RcvHdrLenErr[1]; + pseudo_bit_t RcvHdrErr[1]; + pseudo_bit_t RcvIBLostLinkErr[1]; + pseudo_bit_t Reserved1[9]; + pseudo_bit_t SendSpecialTriggerErr[1]; + pseudo_bit_t SDmaDisabledErr[1]; + pseudo_bit_t SendMinPktLenErr[1]; + pseudo_bit_t SendMaxPktLenErr[1]; + pseudo_bit_t SendUnderRunErr[1]; + pseudo_bit_t SendPktLenErr[1]; + pseudo_bit_t SendDroppedSmpPktErr[1]; + pseudo_bit_t SendDroppedDataPktErr[1]; + pseudo_bit_t SendPioArmLaunchErr[1]; + pseudo_bit_t SendUnexpectedPktNumErr[1]; + pseudo_bit_t SendUnsupportedVLErr[1]; + pseudo_bit_t SendBufMisuseErr[1]; + pseudo_bit_t SDmaGenMismatchErr[1]; + pseudo_bit_t SDmaOutOfBoundErr[1]; + pseudo_bit_t SDmaTailOutOfBoundErr[1]; + pseudo_bit_t SDmaBaseErr[1]; + pseudo_bit_t SDma1stDescErr[1]; + pseudo_bit_t SDmaRpyTagErr[1]; + pseudo_bit_t SDmaDwEnErr[1]; + pseudo_bit_t SDmaMissingDwErr[1]; + pseudo_bit_t SDmaUnexpDataErr[1]; + pseudo_bit_t IBStatusChanged[1]; + pseudo_bit_t InvalidAddrErr[1]; + pseudo_bit_t ResetNegated[1]; + pseudo_bit_t HardwareErr[1]; + pseudo_bit_t SDmaDescAddrMisalignErr[1]; + pseudo_bit_t InvalidEEPCmdErr[1]; + pseudo_bit_t Reserved[10]; +}; +struct QIB_7220_ErrStatus { + PSEUDO_BIT_STRUCT ( struct QIB_7220_ErrStatus_pb ); +}; + +#define QIB_7220_ErrClear_offset 0x00000090UL +struct QIB_7220_ErrClear_pb { + pseudo_bit_t RcvFormatErrClear[1]; + pseudo_bit_t RcvVCRCErrClear[1]; + pseudo_bit_t RcvICRCErrClear[1]; + pseudo_bit_t RcvMinPktLenErrClear[1]; + pseudo_bit_t RcvMaxPktLenErrClear[1]; + pseudo_bit_t RcvLongPktLenErrClear[1]; + pseudo_bit_t RcvShortPktLenErrClear[1]; + pseudo_bit_t RcvUnexpectedCharErrClear[1]; + pseudo_bit_t RcvUnsupportedVLErrClear[1]; + pseudo_bit_t RcvEBPErrClear[1]; + pseudo_bit_t RcvIBFlowErrClear[1]; + pseudo_bit_t RcvBadVersionErrClear[1]; + pseudo_bit_t RcvEgrFullErrClear[1]; + pseudo_bit_t RcvHdrFullErrClear[1]; + pseudo_bit_t RcvBadTidErrClear[1]; + pseudo_bit_t RcvHdrLenErrClear[1]; + pseudo_bit_t RcvHdrErrClear[1]; + pseudo_bit_t RcvIBLostLinkErrClear[1]; + pseudo_bit_t Reserved1[9]; + pseudo_bit_t SendSpecialTriggerErrClear[1]; + pseudo_bit_t SDmaDisabledErrClear[1]; + pseudo_bit_t SendMinPktLenErrClear[1]; + pseudo_bit_t SendMaxPktLenErrClear[1]; + pseudo_bit_t SendUnderRunErrClear[1]; + pseudo_bit_t SendPktLenErrClear[1]; + pseudo_bit_t SendDroppedSmpPktErrClear[1]; + pseudo_bit_t SendDroppedDataPktErrClear[1]; + pseudo_bit_t SendPioArmLaunchErrClear[1]; + pseudo_bit_t SendUnexpectedPktNumErrClear[1]; + pseudo_bit_t SendUnsupportedVLErrClear[1]; + pseudo_bit_t SendBufMisuseErrClear[1]; + pseudo_bit_t SDmaGenMismatchErrClear[1]; + pseudo_bit_t SDmaOutOfBoundErrClear[1]; + pseudo_bit_t SDmaTailOutOfBoundErrClear[1]; + pseudo_bit_t SDmaBaseErrClear[1]; + pseudo_bit_t SDma1stDescErrClear[1]; + pseudo_bit_t SDmaRpyTagErrClear[1]; + pseudo_bit_t SDmaDwEnErrClear[1]; + pseudo_bit_t SDmaMissingDwErrClear[1]; + pseudo_bit_t SDmaUnexpDataErrClear[1]; + pseudo_bit_t IBStatusChangedClear[1]; + pseudo_bit_t InvalidAddrErrClear[1]; + pseudo_bit_t ResetNegatedClear[1]; + pseudo_bit_t HardwareErrClear[1]; + pseudo_bit_t SDmaDescAddrMisalignErrClear[1]; + pseudo_bit_t InvalidEEPCmdErrClear[1]; + pseudo_bit_t Reserved[10]; +}; +struct QIB_7220_ErrClear { + PSEUDO_BIT_STRUCT ( struct QIB_7220_ErrClear_pb ); +}; + +#define QIB_7220_HwErrMask_offset 0x00000098UL +struct QIB_7220_HwErrMask_pb { + pseudo_bit_t PCIeMemParityErrMask[8]; + pseudo_bit_t Reserved3[20]; + pseudo_bit_t SDmaMemReadErrMask[1]; + pseudo_bit_t PoisonedTLPMask[1]; + pseudo_bit_t PcieCplTimeoutMask[1]; + pseudo_bit_t PCIeBusParityErrMask[3]; + pseudo_bit_t Reserved2[2]; + pseudo_bit_t PCIEOct0_uC_MemoryParityErrMask[1]; + pseudo_bit_t PCIEOct1_uC_MemoryParityErrMask[1]; + pseudo_bit_t IB_uC_MemoryParityErrMask[1]; + pseudo_bit_t DDSRXEQMemoryParityErrMask[1]; + pseudo_bit_t TXEMemParityErrMask[4]; + pseudo_bit_t RXEMemParityErrMask[7]; + pseudo_bit_t Reserved1[3]; + pseudo_bit_t PowerOnBISTFailedMask[1]; + pseudo_bit_t Reserved[1]; + pseudo_bit_t PCIESerdesQ0PClkNotDetectMask[1]; + pseudo_bit_t PCIESerdesQ1PClkNotDetectMask[1]; + pseudo_bit_t PCIESerdesQ2PClkNotDetectMask[1]; + pseudo_bit_t PCIESerdesQ3PClkNotDetectMask[1]; + pseudo_bit_t IBSerdesPClkNotDetectMask[1]; + pseudo_bit_t Clk_uC_PLLNotLockedMask[1]; + pseudo_bit_t IBCBusToSPCParityErrMask[1]; + pseudo_bit_t IBCBusFromSPCParityErrMask[1]; +}; +struct QIB_7220_HwErrMask { + PSEUDO_BIT_STRUCT ( struct QIB_7220_HwErrMask_pb ); +}; + +#define QIB_7220_HwErrStatus_offset 0x000000a0UL +struct QIB_7220_HwErrStatus_pb { + pseudo_bit_t PCIeMemParity[8]; + pseudo_bit_t Reserved3[20]; + pseudo_bit_t SDmaMemReadErr[1]; + pseudo_bit_t PoisenedTLP[1]; + pseudo_bit_t PcieCplTimeout[1]; + pseudo_bit_t PCIeBusParity[3]; + pseudo_bit_t Reserved2[2]; + pseudo_bit_t PCIE_uC_Oct0MemoryParityErr[1]; + pseudo_bit_t PCIE_uC_Oct1MemoryParityErr[1]; + pseudo_bit_t IB_uC_MemoryParityErr[1]; + pseudo_bit_t DDSRXEQMemoryParityErr[1]; + pseudo_bit_t TXEMemParity[4]; + pseudo_bit_t RXEMemParity[7]; + pseudo_bit_t Reserved1[3]; + pseudo_bit_t PowerOnBISTFailed[1]; + pseudo_bit_t Reserved[1]; + pseudo_bit_t PCIESerdesQ0PClkNotDetect[1]; + pseudo_bit_t PCIESerdesQ1PClkNotDetect[1]; + pseudo_bit_t PCIESerdesQ2PClkNotDetect[1]; + pseudo_bit_t PCIESerdesQ3PClkNotDetect[1]; + pseudo_bit_t IBSerdesPClkNotDetect[1]; + pseudo_bit_t Clk_uC_PLLNotLocked[1]; + pseudo_bit_t IBCBusToSPCParityErr[1]; + pseudo_bit_t IBCBusFromSPCParityErr[1]; +}; +struct QIB_7220_HwErrStatus { + PSEUDO_BIT_STRUCT ( struct QIB_7220_HwErrStatus_pb ); +}; + +#define QIB_7220_HwErrClear_offset 0x000000a8UL +struct QIB_7220_HwErrClear_pb { + pseudo_bit_t PCIeMemParityClr[8]; + pseudo_bit_t Reserved3[20]; + pseudo_bit_t SDmaMemReadErrClear[1]; + pseudo_bit_t PoisonedTLPClear[1]; + pseudo_bit_t PcieCplTimeoutClear[1]; + pseudo_bit_t PCIeBusParityClr[3]; + pseudo_bit_t Reserved2[2]; + pseudo_bit_t PCIE_uC_Oct0MemoryParityErrClear[1]; + pseudo_bit_t PCIE_uC_Oct1MemoryParityErrClear[1]; + pseudo_bit_t IB_uC_MemoryParityErrClear[1]; + pseudo_bit_t DDSRXEQMemoryParityErrClear[1]; + pseudo_bit_t TXEMemParityClear[4]; + pseudo_bit_t RXEMemParityClear[7]; + pseudo_bit_t Reserved1[3]; + pseudo_bit_t PowerOnBISTFailedClear[1]; + pseudo_bit_t Reserved[1]; + pseudo_bit_t PCIESerdesQ0PClkNotDetectClear[1]; + pseudo_bit_t PCIESerdesQ1PClkNotDetectClear[1]; + pseudo_bit_t PCIESerdesQ2PClkNotDetectClear[1]; + pseudo_bit_t PCIESerdesQ3PClkNotDetectClear[1]; + pseudo_bit_t IBSerdesPClkNotDetectClear[1]; + pseudo_bit_t Clk_uC_PLLNotLockedClear[1]; + pseudo_bit_t IBCBusToSPCparityErrClear[1]; + pseudo_bit_t IBCBusFromSPCParityErrClear[1]; +}; +struct QIB_7220_HwErrClear { + PSEUDO_BIT_STRUCT ( struct QIB_7220_HwErrClear_pb ); +}; + +#define QIB_7220_HwDiagCtrl_offset 0x000000b0UL +struct QIB_7220_HwDiagCtrl_pb { + pseudo_bit_t forcePCIeMemParity[8]; + pseudo_bit_t Reserved2[23]; + pseudo_bit_t forcePCIeBusParity[4]; + pseudo_bit_t Reserved1[1]; + pseudo_bit_t ForcePCIE_uC_Oct0MemoryParityErr[1]; + pseudo_bit_t ForcePCIE_uC_Oct1MemoryParityErr[1]; + pseudo_bit_t ForceIB_uC_MemoryParityErr[1]; + pseudo_bit_t ForceDDSRXEQMemoryParityErr[1]; + pseudo_bit_t ForceTxMemparityErr[4]; + pseudo_bit_t ForceRxMemParityErr[7]; + pseudo_bit_t Reserved[9]; + pseudo_bit_t CounterDisable[1]; + pseudo_bit_t CounterWrEnable[1]; + pseudo_bit_t ForceIBCBusToSPCParityErr[1]; + pseudo_bit_t ForceIBCBusFromSPCParityErr[1]; +}; +struct QIB_7220_HwDiagCtrl { + PSEUDO_BIT_STRUCT ( struct QIB_7220_HwDiagCtrl_pb ); +}; + +#define QIB_7220_REG_0000B8_offset 0x000000b8UL + +#define QIB_7220_IBCStatus_offset 0x000000c0UL +struct QIB_7220_IBCStatus_pb { + pseudo_bit_t LinkTrainingState[5]; + pseudo_bit_t LinkState[3]; + pseudo_bit_t LinkSpeedActive[1]; + pseudo_bit_t LinkWidthActive[1]; + pseudo_bit_t DDS_RXEQ_FAIL[1]; + pseudo_bit_t IB_SERDES_TRIM_DONE[1]; + pseudo_bit_t IBRxLaneReversed[1]; + pseudo_bit_t IBTxLaneReversed[1]; + pseudo_bit_t Reserved[16]; + pseudo_bit_t TxReady[1]; + pseudo_bit_t TxCreditOk[1]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_IBCStatus { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCStatus_pb ); +}; + +#define QIB_7220_IBCCtrl_offset 0x000000c8UL +struct QIB_7220_IBCCtrl_pb { + pseudo_bit_t FlowCtrlPeriod[8]; + pseudo_bit_t FlowCtrlWaterMark[8]; + pseudo_bit_t LinkInitCmd[3]; + pseudo_bit_t LinkCmd[2]; + pseudo_bit_t MaxPktLen[11]; + pseudo_bit_t PhyerrThreshold[4]; + pseudo_bit_t OverrunThreshold[4]; + pseudo_bit_t CreditScale[3]; + pseudo_bit_t Reserved[19]; + pseudo_bit_t LinkDownDefaultState[1]; + pseudo_bit_t Loopback[1]; +}; +struct QIB_7220_IBCCtrl { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCCtrl_pb ); +}; + +#define QIB_7220_EXTStatus_offset 0x000000d0UL +struct QIB_7220_EXTStatus_pb { + pseudo_bit_t Reserved2[14]; + pseudo_bit_t MemBISTEndTest[1]; + pseudo_bit_t MemBISTDisabled[1]; + pseudo_bit_t Reserved1[16]; + pseudo_bit_t Reserved[16]; + pseudo_bit_t GPIOIn[16]; +}; +struct QIB_7220_EXTStatus { + PSEUDO_BIT_STRUCT ( struct QIB_7220_EXTStatus_pb ); +}; + +#define QIB_7220_EXTCtrl_offset 0x000000d8UL +struct QIB_7220_EXTCtrl_pb { + pseudo_bit_t LEDGblErrRedOff[1]; + pseudo_bit_t LEDGblOkGreenOn[1]; + pseudo_bit_t LEDPriPortYellowOn[1]; + pseudo_bit_t LEDPriPortGreenOn[1]; + pseudo_bit_t Reserved[28]; + pseudo_bit_t GPIOInvert[16]; + pseudo_bit_t GPIOOe[16]; +}; +struct QIB_7220_EXTCtrl { + PSEUDO_BIT_STRUCT ( struct QIB_7220_EXTCtrl_pb ); +}; + +#define QIB_7220_GPIOOut_offset 0x000000e0UL + +#define QIB_7220_GPIOMask_offset 0x000000e8UL + +#define QIB_7220_GPIOStatus_offset 0x000000f0UL + +#define QIB_7220_GPIOClear_offset 0x000000f8UL + +#define QIB_7220_RcvCtrl_offset 0x00000100UL +struct QIB_7220_RcvCtrl_pb { + pseudo_bit_t PortEnable[17]; + pseudo_bit_t IntrAvail[17]; + pseudo_bit_t RcvPartitionKeyDisable[1]; + pseudo_bit_t TailUpd[1]; + pseudo_bit_t PortCfg[2]; + pseudo_bit_t RcvQPMapEnable[1]; + pseudo_bit_t Reserved[25]; +}; +struct QIB_7220_RcvCtrl { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvCtrl_pb ); +}; + +#define QIB_7220_RcvBTHQP_offset 0x00000108UL +struct QIB_7220_RcvBTHQP_pb { + pseudo_bit_t RcvBTHQP[24]; + pseudo_bit_t Reserved[8]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_RcvBTHQP { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvBTHQP_pb ); +}; + +#define QIB_7220_RcvHdrSize_offset 0x00000110UL + +#define QIB_7220_RcvHdrCnt_offset 0x00000118UL + +#define QIB_7220_RcvHdrEntSize_offset 0x00000120UL + +#define QIB_7220_RcvTIDBase_offset 0x00000128UL + +#define QIB_7220_RcvTIDCnt_offset 0x00000130UL + +#define QIB_7220_RcvEgrBase_offset 0x00000138UL + +#define QIB_7220_RcvEgrCnt_offset 0x00000140UL + +#define QIB_7220_RcvBufBase_offset 0x00000148UL + +#define QIB_7220_RcvBufSize_offset 0x00000150UL + +#define QIB_7220_RxIntMemBase_offset 0x00000158UL + +#define QIB_7220_RxIntMemSize_offset 0x00000160UL + +#define QIB_7220_RcvPartitionKey_offset 0x00000168UL + +#define QIB_7220_RcvQPMulticastPort_offset 0x00000170UL +struct QIB_7220_RcvQPMulticastPort_pb { + pseudo_bit_t RcvQpMcPort[5]; + pseudo_bit_t Reserved[59]; +}; +struct QIB_7220_RcvQPMulticastPort { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvQPMulticastPort_pb ); +}; + +#define QIB_7220_RcvPktLEDCnt_offset 0x00000178UL +struct QIB_7220_RcvPktLEDCnt_pb { + pseudo_bit_t OFFperiod[32]; + pseudo_bit_t ONperiod[32]; +}; +struct QIB_7220_RcvPktLEDCnt { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvPktLEDCnt_pb ); +}; + +#define QIB_7220_IBCDDRCtrl_offset 0x00000180UL +struct QIB_7220_IBCDDRCtrl_pb { + pseudo_bit_t IB_ENHANCED_MODE[1]; + pseudo_bit_t SD_SPEED[1]; + pseudo_bit_t SD_SPEED_SDR[1]; + pseudo_bit_t SD_SPEED_DDR[1]; + pseudo_bit_t SD_SPEED_QDR[1]; + pseudo_bit_t IB_NUM_CHANNELS[2]; + pseudo_bit_t IB_POLARITY_REV_SUPP[1]; + pseudo_bit_t IB_LANE_REV_SUPPORTED[1]; + pseudo_bit_t SD_RX_EQUAL_ENABLE[1]; + pseudo_bit_t SD_ADD_ENB[1]; + pseudo_bit_t SD_DDSV[1]; + pseudo_bit_t SD_DDS[4]; + pseudo_bit_t HRTBT_ENB[1]; + pseudo_bit_t HRTBT_AUTO[1]; + pseudo_bit_t HRTBT_PORT[8]; + pseudo_bit_t HRTBT_REQ[1]; + pseudo_bit_t Reserved[5]; + pseudo_bit_t IB_DLID[16]; + pseudo_bit_t IB_DLID_MASK[16]; +}; +struct QIB_7220_IBCDDRCtrl { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCDDRCtrl_pb ); +}; + +#define QIB_7220_HRTBT_GUID_offset 0x00000188UL + +#define QIB_7220_IB_SDTEST_IF_TX_offset 0x00000190UL +struct QIB_7220_IB_SDTEST_IF_TX_pb { + pseudo_bit_t TS_T_TX_VALID[1]; + pseudo_bit_t TS_3_TX_VALID[1]; + pseudo_bit_t Reserved1[9]; + pseudo_bit_t TS_TX_OPCODE[2]; + pseudo_bit_t TS_TX_SPEED[3]; + pseudo_bit_t Reserved[16]; + pseudo_bit_t TS_TX_TX_CFG[16]; + pseudo_bit_t TS_TX_RX_CFG[16]; +}; +struct QIB_7220_IB_SDTEST_IF_TX { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IB_SDTEST_IF_TX_pb ); +}; + +#define QIB_7220_IB_SDTEST_IF_RX_offset 0x00000198UL +struct QIB_7220_IB_SDTEST_IF_RX_pb { + pseudo_bit_t TS_T_RX_VALID[1]; + pseudo_bit_t TS_3_RX_VALID[1]; + pseudo_bit_t Reserved[14]; + pseudo_bit_t TS_RX_A[8]; + pseudo_bit_t TS_RX_B[8]; + pseudo_bit_t TS_RX_TX_CFG[16]; + pseudo_bit_t TS_RX_RX_CFG[16]; +}; +struct QIB_7220_IB_SDTEST_IF_RX { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IB_SDTEST_IF_RX_pb ); +}; + +#define QIB_7220_IBCDDRCtrl2_offset 0x000001a0UL +struct QIB_7220_IBCDDRCtrl2_pb { + pseudo_bit_t IB_FRONT_PORCH[5]; + pseudo_bit_t IB_BACK_PORCH[5]; + pseudo_bit_t _unused_0[54]; +}; +struct QIB_7220_IBCDDRCtrl2 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCDDRCtrl2_pb ); +}; + +#define QIB_7220_IBCDDRStatus_offset 0x000001a8UL +struct QIB_7220_IBCDDRStatus_pb { + pseudo_bit_t LinkRoundTripLatency[26]; + pseudo_bit_t ReqDDSLocalFromRmt[4]; + pseudo_bit_t RxEqLocalDevice[2]; + pseudo_bit_t heartbeat_crosstalk[4]; + pseudo_bit_t heartbeat_timed_out[1]; + pseudo_bit_t _unused_0[27]; +}; +struct QIB_7220_IBCDDRStatus { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCDDRStatus_pb ); +}; + +#define QIB_7220_JIntReload_offset 0x000001b0UL +struct QIB_7220_JIntReload_pb { + pseudo_bit_t J_reload[16]; + pseudo_bit_t J_limit_reload[16]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_JIntReload { + PSEUDO_BIT_STRUCT ( struct QIB_7220_JIntReload_pb ); +}; + +#define QIB_7220_IBNCModeCtrl_offset 0x000001b8UL +struct QIB_7220_IBNCModeCtrl_pb { + pseudo_bit_t TSMEnable_send_TS1[1]; + pseudo_bit_t TSMEnable_send_TS2[1]; + pseudo_bit_t TSMEnable_ignore_TSM_on_rx[1]; + pseudo_bit_t Reserved1[5]; + pseudo_bit_t TSMCode_TS1[9]; + pseudo_bit_t TSMCode_TS2[9]; + pseudo_bit_t Reserved[38]; +}; +struct QIB_7220_IBNCModeCtrl { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IBNCModeCtrl_pb ); +}; + +#define QIB_7220_SendCtrl_offset 0x000001c0UL +struct QIB_7220_SendCtrl_pb { + pseudo_bit_t Abort[1]; + pseudo_bit_t SendIntBufAvail[1]; + pseudo_bit_t SendBufAvailUpd[1]; + pseudo_bit_t SPioEnable[1]; + pseudo_bit_t SSpecialTriggerEn[1]; + pseudo_bit_t Reserved2[4]; + pseudo_bit_t SDmaIntEnable[1]; + pseudo_bit_t SDmaSingleDescriptor[1]; + pseudo_bit_t SDmaEnable[1]; + pseudo_bit_t SDmaHalt[1]; + pseudo_bit_t Reserved1[3]; + pseudo_bit_t DisarmPIOBuf[8]; + pseudo_bit_t AvailUpdThld[5]; + pseudo_bit_t Reserved[2]; + pseudo_bit_t Disarm[1]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_SendCtrl { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendCtrl_pb ); +}; + +#define QIB_7220_SendBufBase_offset 0x000001c8UL +struct QIB_7220_SendBufBase_pb { + pseudo_bit_t BaseAddr_SmallPIO[21]; + pseudo_bit_t Reserved1[11]; + pseudo_bit_t BaseAddr_LargePIO[21]; + pseudo_bit_t Reserved[11]; +}; +struct QIB_7220_SendBufBase { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufBase_pb ); +}; + +#define QIB_7220_SendBufSize_offset 0x000001d0UL +struct QIB_7220_SendBufSize_pb { + pseudo_bit_t Size_SmallPIO[12]; + pseudo_bit_t Reserved1[20]; + pseudo_bit_t Size_LargePIO[13]; + pseudo_bit_t Reserved[19]; +}; +struct QIB_7220_SendBufSize { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufSize_pb ); +}; + +#define QIB_7220_SendBufCnt_offset 0x000001d8UL +struct QIB_7220_SendBufCnt_pb { + pseudo_bit_t Num_SmallBuffers[9]; + pseudo_bit_t Reserved1[23]; + pseudo_bit_t Num_LargeBuffers[4]; + pseudo_bit_t Reserved[28]; +}; +struct QIB_7220_SendBufCnt { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufCnt_pb ); +}; + +#define QIB_7220_SendBufAvailAddr_offset 0x000001e0UL +struct QIB_7220_SendBufAvailAddr_pb { + pseudo_bit_t Reserved[6]; + pseudo_bit_t SendBufAvailAddr[34]; + pseudo_bit_t _unused_0[24]; +}; +struct QIB_7220_SendBufAvailAddr { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufAvailAddr_pb ); +}; + +#define QIB_7220_TxIntMemBase_offset 0x000001e8UL + +#define QIB_7220_TxIntMemSize_offset 0x000001f0UL + +#define QIB_7220_SendDmaBase_offset 0x000001f8UL +struct QIB_7220_SendDmaBase_pb { + pseudo_bit_t SendDmaBase[48]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_SendDmaBase { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaBase_pb ); +}; + +#define QIB_7220_SendDmaLenGen_offset 0x00000200UL +struct QIB_7220_SendDmaLenGen_pb { + pseudo_bit_t Length[16]; + pseudo_bit_t Generation[3]; + pseudo_bit_t Reserved[45]; +}; +struct QIB_7220_SendDmaLenGen { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaLenGen_pb ); +}; + +#define QIB_7220_SendDmaTail_offset 0x00000208UL +struct QIB_7220_SendDmaTail_pb { + pseudo_bit_t SendDmaTail[16]; + pseudo_bit_t Reserved[48]; +}; +struct QIB_7220_SendDmaTail { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaTail_pb ); +}; + +#define QIB_7220_SendDmaHead_offset 0x00000210UL +struct QIB_7220_SendDmaHead_pb { + pseudo_bit_t SendDmaHead[16]; + pseudo_bit_t Reserved1[16]; + pseudo_bit_t InternalSendDmaHead[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_SendDmaHead { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaHead_pb ); +}; + +#define QIB_7220_SendDmaHeadAddr_offset 0x00000218UL +struct QIB_7220_SendDmaHeadAddr_pb { + pseudo_bit_t SendDmaHeadAddr[48]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_SendDmaHeadAddr { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaHeadAddr_pb ); +}; + +#define QIB_7220_SendDmaBufMask0_offset 0x00000220UL +struct QIB_7220_SendDmaBufMask0_pb { + pseudo_bit_t BufMask_63_0[0]; + pseudo_bit_t _unused_0[64]; +}; +struct QIB_7220_SendDmaBufMask0 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaBufMask0_pb ); +}; + +#define QIB_7220_SendDmaStatus_offset 0x00000238UL +struct QIB_7220_SendDmaStatus_pb { + pseudo_bit_t SplFifoDescIndex[16]; + pseudo_bit_t SplFifoBufNum[8]; + pseudo_bit_t SplFifoFull[1]; + pseudo_bit_t SplFifoEmpty[1]; + pseudo_bit_t SplFifoDisarmed[1]; + pseudo_bit_t SplFifoReadyToGo[1]; + pseudo_bit_t ScbFetchDescFlag[1]; + pseudo_bit_t ScbEntryValid[1]; + pseudo_bit_t ScbEmpty[1]; + pseudo_bit_t ScbFull[1]; + pseudo_bit_t RpyTag_7_0[8]; + pseudo_bit_t RpyLowAddr_6_0[7]; + pseudo_bit_t ScbDescIndex_13_0[14]; + pseudo_bit_t InternalSDmaEnable[1]; + pseudo_bit_t AbortInProg[1]; + pseudo_bit_t ScoreBoardDrainInProg[1]; +}; +struct QIB_7220_SendDmaStatus { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaStatus_pb ); +}; + +#define QIB_7220_SendBufErr0_offset 0x00000240UL +struct QIB_7220_SendBufErr0_pb { + pseudo_bit_t SendBufErr_63_0[0]; + pseudo_bit_t _unused_0[64]; +}; +struct QIB_7220_SendBufErr0 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufErr0_pb ); +}; + +#define QIB_7220_REG_000258_offset 0x00000258UL + +#define QIB_7220_AvailUpdCount_offset 0x00000268UL +struct QIB_7220_AvailUpdCount_pb { + pseudo_bit_t AvailUpdCount[5]; + pseudo_bit_t _unused_0[59]; +}; +struct QIB_7220_AvailUpdCount { + PSEUDO_BIT_STRUCT ( struct QIB_7220_AvailUpdCount_pb ); +}; + +#define QIB_7220_RcvHdrAddr0_offset 0x00000270UL +struct QIB_7220_RcvHdrAddr0_pb { + pseudo_bit_t Reserved[2]; + pseudo_bit_t RcvHdrAddr0[38]; + pseudo_bit_t _unused_0[24]; +}; +struct QIB_7220_RcvHdrAddr0 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrAddr0_pb ); +}; + +#define QIB_7220_REG_0002F8_offset 0x000002f8UL + +#define QIB_7220_RcvHdrTailAddr0_offset 0x00000300UL +struct QIB_7220_RcvHdrTailAddr0_pb { + pseudo_bit_t Reserved[2]; + pseudo_bit_t RcvHdrTailAddr0[38]; + pseudo_bit_t _unused_0[24]; +}; +struct QIB_7220_RcvHdrTailAddr0 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrTailAddr0_pb ); +}; + +#define QIB_7220_REG_000388_offset 0x00000388UL + +#define QIB_7220_ibsd_epb_access_ctrl_offset 0x000003c0UL +struct QIB_7220_ibsd_epb_access_ctrl_pb { + pseudo_bit_t sw_ib_epb_req[1]; + pseudo_bit_t Reserved[7]; + pseudo_bit_t sw_ib_epb_req_granted[1]; + pseudo_bit_t _unused_0[55]; +}; +struct QIB_7220_ibsd_epb_access_ctrl { + PSEUDO_BIT_STRUCT ( struct QIB_7220_ibsd_epb_access_ctrl_pb ); +}; + +#define QIB_7220_ibsd_epb_transaction_reg_offset 0x000003c8UL +struct QIB_7220_ibsd_epb_transaction_reg_pb { + pseudo_bit_t ib_epb_data[8]; + pseudo_bit_t ib_epb_address[15]; + pseudo_bit_t Reserved2[1]; + pseudo_bit_t ib_epb_read_write[1]; + pseudo_bit_t ib_epb_cs[2]; + pseudo_bit_t Reserved1[1]; + pseudo_bit_t mem_data_parity[1]; + pseudo_bit_t Reserved[1]; + pseudo_bit_t ib_epb_req_error[1]; + pseudo_bit_t ib_epb_rdy[1]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_ibsd_epb_transaction_reg { + PSEUDO_BIT_STRUCT ( struct QIB_7220_ibsd_epb_transaction_reg_pb ); +}; + +#define QIB_7220_REG_0003D0_offset 0x000003d0UL + +#define QIB_7220_XGXSCfg_offset 0x000003d8UL +struct QIB_7220_XGXSCfg_pb { + pseudo_bit_t tx_rx_reset[1]; + pseudo_bit_t Reserved2[1]; + pseudo_bit_t xcv_reset[1]; + pseudo_bit_t Reserved1[6]; + pseudo_bit_t link_sync_mask[10]; + pseudo_bit_t Reserved[44]; + pseudo_bit_t sel_link_down_for_fctrl_lane_sync_reset[1]; +}; +struct QIB_7220_XGXSCfg { + PSEUDO_BIT_STRUCT ( struct QIB_7220_XGXSCfg_pb ); +}; + +#define QIB_7220_IBSerDesCtrl_offset 0x000003e0UL +struct QIB_7220_IBSerDesCtrl_pb { + pseudo_bit_t ResetIB_uC_Core[1]; + pseudo_bit_t Reserved2[7]; + pseudo_bit_t NumSerDesRegsToWrForDDS[5]; + pseudo_bit_t NumSerDesRegsToWrForRXEQ[5]; + pseudo_bit_t Reserved1[14]; + pseudo_bit_t TXINV[1]; + pseudo_bit_t RXINV[1]; + pseudo_bit_t RXIDLE[1]; + pseudo_bit_t TWC[1]; + pseudo_bit_t TXOBPD[1]; + pseudo_bit_t PLLM[3]; + pseudo_bit_t PLLN[2]; + pseudo_bit_t CKSEL_uC[2]; + pseudo_bit_t INT_uC[1]; + pseudo_bit_t Reserved[19]; +}; +struct QIB_7220_IBSerDesCtrl { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IBSerDesCtrl_pb ); +}; + +#define QIB_7220_EEPCtlStat_offset 0x000003e8UL +struct QIB_7220_EEPCtlStat_pb { + pseudo_bit_t EPAccEn[2]; + pseudo_bit_t EPReset[1]; + pseudo_bit_t ByteProg[1]; + pseudo_bit_t PageMode[1]; + pseudo_bit_t LstDatWr[1]; + pseudo_bit_t CmdWrErr[1]; + pseudo_bit_t Reserved[24]; + pseudo_bit_t CtlrStat[1]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_EEPCtlStat { + PSEUDO_BIT_STRUCT ( struct QIB_7220_EEPCtlStat_pb ); +}; + +#define QIB_7220_EEPAddrCmd_offset 0x000003f0UL +struct QIB_7220_EEPAddrCmd_pb { + pseudo_bit_t EPAddr[24]; + pseudo_bit_t EPCmd[8]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_EEPAddrCmd { + PSEUDO_BIT_STRUCT ( struct QIB_7220_EEPAddrCmd_pb ); +}; + +#define QIB_7220_EEPData_offset 0x000003f8UL + +#define QIB_7220_pciesd_epb_access_ctrl_offset 0x00000400UL +struct QIB_7220_pciesd_epb_access_ctrl_pb { + pseudo_bit_t sw_pcie_epb_req[1]; + pseudo_bit_t sw_pcieepb_star_en[2]; + pseudo_bit_t Reserved[5]; + pseudo_bit_t sw_pcie_epb_req_granted[1]; + pseudo_bit_t _unused_0[55]; +}; +struct QIB_7220_pciesd_epb_access_ctrl { + PSEUDO_BIT_STRUCT ( struct QIB_7220_pciesd_epb_access_ctrl_pb ); +}; + +#define QIB_7220_pciesd_epb_transaction_reg_offset 0x00000408UL +struct QIB_7220_pciesd_epb_transaction_reg_pb { + pseudo_bit_t pcie_epb_data[8]; + pseudo_bit_t pcie_epb_address[15]; + pseudo_bit_t Reserved1[1]; + pseudo_bit_t pcie_epb_read_write[1]; + pseudo_bit_t pcie_epb_cs[3]; + pseudo_bit_t mem_data_parity[1]; + pseudo_bit_t Reserved[1]; + pseudo_bit_t pcie_epb_req_error[1]; + pseudo_bit_t pcie_epb_rdy[1]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_pciesd_epb_transaction_reg { + PSEUDO_BIT_STRUCT ( struct QIB_7220_pciesd_epb_transaction_reg_pb ); +}; + +#define QIB_7220_efuse_control_reg_offset 0x00000410UL +struct QIB_7220_efuse_control_reg_pb { + pseudo_bit_t start_op[1]; + pseudo_bit_t operation[1]; + pseudo_bit_t read_valid[1]; + pseudo_bit_t req_error[1]; + pseudo_bit_t Reserved[27]; + pseudo_bit_t rdy[1]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_efuse_control_reg { + PSEUDO_BIT_STRUCT ( struct QIB_7220_efuse_control_reg_pb ); +}; + +#define QIB_7220_efuse_rddata0_reg_offset 0x00000418UL + +#define QIB_7220_procmon_register_offset 0x00000438UL +struct QIB_7220_procmon_register_pb { + pseudo_bit_t interval_time[12]; + pseudo_bit_t Reserved1[2]; + pseudo_bit_t clear_counter[1]; + pseudo_bit_t start_counter[1]; + pseudo_bit_t procmon_count[9]; + pseudo_bit_t Reserved[6]; + pseudo_bit_t procmon_count_valid[1]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_procmon_register { + PSEUDO_BIT_STRUCT ( struct QIB_7220_procmon_register_pb ); +}; + +#define QIB_7220_PcieRbufTestReg0_offset 0x00000440UL + +#define QIB_7220_PcieRBufTestReg1_offset 0x00000448UL + +#define QIB_7220_SPC_JTAG_ACCESS_REG_offset 0x00000460UL +struct QIB_7220_SPC_JTAG_ACCESS_REG_pb { + pseudo_bit_t rdy[1]; + pseudo_bit_t tdo[1]; + pseudo_bit_t tdi[1]; + pseudo_bit_t opcode[2]; + pseudo_bit_t bist_en[5]; + pseudo_bit_t SPC_JTAG_ACCESS_EN[1]; + pseudo_bit_t _unused_0[53]; +}; +struct QIB_7220_SPC_JTAG_ACCESS_REG { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SPC_JTAG_ACCESS_REG_pb ); +}; + +#define QIB_7220_LAControlReg_offset 0x00000468UL +struct QIB_7220_LAControlReg_pb { + pseudo_bit_t Finished[1]; + pseudo_bit_t Address[8]; + pseudo_bit_t Mode[2]; + pseudo_bit_t Delay[20]; + pseudo_bit_t Reserved[1]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_LAControlReg { + PSEUDO_BIT_STRUCT ( struct QIB_7220_LAControlReg_pb ); +}; + +#define QIB_7220_GPIODebugSelReg_offset 0x00000470UL +struct QIB_7220_GPIODebugSelReg_pb { + pseudo_bit_t GPIOSourceSelDebug[16]; + pseudo_bit_t SelPulse[16]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_GPIODebugSelReg { + PSEUDO_BIT_STRUCT ( struct QIB_7220_GPIODebugSelReg_pb ); +}; + +#define QIB_7220_DebugPortValueReg_offset 0x00000478UL + +#define QIB_7220_SendDmaBufUsed0_offset 0x00000480UL +struct QIB_7220_SendDmaBufUsed0_pb { + pseudo_bit_t BufUsed_63_0[0]; + pseudo_bit_t _unused_0[64]; +}; +struct QIB_7220_SendDmaBufUsed0 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaBufUsed0_pb ); +}; + +#define QIB_7220_SendDmaReqTagUsed_offset 0x00000498UL +struct QIB_7220_SendDmaReqTagUsed_pb { + pseudo_bit_t ReqTagUsed_7_0[8]; + pseudo_bit_t _unused_0[8]; + pseudo_bit_t Reserved[48]; + pseudo_bit_t _unused_1[8]; +}; +struct QIB_7220_SendDmaReqTagUsed { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaReqTagUsed_pb ); +}; + +#define QIB_7220_efuse_pgm_data0_offset 0x000004a0UL + +#define QIB_7220_MEM_0004B0_offset 0x000004b0UL + +#define QIB_7220_SerDes_DDSRXEQ0_offset 0x00000500UL +struct QIB_7220_SerDes_DDSRXEQ0_pb { + pseudo_bit_t element_num[4]; + pseudo_bit_t reg_addr[6]; + pseudo_bit_t _unused_0[54]; +}; +struct QIB_7220_SerDes_DDSRXEQ0 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SerDes_DDSRXEQ0_pb ); +}; + +#define QIB_7220_MEM_0005F0_offset 0x000005f0UL + +#define QIB_7220_LAMemory_offset 0x00000600UL + +#define QIB_7220_MEM_0007F0_offset 0x000007f0UL + +#define QIB_7220_SendBufAvail0_offset 0x00001000UL +struct QIB_7220_SendBufAvail0_pb { + pseudo_bit_t SendBuf_31_0[0]; + pseudo_bit_t _unused_0[64]; +}; +struct QIB_7220_SendBufAvail0 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufAvail0_pb ); +}; + +#define QIB_7220_MEM_001028_offset 0x00001028UL + +#define QIB_7220_LBIntCnt_offset 0x00013000UL + +#define QIB_7220_LBFlowStallCnt_offset 0x00013008UL + +#define QIB_7220_TxSDmaDescCnt_offset 0x00013010UL + +#define QIB_7220_TxUnsupVLErrCnt_offset 0x00013018UL + +#define QIB_7220_TxDataPktCnt_offset 0x00013020UL + +#define QIB_7220_TxFlowPktCnt_offset 0x00013028UL + +#define QIB_7220_TxDwordCnt_offset 0x00013030UL + +#define QIB_7220_TxLenErrCnt_offset 0x00013038UL + +#define QIB_7220_TxMaxMinLenErrCnt_offset 0x00013040UL + +#define QIB_7220_TxUnderrunCnt_offset 0x00013048UL + +#define QIB_7220_TxFlowStallCnt_offset 0x00013050UL + +#define QIB_7220_TxDroppedPktCnt_offset 0x00013058UL + +#define QIB_7220_RxDroppedPktCnt_offset 0x00013060UL + +#define QIB_7220_RxDataPktCnt_offset 0x00013068UL + +#define QIB_7220_RxFlowPktCnt_offset 0x00013070UL + +#define QIB_7220_RxDwordCnt_offset 0x00013078UL + +#define QIB_7220_RxLenErrCnt_offset 0x00013080UL + +#define QIB_7220_RxMaxMinLenErrCnt_offset 0x00013088UL + +#define QIB_7220_RxICRCErrCnt_offset 0x00013090UL + +#define QIB_7220_RxVCRCErrCnt_offset 0x00013098UL + +#define QIB_7220_RxFlowCtrlViolCnt_offset 0x000130a0UL + +#define QIB_7220_RxVersionErrCnt_offset 0x000130a8UL + +#define QIB_7220_RxLinkMalformCnt_offset 0x000130b0UL + +#define QIB_7220_RxEBPCnt_offset 0x000130b8UL + +#define QIB_7220_RxLPCRCErrCnt_offset 0x000130c0UL + +#define QIB_7220_RxBufOvflCnt_offset 0x000130c8UL + +#define QIB_7220_RxTIDFullErrCnt_offset 0x000130d0UL + +#define QIB_7220_RxTIDValidErrCnt_offset 0x000130d8UL + +#define QIB_7220_RxPKeyMismatchCnt_offset 0x000130e0UL + +#define QIB_7220_RxP0HdrEgrOvflCnt_offset 0x000130e8UL + +#define QIB_7220_IBStatusChangeCnt_offset 0x00013170UL + +#define QIB_7220_IBLinkErrRecoveryCnt_offset 0x00013178UL + +#define QIB_7220_IBLinkDownedCnt_offset 0x00013180UL + +#define QIB_7220_IBSymbolErrCnt_offset 0x00013188UL + +#define QIB_7220_RxVL15DroppedPktCnt_offset 0x00013190UL + +#define QIB_7220_RxOtherLocalPhyErrCnt_offset 0x00013198UL + +#define QIB_7220_PcieRetryBufDiagQwordCnt_offset 0x000131a0UL + +#define QIB_7220_ExcessBufferOvflCnt_offset 0x000131a8UL + +#define QIB_7220_LocalLinkIntegrityErrCnt_offset 0x000131b0UL + +#define QIB_7220_RxVlErrCnt_offset 0x000131b8UL + +#define QIB_7220_RxDlidFltrCnt_offset 0x000131c0UL + +#define QIB_7220_CNT_0131C8_offset 0x000131c8UL + +#define QIB_7220_PSStat_offset 0x00013200UL + +#define QIB_7220_PSStart_offset 0x00013208UL + +#define QIB_7220_PSInterval_offset 0x00013210UL + +#define QIB_7220_PSRcvDataCount_offset 0x00013218UL + +#define QIB_7220_PSRcvPktsCount_offset 0x00013220UL + +#define QIB_7220_PSXmitDataCount_offset 0x00013228UL + +#define QIB_7220_PSXmitPktsCount_offset 0x00013230UL + +#define QIB_7220_PSXmitWaitCount_offset 0x00013238UL + +#define QIB_7220_CNT_013240_offset 0x00013240UL + +#define QIB_7220_RcvEgrArray_offset 0x00014000UL + +#define QIB_7220_MEM_038000_offset 0x00038000UL + +#define QIB_7220_RcvTIDArray0_offset 0x00053000UL + +#define QIB_7220_PIOLaunchFIFO_offset 0x00064000UL + +#define QIB_7220_MEM_064480_offset 0x00064480UL + +#define QIB_7220_SendPIOpbcCache_offset 0x00064800UL + +#define QIB_7220_MEM_064C80_offset 0x00064c80UL + +#define QIB_7220_PreLaunchFIFO_offset 0x00065000UL + +#define QIB_7220_MEM_065080_offset 0x00065080UL + +#define QIB_7220_ScoreBoard_offset 0x00065400UL + +#define QIB_7220_MEM_065440_offset 0x00065440UL + +#define QIB_7220_DescriptorFIFO_offset 0x00065800UL + +#define QIB_7220_MEM_065880_offset 0x00065880UL + +#define QIB_7220_RcvBuf1_offset 0x00072000UL + +#define QIB_7220_MEM_074800_offset 0x00074800UL + +#define QIB_7220_RcvBuf2_offset 0x00075000UL + +#define QIB_7220_MEM_076400_offset 0x00076400UL + +#define QIB_7220_RcvFlags_offset 0x00077000UL + +#define QIB_7220_MEM_078400_offset 0x00078400UL + +#define QIB_7220_RcvLookupBuf1_offset 0x00079000UL + +#define QIB_7220_MEM_07A400_offset 0x0007a400UL + +#define QIB_7220_RcvDMADatBuf_offset 0x0007b000UL + +#define QIB_7220_RcvDMAHdrBuf_offset 0x0007b800UL + +#define QIB_7220_MiscRXEIntMem_offset 0x0007c000UL + +#define QIB_7220_MEM_07D400_offset 0x0007d400UL + +#define QIB_7220_PCIERcvBuf_offset 0x00080000UL + +#define QIB_7220_PCIERetryBuf_offset 0x00084000UL + +#define QIB_7220_PCIERcvBufRdToWrAddr_offset 0x00088000UL + +#define QIB_7220_PCIECplBuf_offset 0x00090000UL + +#define QIB_7220_IBSerDesMappTable_offset 0x00094000UL + +#define QIB_7220_MEM_095000_offset 0x00095000UL + +#define QIB_7220_SendBuf0_MA_offset 0x00100000UL + +#define QIB_7220_MEM_1A0000_offset 0x001a0000UL + +#define QIB_7220_RcvHdrTail0_offset 0x00200000UL + +#define QIB_7220_RcvHdrHead0_offset 0x00200008UL +struct QIB_7220_RcvHdrHead0_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead0 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead0_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail0_offset 0x00200010UL + +#define QIB_7220_RcvEgrIndexHead0_offset 0x00200018UL + +#define QIB_7220_MEM_200020_offset 0x00200020UL + +#define QIB_7220_RcvHdrTail1_offset 0x00210000UL + +#define QIB_7220_RcvHdrHead1_offset 0x00210008UL +struct QIB_7220_RcvHdrHead1_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead1 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead1_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail1_offset 0x00210010UL + +#define QIB_7220_RcvEgrIndexHead1_offset 0x00210018UL + +#define QIB_7220_MEM_210020_offset 0x00210020UL + +#define QIB_7220_RcvHdrTail2_offset 0x00220000UL + +#define QIB_7220_RcvHdrHead2_offset 0x00220008UL +struct QIB_7220_RcvHdrHead2_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead2 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead2_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail2_offset 0x00220010UL + +#define QIB_7220_RcvEgrIndexHead2_offset 0x00220018UL + +#define QIB_7220_MEM_220020_offset 0x00220020UL + +#define QIB_7220_RcvHdrTail3_offset 0x00230000UL + +#define QIB_7220_RcvHdrHead3_offset 0x00230008UL +struct QIB_7220_RcvHdrHead3_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead3 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead3_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail3_offset 0x00230010UL + +#define QIB_7220_RcvEgrIndexHead3_offset 0x00230018UL + +#define QIB_7220_MEM_230020_offset 0x00230020UL + +#define QIB_7220_RcvHdrTail4_offset 0x00240000UL + +#define QIB_7220_RcvHdrHead4_offset 0x00240008UL +struct QIB_7220_RcvHdrHead4_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead4 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead4_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail4_offset 0x00240010UL + +#define QIB_7220_RcvEgrIndexHead4_offset 0x00240018UL + +#define QIB_7220_MEM_240020_offset 0x00240020UL + +#define QIB_7220_RcvHdrTail5_offset 0x00250000UL + +#define QIB_7220_RcvHdrHead5_offset 0x00250008UL +struct QIB_7220_RcvHdrHead5_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead5 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead5_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail5_offset 0x00250010UL + +#define QIB_7220_RcvEgrIndexHead5_offset 0x00250018UL + +#define QIB_7220_MEM_250020_offset 0x00250020UL + +#define QIB_7220_RcvHdrTail6_offset 0x00260000UL + +#define QIB_7220_RcvHdrHead6_offset 0x00260008UL +struct QIB_7220_RcvHdrHead6_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead6 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead6_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail6_offset 0x00260010UL + +#define QIB_7220_RcvEgrIndexHead6_offset 0x00260018UL + +#define QIB_7220_MEM_260020_offset 0x00260020UL + +#define QIB_7220_RcvHdrTail7_offset 0x00270000UL + +#define QIB_7220_RcvHdrHead7_offset 0x00270008UL +struct QIB_7220_RcvHdrHead7_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead7 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead7_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail7_offset 0x00270010UL + +#define QIB_7220_RcvEgrIndexHead7_offset 0x00270018UL + +#define QIB_7220_MEM_270020_offset 0x00270020UL + +#define QIB_7220_RcvHdrTail8_offset 0x00280000UL + +#define QIB_7220_RcvHdrHead8_offset 0x00280008UL +struct QIB_7220_RcvHdrHead8_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead8 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead8_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail8_offset 0x00280010UL + +#define QIB_7220_RcvEgrIndexHead8_offset 0x00280018UL + +#define QIB_7220_MEM_280020_offset 0x00280020UL + +#define QIB_7220_RcvHdrTail9_offset 0x00290000UL + +#define QIB_7220_RcvHdrHead9_offset 0x00290008UL +struct QIB_7220_RcvHdrHead9_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead9 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead9_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail9_offset 0x00290010UL + +#define QIB_7220_RcvEgrIndexHead9_offset 0x00290018UL + +#define QIB_7220_MEM_290020_offset 0x00290020UL + +#define QIB_7220_RcvHdrTail10_offset 0x002a0000UL + +#define QIB_7220_RcvHdrHead10_offset 0x002a0008UL +struct QIB_7220_RcvHdrHead10_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead10 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead10_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail10_offset 0x002a0010UL + +#define QIB_7220_RcvEgrIndexHead10_offset 0x002a0018UL + +#define QIB_7220_MEM_2A0020_offset 0x002a0020UL + +#define QIB_7220_RcvHdrTail11_offset 0x002b0000UL + +#define QIB_7220_RcvHdrHead11_offset 0x002b0008UL +struct QIB_7220_RcvHdrHead11_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead11 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead11_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail11_offset 0x002b0010UL + +#define QIB_7220_RcvEgrIndexHead11_offset 0x002b0018UL + +#define QIB_7220_MEM_2B0020_offset 0x002b0020UL + +#define QIB_7220_RcvHdrTail12_offset 0x002c0000UL + +#define QIB_7220_RcvHdrHead12_offset 0x002c0008UL +struct QIB_7220_RcvHdrHead12_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead12 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead12_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail12_offset 0x002c0010UL + +#define QIB_7220_RcvEgrIndexHead12_offset 0x002c0018UL + +#define QIB_7220_MEM_2C0020_offset 0x002c0020UL + +#define QIB_7220_RcvHdrTail13_offset 0x002d0000UL + +#define QIB_7220_RcvHdrHead13_offset 0x002d0008UL +struct QIB_7220_RcvHdrHead13_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead13 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead13_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail13_offset 0x002d0010UL + +#define QIB_7220_RcvEgrIndexHead13_offset 0x002d0018UL + +#define QIB_7220_MEM_2D0020_offset 0x002d0020UL + +#define QIB_7220_RcvHdrTail14_offset 0x002e0000UL + +#define QIB_7220_RcvHdrHead14_offset 0x002e0008UL +struct QIB_7220_RcvHdrHead14_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead14 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead14_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail14_offset 0x002e0010UL + +#define QIB_7220_RcvEgrIndexHead14_offset 0x002e0018UL + +#define QIB_7220_MEM_2E0020_offset 0x002e0020UL + +#define QIB_7220_RcvHdrTail15_offset 0x002f0000UL + +#define QIB_7220_RcvHdrHead15_offset 0x002f0008UL +struct QIB_7220_RcvHdrHead15_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead15 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead15_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail15_offset 0x002f0010UL + +#define QIB_7220_RcvEgrIndexHead15_offset 0x002f0018UL + +#define QIB_7220_MEM_2F0020_offset 0x002f0020UL + +#define QIB_7220_RcvHdrTail16_offset 0x00300000UL + +#define QIB_7220_RcvHdrHead16_offset 0x00300008UL +struct QIB_7220_RcvHdrHead16_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead16 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead16_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail16_offset 0x00300010UL + +#define QIB_7220_RcvEgrIndexHead16_offset 0x00300018UL + +#define QIB_7220_MEM_300020_offset 0x00300020UL + diff --git a/gpxe/src/drivers/infiniband/qib_genbits.pl b/gpxe/src/drivers/infiniband/qib_genbits.pl new file mode 100644 index 00000000..9eba4da5 --- /dev/null +++ b/gpxe/src/drivers/infiniband/qib_genbits.pl @@ -0,0 +1,95 @@ +#!/usr/bin/perl -w +# +# Copyright (C) 2008 Michael Brown . +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +use strict; +use warnings; + +my $offsets = {}; +my $structures = {}; +my $structure = ""; + +while ( <> ) { + chomp; + if ( /^\#define (\S+)_OFFS (\S+)$/ ) { + $structure = $1; + $offsets->{$structure} = $2; + } elsif ( /^\#define ${structure}_(\S+)_LSB (\S+)$/ ) { + $structures->{$structure}->{$1}->{LSB} = $2; + } elsif ( /^\#define ${structure}_(\S+)_RMASK (\S+)$/ ) { + $structures->{$structure}->{$1}->{RMASK} = $2; + } elsif ( /^\s*$/ ) { + # Do nothing + } else { + print "$_\n"; + } +} + +my $data = [ map { { name => $_, offset => $offsets->{$_} }; } + sort { hex ( $offsets->{$a} ) <=> hex ( $offsets->{$b} ) } + keys %$offsets ]; + +foreach my $datum ( @$data ) { + next unless exists $structures->{$datum->{name}}; + $structure = $structures->{$datum->{name}}; + my $fields = [ map { { name => $_, lsb => $structure->{$_}->{LSB}, + rmask => $structure->{$_}->{RMASK} }; } + sort { hex ( $structure->{$a}->{LSB} ) <=> + hex ( $structure->{$b}->{LSB} ) } + keys %$structure ]; + $datum->{fields} = $fields; +} + +print "\n/* This file has been further processed by $0 */\n\n\n"; + +foreach my $datum ( @$data ) { + printf "#define %s_offset 0x%08xUL\n", + $datum->{name}, hex ( $datum->{offset} ); + if ( exists $datum->{fields} ) { + my $lsb = 0; + my $reserved_idx = 0; + printf "struct %s_pb {\n", $datum->{name}; + foreach my $field ( @{$datum->{fields}} ) { + my $pad_width = ( hex ( $field->{lsb} ) - $lsb ); + die "Inconsistent LSB/RMASK in $datum->{name}\n" if $pad_width < 0; + printf "\tpseudo_bit_t _unused_%u[%u];\n", $reserved_idx++, $pad_width + if $pad_width; + # Damn Perl can't cope with 64-bit hex constants + my $width = 0; + my $rmask = $field->{rmask}; + while ( $rmask =~ /^(0x.+)f$/i ) { + $width += 4; + $rmask = $1; + } + $rmask = hex ( $rmask ); + while ( $rmask ) { + $width++; + $rmask >>= 1; + } + printf "\tpseudo_bit_t %s[%u];\n", $field->{name}, $width; + $lsb += $width; + } + my $pad_width = ( 64 - $lsb ); + die "Inconsistent LSB/RMASK in $datum->{name}\n" if $pad_width < 0; + printf "\tpseudo_bit_t _unused_%u[%u];\n", $reserved_idx++, $pad_width + if $pad_width; + printf "};\n"; + printf "struct %s {\n\tPSEUDO_BIT_STRUCT ( struct %s_pb );\n};\n", + $datum->{name}, $datum->{name}; + } + print "\n"; +} diff --git a/gpxe/src/drivers/net/3c509.c b/gpxe/src/drivers/net/3c509.c index 8a15aff2..ecfdec55 100644 --- a/gpxe/src/drivers/net/3c509.c +++ b/gpxe/src/drivers/net/3c509.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/gpxe/src/drivers/net/3c595.c b/gpxe/src/drivers/net/3c595.c index 7138f936..198e12e7 100644 --- a/gpxe/src/drivers/net/3c595.c +++ b/gpxe/src/drivers/net/3c595.c @@ -363,7 +363,7 @@ vxgetlink(void) if (n > 0) { printf("/"); } - printf(conn_tab[k].name); + printf("%s", conn_tab[k].name ); n++; } } diff --git a/gpxe/src/drivers/net/3c90x.c b/gpxe/src/drivers/net/3c90x.c index 8158239d..a98e6628 100644 --- a/gpxe/src/drivers/net/3c90x.c +++ b/gpxe/src/drivers/net/3c90x.c @@ -497,7 +497,7 @@ a3c90x_transmit(struct nic *nic __unused, const char *d, unsigned int t, unsigned char status; unsigned i, retries; - tick_t ct; + unsigned long ct; for (retries=0; retries < XMIT_RETRIES ; retries++) { @@ -543,7 +543,7 @@ a3c90x_transmit(struct nic *nic __unused, const char *d, unsigned int t, ct = currticks(); while (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004) && - ct + 10*USECS_IN_MSEC < currticks()); + ct + 10*1000 < currticks()); ; if (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004)) diff --git a/gpxe/src/drivers/net/cs89x0.c b/gpxe/src/drivers/net/cs89x0.c index 11988add..1f647a8e 100644 --- a/gpxe/src/drivers/net/cs89x0.c +++ b/gpxe/src/drivers/net/cs89x0.c @@ -419,8 +419,8 @@ retry: ETH_ALEN/2); outw(((t >> 8)&0xFF)|(t << 8), eth_nic_base + TX_FRAME_PORT); outsw(eth_nic_base + TX_FRAME_PORT, p, (s+1)/2); - for (sr = sr/2 - (s+1)/2 - ETH_ALEN - 1; sr-- > 0; - outw(0, eth_nic_base + TX_FRAME_PORT)); + for (sr = sr/2 - (s+1)/2 - ETH_ALEN - 1; sr > 0; sr--) + outw(0, eth_nic_base + TX_FRAME_PORT); /* wait for transfer to succeed */ for (tmo = currticks()+5*TICKS_PER_SEC; diff --git a/gpxe/src/drivers/net/e1000/e1000.h b/gpxe/src/drivers/net/e1000/e1000.h index 4ae41451..77a09ef1 100644 --- a/gpxe/src/drivers/net/e1000/e1000.h +++ b/gpxe/src/drivers/net/e1000/e1000.h @@ -34,7 +34,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/gpxe/src/drivers/net/e1000/e1000_osdep.h b/gpxe/src/drivers/net/e1000/e1000_osdep.h index 7df9b5e9..c2d9eb9c 100644 --- a/gpxe/src/drivers/net/e1000/e1000_osdep.h +++ b/gpxe/src/drivers/net/e1000/e1000_osdep.h @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include @@ -74,60 +74,60 @@ typedef enum { #define DEBUGOUT3 DEBUGOUT1 #define DEBUGOUT7 DEBUGOUT1 -#define E1000_WRITE_REG(a, reg, value) ( \ +#define E1000_WRITE_REG(a, reg, value) \ writel((value), ((a)->hw_addr + \ - (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg)))) + (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg))) -#define E1000_READ_REG(a, reg) ( \ +#define E1000_READ_REG(a, reg) \ readl((a)->hw_addr + \ - (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg))) + (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg)) -#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \ +#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \ writel((value), ((a)->hw_addr + \ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \ - ((offset) << 2)))) + ((offset) << 2))) -#define E1000_READ_REG_ARRAY(a, reg, offset) ( \ +#define E1000_READ_REG_ARRAY(a, reg, offset) \ readl((a)->hw_addr + \ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \ - ((offset) << 2))) + ((offset) << 2)) #define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY #define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY -#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) ( \ +#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) \ writew((value), ((a)->hw_addr + \ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \ - ((offset) << 1)))) + ((offset) << 1))) -#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \ +#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) \ readw((a)->hw_addr + \ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \ - ((offset) << 1))) + ((offset) << 1)) -#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \ +#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) \ writeb((value), ((a)->hw_addr + \ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \ - (offset)))) + (offset))) -#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \ +#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) \ readb((a)->hw_addr + \ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \ - (offset))) + (offset)) #define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS) -#define E1000_WRITE_ICH_FLASH_REG(a, reg, value) ( \ - writel((value), ((a)->flash_address + reg))) +#define E1000_WRITE_ICH_FLASH_REG(a, reg, value) \ + writel((value), ((a)->flash_address + reg)) -#define E1000_READ_ICH_FLASH_REG(a, reg) ( \ - readl((a)->flash_address + reg)) +#define E1000_READ_ICH_FLASH_REG(a, reg) \ + readl((a)->flash_address + reg) -#define E1000_WRITE_ICH_FLASH_REG16(a, reg, value) ( \ - writew((value), ((a)->flash_address + reg))) +#define E1000_WRITE_ICH_FLASH_REG16(a, reg, value) \ + writew((value), ((a)->flash_address + reg)) -#define E1000_READ_ICH_FLASH_REG16(a, reg) ( \ - readw((a)->flash_address + reg)) +#define E1000_READ_ICH_FLASH_REG16(a, reg) \ + readw((a)->flash_address + reg) #define msleep(n) mdelay(n) diff --git a/gpxe/src/drivers/net/eepro100.c b/gpxe/src/drivers/net/eepro100.c index f746976a..e6e7db49 100644 --- a/gpxe/src/drivers/net/eepro100.c +++ b/gpxe/src/drivers/net/eepro100.c @@ -407,7 +407,7 @@ static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, un } hdr; unsigned short status; int s1, s2; - tick_t ct; + unsigned long ct; status = inw(ioaddr + SCBStatus); /* Acknowledge all of the current interrupt sources ASAP. */ @@ -448,7 +448,7 @@ static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, un ct = currticks(); /* timeout 10 ms for transmit */ - while (!txfd.status && ct + 10*USECS_IN_MSEC) + while (!txfd.status && ct + 10*1000) /* Wait */; s2 = inw (ioaddr + SCBStatus); @@ -608,7 +608,7 @@ static int eepro100_probe ( struct nic *nic, struct pci_device *pci ) { int read_cmd, ee_size; int options; int rx_mode; - tick_t ct; + unsigned long ct; /* we cache only the first few words of the EEPROM data be careful not to access beyond this array */ @@ -753,7 +753,7 @@ static int eepro100_probe ( struct nic *nic, struct pci_device *pci ) { whereami ("started TX thingy (config, iasetup)."); ct = currticks(); - while (!txfd.status && ct + 10*USECS_IN_MSEC < currticks()) + while (!txfd.status && ct + 10*1000 < currticks()) /* Wait */; /* Read the status register once to disgard stale data */ diff --git a/gpxe/src/drivers/net/epic100.c b/gpxe/src/drivers/net/epic100.c index 67b4f0fb..1e36a680 100644 --- a/gpxe/src/drivers/net/epic100.c +++ b/gpxe/src/drivers/net/epic100.c @@ -309,7 +309,7 @@ epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type, unsigned short nstype; unsigned char *txp; int entry; - tick_t ct; + unsigned long ct; /* Calculate the next Tx descriptor entry. */ entry = cur_tx % TX_RING_SIZE; @@ -352,7 +352,7 @@ epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type, ct = currticks(); /* timeout 10 ms for transmit */ while ((le32_to_cpu(tx_ring[entry].status) & (TRING_OWN)) && - ct + 10*USECS_IN_MSEC < currticks()) + ct + 10*1000 < currticks()) /* Wait */; if ((le32_to_cpu(tx_ring[entry].status) & TRING_OWN) != 0) diff --git a/gpxe/src/drivers/net/etherfabric.c b/gpxe/src/drivers/net/etherfabric.c index 8a6b1a17..7cd29f27 100644 --- a/gpxe/src/drivers/net/etherfabric.c +++ b/gpxe/src/drivers/net/etherfabric.c @@ -15,17 +15,21 @@ * ************************************************************************** */ - -#include "etherboot.h" -#include "nic.h" +#include +#include +#include #include +#include +#include +#include #include -#include -#include -#include -#include -#define dma_addr_t unsigned long +#include +#include +#include +#include +#include #include "etherfabric.h" +#include "etherfabric_nic.h" /************************************************************************** * @@ -34,193 +38,35 @@ ************************************************************************** */ -#define EFAB_ASSERT(x) \ - do { \ - if ( ! (x) ) { \ - DBG ( "ASSERT(%s) failed at %s line %d [%s]\n", #x, \ - __FILE__, __LINE__, __FUNCTION__ ); \ - } \ - } while (0) - -#define EFAB_TRACE(...) DBG ( __VA_ARGS__ ) - #define EFAB_REGDUMP(...) +#define EFAB_TRACE(...) DBGP(__VA_ARGS__) -#define EFAB_LOG(...) printf ( __VA_ARGS__ ) -#define EFAB_ERR(...) printf ( __VA_ARGS__ ) - -#define FALCON_USE_IO_BAR 1 +// printf() is not allowed within drivers. Use DBG() instead. +#define EFAB_LOG(...) DBG(__VA_ARGS__) +#define EFAB_ERR(...) DBG(__VA_ARGS__) -/* - * EtherFabric constants - * - */ +#define FALCON_USE_IO_BAR 0 -/* PCI Definitions */ -#define EFAB_VENDID_LEVEL5 0x1924 -#define FALCON_P_DEVID 0x0703 /* Temporary PCI ID */ -#define EF1002_DEVID 0xC101 +#define HZ 100 +#define EFAB_BYTE 1 /************************************************************************** * - * Data structures + * Hardware data structures and sizing * ************************************************************************** */ +extern int __invalid_queue_size; +#define FQS(_prefix, _x) \ + ( ( (_x) == 512 ) ? _prefix ## _SIZE_512 : \ + ( ( (_x) == 1024 ) ? _prefix ## _SIZE_1K : \ + ( ( (_x) == 2048 ) ? _prefix ## _SIZE_2K : \ + ( ( (_x) == 4096) ? _prefix ## _SIZE_4K : \ + __invalid_queue_size ) ) ) ) -/* - * Buffers used for TX, RX and event queue - * - */ -#define EFAB_BUF_ALIGN 4096 -#define EFAB_DATA_BUF_SIZE 2048 -#define EFAB_RX_BUFS 16 -#define EFAB_RXD_SIZE 512 -#define EFAB_TXD_SIZE 512 -#define EFAB_EVQ_SIZE 512 -struct efab_buffers { - uint8_t eventq[4096]; - uint8_t rxd[4096]; - uint8_t txd[4096]; - uint8_t tx_buf[EFAB_DATA_BUF_SIZE]; - uint8_t rx_buf[EFAB_RX_BUFS][EFAB_DATA_BUF_SIZE]; - uint8_t padding[EFAB_BUF_ALIGN-1]; -}; -static struct efab_buffers efab_buffers; - -/** An RX buffer */ -struct efab_rx_buf { - uint8_t *addr; - unsigned int len; - int id; -}; - -/** A TX buffer */ -struct efab_tx_buf { - uint8_t *addr; - unsigned int len; - int id; -}; - -/** Etherfabric event type */ -enum efab_event_type { - EFAB_EV_NONE = 0, - EFAB_EV_TX, - EFAB_EV_RX, -}; - -/** Etherfabric event */ -struct efab_event { - /** Event type */ - enum efab_event_type type; - /** RX buffer ID */ - int rx_id; - /** RX length */ - unsigned int rx_len; - /** Packet should be dropped */ - int drop; -}; - -/* - * Etherfabric abstraction layer - * - */ -struct efab_nic; -struct efab_operations { - void ( * get_membase ) ( struct efab_nic *efab ); - int ( * reset ) ( struct efab_nic *efab ); - int ( * init_nic ) ( struct efab_nic *efab ); - int ( * read_eeprom ) ( struct efab_nic *efab ); - void ( * build_rx_desc ) ( struct efab_nic *efab, - struct efab_rx_buf *rx_buf ); - void ( * notify_rx_desc ) ( struct efab_nic *efab ); - void ( * build_tx_desc ) ( struct efab_nic *efab, - struct efab_tx_buf *tx_buf ); - void ( * notify_tx_desc ) ( struct efab_nic *efab ); - int ( * fetch_event ) ( struct efab_nic *efab, - struct efab_event *event ); - void ( * mask_irq ) ( struct efab_nic *efab, int enabled ); - void ( * generate_irq ) ( struct efab_nic *efab ); - void ( * mdio_write ) ( struct efab_nic *efab, int location, - int value ); - int ( * mdio_read ) ( struct efab_nic *efab, int location ); -}; - -struct efab_mac_operations { - void ( * mac_writel ) ( struct efab_nic *efab, efab_dword_t *value, - unsigned int mac_reg ); - void ( * mac_readl ) ( struct efab_nic *efab, efab_dword_t *value, - unsigned int mac_reg ); - int ( * init ) ( struct efab_nic *efab ); - int ( * reset ) ( struct efab_nic *efab ); -}; - -/* - * Driver private data structure - * - */ -struct efab_nic { - - /** PCI device */ - struct pci_device *pci; - - /** Operations table */ - struct efab_operations *op; - /** MAC operations table */ - struct efab_mac_operations *mac_op; - - /** Memory base */ - void *membase; - - /** I/O base */ - unsigned int iobase; - - /** Buffers */ - uint8_t *eventq; /* Falcon only */ - uint8_t *txd; /* Falcon only */ - uint8_t *rxd; /* Falcon only */ - struct efab_tx_buf tx_buf; - struct efab_rx_buf rx_bufs[EFAB_RX_BUFS]; - - /** Buffer pointers */ - unsigned int eventq_read_ptr; /* Falcon only */ - unsigned int tx_write_ptr; - unsigned int rx_write_ptr; - - /** Port 0/1 on the NIC */ - int port; - - /** MAC address */ - uint8_t mac_addr[ETH_ALEN]; - /** GMII link options */ - unsigned int link_options; - /** Link status */ - int link_up; - - /* Nic type fields */ - int has_flash : 1; - int has_eeprom : 1; - int is_10g : 1; - int is_dual : 1; - int is_asic : 1; - - /** INT_REG_KER for Falcon */ - efab_oword_t int_ker __attribute__ (( aligned ( 16 ) )); - - /** I2C access */ - struct i2c_bit_basher ef1002_i2c; - unsigned long ef1002_i2c_outputs; - struct i2c_device ef1002_eeprom; - - /** SPI access */ - struct spi_bus spi; - struct spi_device falcon_flash; - struct spi_device falcon_eeprom; - - /** Non-volatile options */ - struct nvo_block nvo; -}; +#define EFAB_MAX_FRAME_LEN(mtu) \ + ( ( ( ( mtu ) + 4/* FCS */ ) + 7 ) & ~7 ) /************************************************************************** * @@ -229,6 +75,10 @@ struct efab_nic { ************************************************************************** */ +static void falcon_mdio_write (struct efab_nic *efab, int device, + int location, int value ); +static int falcon_mdio_read ( struct efab_nic *efab, int device, int location ); + /* GMII registers */ #define MII_BMSR 0x01 /* Basic mode status register */ #define MII_ADVERTISE 0x04 /* Advertisement control register */ @@ -257,7 +107,8 @@ struct efab_nic { #define LPA_100 (LPA_100FULL | LPA_100HALF | LPA_100BASE4) #define LPA_1000 ( LPA_1000FULL | LPA_1000HALF ) #define LPA_10000 ( LPA_10000FULL | LPA_10000HALF ) -#define LPA_DUPLEX ( LPA_10FULL | LPA_100FULL | LPA_1000FULL ) +#define LPA_DUPLEX ( LPA_10FULL | LPA_100FULL | LPA_1000FULL | \ + LPA_10000FULL ) /* Mask of bits not associated with speed or duplexity. */ #define LPA_OTHER ~( LPA_10FULL | LPA_10HALF | LPA_100FULL | \ @@ -270,13 +121,15 @@ struct efab_nic { * Retrieve GMII autonegotiation advertised abilities * */ -static unsigned int gmii_autoneg_advertised ( struct efab_nic *efab ) { +static unsigned int +gmii_autoneg_advertised ( struct efab_nic *efab ) +{ unsigned int mii_advertise; unsigned int gmii_advertise; - + /* Extended bits are in bits 8 and 9 of GMII_GTCR */ - mii_advertise = efab->op->mdio_read ( efab, MII_ADVERTISE ); - gmii_advertise = ( ( efab->op->mdio_read ( efab, GMII_GTCR ) >> 8 ) + mii_advertise = falcon_mdio_read ( efab, 0, MII_ADVERTISE ); + gmii_advertise = ( ( falcon_mdio_read ( efab, 0, GMII_GTCR ) >> 8 ) & 0x03 ); return ( ( gmii_advertise << 16 ) | mii_advertise ); } @@ -285,13 +138,15 @@ static unsigned int gmii_autoneg_advertised ( struct efab_nic *efab ) { * Retrieve GMII autonegotiation link partner abilities * */ -static unsigned int gmii_autoneg_lpa ( struct efab_nic *efab ) { +static unsigned int +gmii_autoneg_lpa ( struct efab_nic *efab ) +{ unsigned int mii_lpa; unsigned int gmii_lpa; - + /* Extended bits are in bits 10 and 11 of GMII_GTSR */ - mii_lpa = efab->op->mdio_read ( efab, MII_LPA ); - gmii_lpa = ( efab->op->mdio_read ( efab, GMII_GTSR ) >> 10 ) & 0x03; + mii_lpa = falcon_mdio_read ( efab, 0, MII_LPA ); + gmii_lpa = ( falcon_mdio_read ( efab, 0, GMII_GTSR ) >> 10 ) & 0x03; return ( ( gmii_lpa << 16 ) | mii_lpa ); } @@ -299,7 +154,9 @@ static unsigned int gmii_autoneg_lpa ( struct efab_nic *efab ) { * Calculate GMII autonegotiated link technology * */ -static unsigned int gmii_nway_result ( unsigned int negotiated ) { +static unsigned int +gmii_nway_result ( unsigned int negotiated ) +{ unsigned int other_bits; /* Mask out the speed and duplexity bits */ @@ -324,3108 +181,4061 @@ static unsigned int gmii_nway_result ( unsigned int negotiated ) { * Check GMII PHY link status * */ -static int gmii_link_ok ( struct efab_nic *efab ) { +static int +gmii_link_ok ( struct efab_nic *efab ) +{ int status; int phy_status; - + /* BMSR is latching - it returns "link down" if the link has * been down at any point since the last read. To get a * real-time status, we therefore read the register twice and * use the result of the second read. */ - efab->op->mdio_read ( efab, MII_BMSR ); - status = efab->op->mdio_read ( efab, MII_BMSR ); + (void) falcon_mdio_read ( efab, 0, MII_BMSR ); + status = falcon_mdio_read ( efab, 0, MII_BMSR ); /* Read the PHY-specific Status Register. This is * non-latching, so we need do only a single read. */ - phy_status = efab->op->mdio_read ( efab, GMII_PSSR ); + phy_status = falcon_mdio_read ( efab, 0, GMII_PSSR ); return ( ( status & BMSR_LSTATUS ) && ( phy_status & PSSR_LSTATUS ) ); } /************************************************************************** * - * Alaska PHY + * MDIO routines * ************************************************************************** */ -/** - * Initialise Alaska PHY - * - */ -static void alaska_init ( struct efab_nic *efab ) { - unsigned int advertised, lpa; - - /* Read link up status */ - efab->link_up = gmii_link_ok ( efab ); - - if ( ! efab->link_up ) - return; - - /* Determine link options from PHY. */ - advertised = gmii_autoneg_advertised ( efab ); - lpa = gmii_autoneg_lpa ( efab ); - efab->link_options = gmii_nway_result ( advertised & lpa ); - - /* print out the link speed */ - EFAB_LOG ( "%dMbps %s-duplex (%04x,%04x)\n", - ( efab->link_options & LPA_10000 ? 1000 : - ( efab->link_options & LPA_1000 ? 1000 : - ( efab->link_options & LPA_100 ? 100 : 10 ) ) ), - ( efab->link_options & LPA_DUPLEX ? "full" : "half" ), - advertised, lpa ); +/* Numbering of the MDIO Manageable Devices (MMDs) */ +/* Physical Medium Attachment/ Physical Medium Dependent sublayer */ +#define MDIO_MMD_PMAPMD (1) +/* WAN Interface Sublayer */ +#define MDIO_MMD_WIS (2) +/* Physical Coding Sublayer */ +#define MDIO_MMD_PCS (3) +/* PHY Extender Sublayer */ +#define MDIO_MMD_PHYXS (4) +/* Extender Sublayer */ +#define MDIO_MMD_DTEXS (5) +/* Transmission convergence */ +#define MDIO_MMD_TC (6) +/* Auto negotiation */ +#define MDIO_MMD_AN (7) + +/* Generic register locations */ +#define MDIO_MMDREG_CTRL1 (0) +#define MDIO_MMDREG_STAT1 (1) +#define MDIO_MMDREG_DEVS0 (5) +#define MDIO_MMDREG_STAT2 (8) + +/* Bits in MMDREG_CTRL1 */ +/* Reset */ +#define MDIO_MMDREG_CTRL1_RESET_LBN (15) +#define MDIO_MMDREG_CTRL1_RESET_WIDTH (1) + +/* Bits in MMDREG_STAT1 */ +#define MDIO_MMDREG_STAT1_FAULT_LBN (7) +#define MDIO_MMDREG_STAT1_FAULT_WIDTH (1) + +/* Link state */ +#define MDIO_MMDREG_STAT1_LINK_LBN (2) +#define MDIO_MMDREG_STAT1_LINK_WIDTH (1) + +/* Bits in MMDREG_DEVS0. */ +#define DEV_PRESENT_BIT(_b) (1 << _b) + +#define MDIO_MMDREG_DEVS0_DTEXS DEV_PRESENT_BIT(MDIO_MMD_DTEXS) +#define MDIO_MMDREG_DEVS0_PHYXS DEV_PRESENT_BIT(MDIO_MMD_PHYXS) +#define MDIO_MMDREG_DEVS0_PCS DEV_PRESENT_BIT(MDIO_MMD_PCS) +#define MDIO_MMDREG_DEVS0_WIS DEV_PRESENT_BIT(MDIO_MMD_WIS) +#define MDIO_MMDREG_DEVS0_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD) + +#define MDIO_MMDREG_DEVS0_AN DEV_PRESENT_BIT(MDIO_MMD_AN) + +/* Bits in MMDREG_STAT2 */ +#define MDIO_MMDREG_STAT2_PRESENT_VAL (2) +#define MDIO_MMDREG_STAT2_PRESENT_LBN (14) +#define MDIO_MMDREG_STAT2_PRESENT_WIDTH (2) + +/* PHY XGXS lane state */ +#define MDIO_PHYXS_LANE_STATE (0x18) +#define MDIO_PHYXS_LANE_ALIGNED_LBN (12) +#define MDIO_PHYXS_LANE_SYNC0_LBN (0) +#define MDIO_PHYXS_LANE_SYNC1_LBN (1) +#define MDIO_PHYXS_LANE_SYNC2_LBN (2) +#define MDIO_PHYXS_LANE_SYNC3_LBN (3) + +/* This ought to be ridiculous overkill. We expect it to fail rarely */ +#define MDIO45_RESET_TRIES 100 +#define MDIO45_RESET_SPINTIME 10 + +static int +mdio_clause45_wait_reset_mmds ( struct efab_nic* efab ) +{ + int tries = MDIO45_RESET_TRIES; + int in_reset; + + while(tries) { + int mask = efab->phy_op->mmds; + int mmd = 0; + in_reset = 0; + while(mask) { + if (mask & 1) { + int stat = falcon_mdio_read ( efab, mmd, + MDIO_MMDREG_CTRL1 ); + if (stat < 0) { + EFAB_ERR("Failed to read status of MMD %d\n", + mmd ); + in_reset = 1; + break; + } + if (stat & (1 << MDIO_MMDREG_CTRL1_RESET_LBN)) + in_reset |= (1 << mmd); + } + mask = mask >> 1; + mmd++; + } + if (!in_reset) + break; + tries--; + mdelay ( MDIO45_RESET_SPINTIME ); + } + if (in_reset != 0) { + EFAB_ERR("Not all MMDs came out of reset in time. MMDs " + "still in reset: %x\n", in_reset); + return -ETIMEDOUT; + } + return 0; } +static int +mdio_clause45_reset_mmd ( struct efab_nic *efab, int mmd ) +{ + int tries = MDIO45_RESET_TRIES; + int ctrl; -/************************************************************************** - * - * Mentor MAC - * - ************************************************************************** - */ - -/* GMAC configuration register 1 */ -#define GM_CFG1_REG_MAC 0x00 -#define GM_SW_RST_LBN 31 -#define GM_SW_RST_WIDTH 1 -#define GM_RX_FC_EN_LBN 5 -#define GM_RX_FC_EN_WIDTH 1 -#define GM_TX_FC_EN_LBN 4 -#define GM_TX_FC_EN_WIDTH 1 -#define GM_RX_EN_LBN 2 -#define GM_RX_EN_WIDTH 1 -#define GM_TX_EN_LBN 0 -#define GM_TX_EN_WIDTH 1 - -/* GMAC configuration register 2 */ -#define GM_CFG2_REG_MAC 0x01 -#define GM_PAMBL_LEN_LBN 12 -#define GM_PAMBL_LEN_WIDTH 4 -#define GM_IF_MODE_LBN 8 -#define GM_IF_MODE_WIDTH 2 -#define GM_PAD_CRC_EN_LBN 2 -#define GM_PAD_CRC_EN_WIDTH 1 -#define GM_FD_LBN 0 -#define GM_FD_WIDTH 1 - -/* GMAC maximum frame length register */ -#define GM_MAX_FLEN_REG_MAC 0x04 -#define GM_MAX_FLEN_LBN 0 -#define GM_MAX_FLEN_WIDTH 16 + falcon_mdio_write ( efab, mmd, MDIO_MMDREG_CTRL1, + ( 1 << MDIO_MMDREG_CTRL1_RESET_LBN ) ); -/* GMAC MII management configuration register */ -#define GM_MII_MGMT_CFG_REG_MAC 0x08 -#define GM_MGMT_CLK_SEL_LBN 0 -#define GM_MGMT_CLK_SEL_WIDTH 3 + /* Wait for the reset bit to clear. */ + do { + mdelay ( MDIO45_RESET_SPINTIME ); -/* GMAC MII management command register */ -#define GM_MII_MGMT_CMD_REG_MAC 0x09 -#define GM_MGMT_SCAN_CYC_LBN 1 -#define GM_MGMT_SCAN_CYC_WIDTH 1 -#define GM_MGMT_RD_CYC_LBN 0 -#define GM_MGMT_RD_CYC_WIDTH 1 + ctrl = falcon_mdio_read ( efab, mmd, MDIO_MMDREG_CTRL1 ); + if ( ~ctrl & ( 1 << MDIO_MMDREG_CTRL1_RESET_LBN ) ) + return 0; + } while ( --tries ); -/* GMAC MII management address register */ -#define GM_MII_MGMT_ADR_REG_MAC 0x0a -#define GM_MGMT_PHY_ADDR_LBN 8 -#define GM_MGMT_PHY_ADDR_WIDTH 5 -#define GM_MGMT_REG_ADDR_LBN 0 -#define GM_MGMT_REG_ADDR_WIDTH 5 + EFAB_ERR ( "Failed to reset mmd %d\n", mmd ); -/* GMAC MII management control register */ -#define GM_MII_MGMT_CTL_REG_MAC 0x0b -#define GM_MGMT_CTL_LBN 0 -#define GM_MGMT_CTL_WIDTH 16 + return -ETIMEDOUT; +} -/* GMAC MII management status register */ -#define GM_MII_MGMT_STAT_REG_MAC 0x0c -#define GM_MGMT_STAT_LBN 0 -#define GM_MGMT_STAT_WIDTH 16 +static int +mdio_clause45_links_ok(struct efab_nic *efab ) +{ + int status, good; + int ok = 1; + int mmd = 0; + int mmd_mask = efab->phy_op->mmds; + + while (mmd_mask) { + if (mmd_mask & 1) { + /* Double reads because link state is latched, and a + * read moves the current state into the register */ + status = falcon_mdio_read ( efab, mmd, + MDIO_MMDREG_STAT1 ); + status = falcon_mdio_read ( efab, mmd, + MDIO_MMDREG_STAT1 ); + + good = status & (1 << MDIO_MMDREG_STAT1_LINK_LBN); + ok = ok && good; + } + mmd_mask = (mmd_mask >> 1); + mmd++; + } + return ok; +} -/* GMAC MII management indicators register */ -#define GM_MII_MGMT_IND_REG_MAC 0x0d -#define GM_MGMT_BUSY_LBN 0 -#define GM_MGMT_BUSY_WIDTH 1 +static int +mdio_clause45_check_mmds ( struct efab_nic *efab ) +{ + int mmd = 0; + int devices = falcon_mdio_read ( efab, MDIO_MMD_PHYXS, + MDIO_MMDREG_DEVS0 ); + int mmd_mask = efab->phy_op->mmds; + + /* Check all the expected MMDs are present */ + if ( devices < 0 ) { + EFAB_ERR ( "Failed to read devices present\n" ); + return -EIO; + } + if ( ( devices & mmd_mask ) != mmd_mask ) { + EFAB_ERR ( "required MMDs not present: got %x, wanted %x\n", + devices, mmd_mask ); + return -EIO; + } -/* GMAC station address register 1 */ -#define GM_ADR1_REG_MAC 0x10 -#define GM_HWADDR_5_LBN 24 -#define GM_HWADDR_5_WIDTH 8 -#define GM_HWADDR_4_LBN 16 -#define GM_HWADDR_4_WIDTH 8 -#define GM_HWADDR_3_LBN 8 -#define GM_HWADDR_3_WIDTH 8 -#define GM_HWADDR_2_LBN 0 -#define GM_HWADDR_2_WIDTH 8 + /* Check all required MMDs are responding and happy. */ + while ( mmd_mask ) { + if ( mmd_mask & 1 ) { + efab_dword_t reg; + int status; + reg.opaque = falcon_mdio_read ( efab, mmd, + MDIO_MMDREG_STAT2 ); + status = EFAB_DWORD_FIELD ( reg, + MDIO_MMDREG_STAT2_PRESENT ); + if ( status != MDIO_MMDREG_STAT2_PRESENT_VAL ) { -/* GMAC station address register 2 */ -#define GM_ADR2_REG_MAC 0x11 -#define GM_HWADDR_1_LBN 24 -#define GM_HWADDR_1_WIDTH 8 -#define GM_HWADDR_0_LBN 16 -#define GM_HWADDR_0_WIDTH 8 -/* GMAC FIFO configuration register 0 */ -#define GMF_CFG0_REG_MAC 0x12 -#define GMF_FTFENREQ_LBN 12 -#define GMF_FTFENREQ_WIDTH 1 -#define GMF_STFENREQ_LBN 11 -#define GMF_STFENREQ_WIDTH 1 -#define GMF_FRFENREQ_LBN 10 -#define GMF_FRFENREQ_WIDTH 1 -#define GMF_SRFENREQ_LBN 9 -#define GMF_SRFENREQ_WIDTH 1 -#define GMF_WTMENREQ_LBN 8 -#define GMF_WTMENREQ_WIDTH 1 + return -EIO; + } + } + mmd_mask >>= 1; + mmd++; + } -/* GMAC FIFO configuration register 1 */ -#define GMF_CFG1_REG_MAC 0x13 -#define GMF_CFGFRTH_LBN 16 -#define GMF_CFGFRTH_WIDTH 5 -#define GMF_CFGXOFFRTX_LBN 0 -#define GMF_CFGXOFFRTX_WIDTH 16 + return 0; +} -/* GMAC FIFO configuration register 2 */ -#define GMF_CFG2_REG_MAC 0x14 -#define GMF_CFGHWM_LBN 16 -#define GMF_CFGHWM_WIDTH 6 -#define GMF_CFGLWM_LBN 0 -#define GMF_CFGLWM_WIDTH 6 +/* I/O BAR address register */ +#define FCN_IOM_IND_ADR_REG 0x0 -/* GMAC FIFO configuration register 3 */ -#define GMF_CFG3_REG_MAC 0x15 -#define GMF_CFGHWMFT_LBN 16 -#define GMF_CFGHWMFT_WIDTH 6 -#define GMF_CFGFTTH_LBN 0 -#define GMF_CFGFTTH_WIDTH 6 +/* I/O BAR data register */ +#define FCN_IOM_IND_DAT_REG 0x4 -/* GMAC FIFO configuration register 4 */ -#define GMF_CFG4_REG_MAC 0x16 -#define GMF_HSTFLTRFRM_PAUSE_LBN 12 -#define GMF_HSTFLTRFRM_PAUSE_WIDTH 12 +/* Address region register */ +#define FCN_ADR_REGION_REG_KER 0x00 +#define FCN_ADR_REGION0_LBN 0 +#define FCN_ADR_REGION0_WIDTH 18 +#define FCN_ADR_REGION1_LBN 32 +#define FCN_ADR_REGION1_WIDTH 18 +#define FCN_ADR_REGION2_LBN 64 +#define FCN_ADR_REGION2_WIDTH 18 +#define FCN_ADR_REGION3_LBN 96 +#define FCN_ADR_REGION3_WIDTH 18 -/* GMAC FIFO configuration register 5 */ -#define GMF_CFG5_REG_MAC 0x17 -#define GMF_CFGHDPLX_LBN 22 -#define GMF_CFGHDPLX_WIDTH 1 -#define GMF_CFGBYTMODE_LBN 19 -#define GMF_CFGBYTMODE_WIDTH 1 -#define GMF_HSTDRPLT64_LBN 18 -#define GMF_HSTDRPLT64_WIDTH 1 -#define GMF_HSTFLTRFRMDC_PAUSE_LBN 12 -#define GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1 +/* Interrupt enable register */ +#define FCN_INT_EN_REG_KER 0x0010 +#define FCN_MEM_PERR_INT_EN_KER_LBN 5 +#define FCN_MEM_PERR_INT_EN_KER_WIDTH 1 +#define FCN_KER_INT_CHAR_LBN 4 +#define FCN_KER_INT_CHAR_WIDTH 1 +#define FCN_KER_INT_KER_LBN 3 +#define FCN_KER_INT_KER_WIDTH 1 +#define FCN_ILL_ADR_ERR_INT_EN_KER_LBN 2 +#define FCN_ILL_ADR_ERR_INT_EN_KER_WIDTH 1 +#define FCN_SRM_PERR_INT_EN_KER_LBN 1 +#define FCN_SRM_PERR_INT_EN_KER_WIDTH 1 +#define FCN_DRV_INT_EN_KER_LBN 0 +#define FCN_DRV_INT_EN_KER_WIDTH 1 -struct efab_mentormac_parameters { - int gmf_cfgfrth; - int gmf_cfgftth; - int gmf_cfghwmft; - int gmf_cfghwm; - int gmf_cfglwm; -}; +/* Interrupt status register */ +#define FCN_INT_ADR_REG_KER 0x0030 +#define FCN_INT_ADR_KER_LBN 0 +#define FCN_INT_ADR_KER_WIDTH EFAB_DMA_TYPE_WIDTH ( 64 ) -/** - * Reset Mentor MAC - * - */ -static void mentormac_reset ( struct efab_nic *efab ) { - efab_dword_t reg; - int save_port; +/* Interrupt status register (B0 only) */ +#define INT_ISR0_B0 0x90 +#define INT_ISR1_B0 0xA0 - /* Take into reset */ - EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 1 ); - efab->mac_op->mac_writel ( efab, ®, GM_CFG1_REG_MAC ); - udelay ( 1000 ); +/* Interrupt acknowledge register (A0/A1 only) */ +#define FCN_INT_ACK_KER_REG_A1 0x0050 +#define INT_ACK_DUMMY_DATA_LBN 0 +#define INT_ACK_DUMMY_DATA_WIDTH 32 - /* Take out of reset */ - EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 0 ); - efab->mac_op->mac_writel ( efab, ®, GM_CFG1_REG_MAC ); - udelay ( 1000 ); +/* Interrupt acknowledge work-around register (A0/A1 only )*/ +#define WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 0x0070 - /* Mentor MAC connects both PHYs to MAC 0 */ - save_port = efab->port; - efab->port = 0; - /* Configure GMII interface so PHY is accessible. Note that - * GMII interface is connected only to port 0, and that on - * Falcon this is a no-op. - */ - EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_CLK_SEL, 0x4 ); - efab->mac_op->mac_writel ( efab, ®, GM_MII_MGMT_CFG_REG_MAC ); - udelay ( 10 ); - efab->port = save_port; -} +/* Hardware initialisation register */ +#define FCN_HW_INIT_REG_KER 0x00c0 +#define FCN_BCSR_TARGET_MASK_LBN 101 +#define FCN_BCSR_TARGET_MASK_WIDTH 4 -/** - * Initialise Mentor MAC - * - */ -static void mentormac_init ( struct efab_nic *efab, - struct efab_mentormac_parameters *params ) { - int pause, if_mode, full_duplex, bytemode, half_duplex; - efab_dword_t reg; +/* SPI host command register */ +#define FCN_EE_SPI_HCMD_REG 0x0100 +#define FCN_EE_SPI_HCMD_CMD_EN_LBN 31 +#define FCN_EE_SPI_HCMD_CMD_EN_WIDTH 1 +#define FCN_EE_WR_TIMER_ACTIVE_LBN 28 +#define FCN_EE_WR_TIMER_ACTIVE_WIDTH 1 +#define FCN_EE_SPI_HCMD_SF_SEL_LBN 24 +#define FCN_EE_SPI_HCMD_SF_SEL_WIDTH 1 +#define FCN_EE_SPI_EEPROM 0 +#define FCN_EE_SPI_FLASH 1 +#define FCN_EE_SPI_HCMD_DABCNT_LBN 16 +#define FCN_EE_SPI_HCMD_DABCNT_WIDTH 5 +#define FCN_EE_SPI_HCMD_READ_LBN 15 +#define FCN_EE_SPI_HCMD_READ_WIDTH 1 +#define FCN_EE_SPI_READ 1 +#define FCN_EE_SPI_WRITE 0 +#define FCN_EE_SPI_HCMD_DUBCNT_LBN 12 +#define FCN_EE_SPI_HCMD_DUBCNT_WIDTH 2 +#define FCN_EE_SPI_HCMD_ADBCNT_LBN 8 +#define FCN_EE_SPI_HCMD_ADBCNT_WIDTH 2 +#define FCN_EE_SPI_HCMD_ENC_LBN 0 +#define FCN_EE_SPI_HCMD_ENC_WIDTH 8 - /* Configuration register 1 */ - pause = ( efab->link_options & LPA_PAUSE ) ? 1 : 0; - if ( ! ( efab->link_options & LPA_DUPLEX ) ) { - /* Half-duplex operation requires TX flow control */ - pause = 1; - } - EFAB_POPULATE_DWORD_4 ( reg, - GM_TX_EN, 1, - GM_TX_FC_EN, pause, - GM_RX_EN, 1, - GM_RX_FC_EN, 1 ); - efab->mac_op->mac_writel ( efab, ®, GM_CFG1_REG_MAC ); - udelay ( 10 ); +/* SPI host address register */ +#define FCN_EE_SPI_HADR_REG 0x0110 +#define FCN_EE_SPI_HADR_DUBYTE_LBN 24 +#define FCN_EE_SPI_HADR_DUBYTE_WIDTH 8 +#define FCN_EE_SPI_HADR_ADR_LBN 0 +#define FCN_EE_SPI_HADR_ADR_WIDTH 24 - /* Configuration register 2 */ - if_mode = ( efab->link_options & LPA_1000 ) ? 2 : 1; - full_duplex = ( efab->link_options & LPA_DUPLEX ) ? 1 : 0; - EFAB_POPULATE_DWORD_4 ( reg, - GM_IF_MODE, if_mode, - GM_PAD_CRC_EN, 1, - GM_FD, full_duplex, - GM_PAMBL_LEN, 0x7 /* ? */ ); - efab->mac_op->mac_writel ( efab, ®, GM_CFG2_REG_MAC ); - udelay ( 10 ); +/* SPI host data register */ +#define FCN_EE_SPI_HDATA_REG 0x0120 +#define FCN_EE_SPI_HDATA3_LBN 96 +#define FCN_EE_SPI_HDATA3_WIDTH 32 +#define FCN_EE_SPI_HDATA2_LBN 64 +#define FCN_EE_SPI_HDATA2_WIDTH 32 +#define FCN_EE_SPI_HDATA1_LBN 32 +#define FCN_EE_SPI_HDATA1_WIDTH 32 +#define FCN_EE_SPI_HDATA0_LBN 0 +#define FCN_EE_SPI_HDATA0_WIDTH 32 - /* Max frame len register */ - EFAB_POPULATE_DWORD_1 ( reg, GM_MAX_FLEN, ETH_FRAME_LEN + 4 /* FCS */); - efab->mac_op->mac_writel ( efab, ®, GM_MAX_FLEN_REG_MAC ); - udelay ( 10 ); +/* VPD Config 0 Register register */ +#define FCN_EE_VPD_CFG_REG 0x0140 +#define FCN_EE_VPD_EN_LBN 0 +#define FCN_EE_VPD_EN_WIDTH 1 +#define FCN_EE_VPD_EN_AD9_MODE_LBN 1 +#define FCN_EE_VPD_EN_AD9_MODE_WIDTH 1 +#define FCN_EE_EE_CLOCK_DIV_LBN 112 +#define FCN_EE_EE_CLOCK_DIV_WIDTH 7 +#define FCN_EE_SF_CLOCK_DIV_LBN 120 +#define FCN_EE_SF_CLOCK_DIV_WIDTH 7 - /* FIFO configuration register 0 */ - EFAB_POPULATE_DWORD_5 ( reg, - GMF_FTFENREQ, 1, - GMF_STFENREQ, 1, - GMF_FRFENREQ, 1, - GMF_SRFENREQ, 1, - GMF_WTMENREQ, 1 ); - efab->mac_op->mac_writel ( efab, ®, GMF_CFG0_REG_MAC ); - udelay ( 10 ); - /* FIFO configuration register 1 */ - EFAB_POPULATE_DWORD_2 ( reg, - GMF_CFGFRTH, params->gmf_cfgfrth, - GMF_CFGXOFFRTX, 0xffff ); - efab->mac_op->mac_writel ( efab, ®, GMF_CFG1_REG_MAC ); - udelay ( 10 ); +/* NIC status register */ +#define FCN_NIC_STAT_REG 0x0200 +#define FCN_ONCHIP_SRAM_LBN 16 +#define FCN_ONCHIP_SRAM_WIDTH 1 +#define FCN_SF_PRST_LBN 9 +#define FCN_SF_PRST_WIDTH 1 +#define FCN_EE_PRST_LBN 8 +#define FCN_EE_PRST_WIDTH 1 +#define FCN_EE_STRAP_LBN 7 +#define FCN_EE_STRAP_WIDTH 1 +#define FCN_PCI_PCIX_MODE_LBN 4 +#define FCN_PCI_PCIX_MODE_WIDTH 3 +#define FCN_PCI_PCIX_MODE_PCI33_DECODE 0 +#define FCN_PCI_PCIX_MODE_PCI66_DECODE 1 +#define FCN_PCI_PCIX_MODE_PCIX66_DECODE 5 +#define FCN_PCI_PCIX_MODE_PCIX100_DECODE 6 +#define FCN_PCI_PCIX_MODE_PCIX133_DECODE 7 +#define FCN_STRAP_ISCSI_EN_LBN 3 +#define FCN_STRAP_ISCSI_EN_WIDTH 1 +#define FCN_STRAP_PINS_LBN 0 +#define FCN_STRAP_PINS_WIDTH 3 +#define FCN_STRAP_10G_LBN 2 +#define FCN_STRAP_10G_WIDTH 1 +#define FCN_STRAP_DUAL_PORT_LBN 1 +#define FCN_STRAP_DUAL_PORT_WIDTH 1 +#define FCN_STRAP_PCIE_LBN 0 +#define FCN_STRAP_PCIE_WIDTH 1 + +/* Falcon revisions */ +#define FALCON_REV_A0 0 +#define FALCON_REV_A1 1 +#define FALCON_REV_B0 2 - /* FIFO configuration register 2 */ - EFAB_POPULATE_DWORD_2 ( reg, - GMF_CFGHWM, params->gmf_cfghwm, - GMF_CFGLWM, params->gmf_cfglwm ); - efab->mac_op->mac_writel ( efab, ®, GMF_CFG2_REG_MAC ); - udelay ( 10 ); +/* GPIO control register */ +#define FCN_GPIO_CTL_REG_KER 0x0210 +#define FCN_GPIO_CTL_REG_KER 0x0210 - /* FIFO configuration register 3 */ - EFAB_POPULATE_DWORD_2 ( reg, - GMF_CFGHWMFT, params->gmf_cfghwmft, - GMF_CFGFTTH, params->gmf_cfgftth ); - efab->mac_op->mac_writel ( efab, ®, GMF_CFG3_REG_MAC ); - udelay ( 10 ); +#define FCN_GPIO3_OEN_LBN 27 +#define FCN_GPIO3_OEN_WIDTH 1 +#define FCN_GPIO2_OEN_LBN 26 +#define FCN_GPIO2_OEN_WIDTH 1 +#define FCN_GPIO1_OEN_LBN 25 +#define FCN_GPIO1_OEN_WIDTH 1 +#define FCN_GPIO0_OEN_LBN 24 +#define FCN_GPIO0_OEN_WIDTH 1 + +#define FCN_GPIO3_OUT_LBN 19 +#define FCN_GPIO3_OUT_WIDTH 1 +#define FCN_GPIO2_OUT_LBN 18 +#define FCN_GPIO2_OUT_WIDTH 1 +#define FCN_GPIO1_OUT_LBN 17 +#define FCN_GPIO1_OUT_WIDTH 1 +#define FCN_GPIO0_OUT_LBN 16 +#define FCN_GPIO0_OUT_WIDTH 1 + +#define FCN_GPIO3_IN_LBN 11 +#define FCN_GPIO3_IN_WIDTH 1 +#define FCN_GPIO2_IN_LBN 10 +#define FCN_GPIO2_IN_WIDTH 1 +#define FCN_GPIO1_IN_LBN 9 +#define FCN_GPIO1_IN_WIDTH 1 +#define FCN_GPIO0_IN_LBN 8 +#define FCN_GPIO0_IN_WIDTH 1 - /* FIFO configuration register 4 */ - EFAB_POPULATE_DWORD_1 ( reg, GMF_HSTFLTRFRM_PAUSE, 1 ); - efab->mac_op->mac_writel ( efab, ®, GMF_CFG4_REG_MAC ); - udelay ( 10 ); - - /* FIFO configuration register 5 */ - bytemode = ( efab->link_options & LPA_1000 ) ? 1 : 0; - half_duplex = ( efab->link_options & LPA_DUPLEX ) ? 0 : 1; - efab->mac_op->mac_readl ( efab, ®, GMF_CFG5_REG_MAC ); - EFAB_SET_DWORD_FIELD ( reg, GMF_CFGBYTMODE, bytemode ); - EFAB_SET_DWORD_FIELD ( reg, GMF_CFGHDPLX, half_duplex ); - EFAB_SET_DWORD_FIELD ( reg, GMF_HSTDRPLT64, half_duplex ); - EFAB_SET_DWORD_FIELD ( reg, GMF_HSTFLTRFRMDC_PAUSE, 0 ); - efab->mac_op->mac_writel ( efab, ®, GMF_CFG5_REG_MAC ); - udelay ( 10 ); - - /* MAC address */ - EFAB_POPULATE_DWORD_4 ( reg, - GM_HWADDR_5, efab->mac_addr[5], - GM_HWADDR_4, efab->mac_addr[4], - GM_HWADDR_3, efab->mac_addr[3], - GM_HWADDR_2, efab->mac_addr[2] ); - efab->mac_op->mac_writel ( efab, ®, GM_ADR1_REG_MAC ); - udelay ( 10 ); - EFAB_POPULATE_DWORD_2 ( reg, - GM_HWADDR_1, efab->mac_addr[1], - GM_HWADDR_0, efab->mac_addr[0] ); - efab->mac_op->mac_writel ( efab, ®, GM_ADR2_REG_MAC ); - udelay ( 10 ); -} +#define FCN_FLASH_PRESENT_LBN 7 +#define FCN_FLASH_PRESENT_WIDTH 1 +#define FCN_EEPROM_PRESENT_LBN 6 +#define FCN_EEPROM_PRESENT_WIDTH 1 +#define FCN_BOOTED_USING_NVDEVICE_LBN 3 +#define FCN_BOOTED_USING_NVDEVICE_WIDTH 1 -/** - * Wait for GMII access to complete - * - */ -static int mentormac_gmii_wait ( struct efab_nic *efab ) { - int count; - efab_dword_t indicator; +/* Defines for extra non-volatile storage */ +#define FCN_NV_MAGIC_NUMBER 0xFA1C - for ( count = 0 ; count < 1000 ; count++ ) { - udelay ( 10 ); - efab->mac_op->mac_readl ( efab, &indicator, - GM_MII_MGMT_IND_REG_MAC ); - if ( EFAB_DWORD_FIELD ( indicator, GM_MGMT_BUSY ) == 0 ) - return 1; - } - EFAB_ERR ( "Timed out waiting for GMII\n" ); - return 0; -} +/* Global control register */ +#define FCN_GLB_CTL_REG_KER 0x0220 +#define FCN_EXT_PHY_RST_CTL_LBN 63 +#define FCN_EXT_PHY_RST_CTL_WIDTH 1 +#define FCN_PCIE_SD_RST_CTL_LBN 61 +#define FCN_PCIE_SD_RST_CTL_WIDTH 1 +#define FCN_PCIE_STCK_RST_CTL_LBN 59 +#define FCN_PCIE_STCK_RST_CTL_WIDTH 1 +#define FCN_PCIE_NSTCK_RST_CTL_LBN 58 +#define FCN_PCIE_NSTCK_RST_CTL_WIDTH 1 +#define FCN_PCIE_CORE_RST_CTL_LBN 57 +#define FCN_PCIE_CORE_RST_CTL_WIDTH 1 +#define FCN_EE_RST_CTL_LBN 49 +#define FCN_EE_RST_CTL_WIDTH 1 +#define FCN_RST_EXT_PHY_LBN 31 +#define FCN_RST_EXT_PHY_WIDTH 1 +#define FCN_EXT_PHY_RST_DUR_LBN 1 +#define FCN_EXT_PHY_RST_DUR_WIDTH 3 +#define FCN_SWRST_LBN 0 +#define FCN_SWRST_WIDTH 1 +#define INCLUDE_IN_RESET 0 +#define EXCLUDE_FROM_RESET 1 -/** - * Write a GMII register - * - */ -static void mentormac_mdio_write ( struct efab_nic *efab, int phy_id, - int location, int value ) { - efab_dword_t reg; - int save_port; +/* FPGA build version */ +#define FCN_ALTERA_BUILD_REG_KER 0x0300 +#define FCN_VER_MAJOR_LBN 24 +#define FCN_VER_MAJOR_WIDTH 8 +#define FCN_VER_MINOR_LBN 16 +#define FCN_VER_MINOR_WIDTH 8 +#define FCN_VER_BUILD_LBN 0 +#define FCN_VER_BUILD_WIDTH 16 +#define FCN_VER_ALL_LBN 0 +#define FCN_VER_ALL_WIDTH 32 + +/* Spare EEPROM bits register (flash 0x390) */ +#define FCN_SPARE_REG_KER 0x310 +#define FCN_MEM_PERR_EN_TX_DATA_LBN 72 +#define FCN_MEM_PERR_EN_TX_DATA_WIDTH 2 - EFAB_TRACE ( "Writing GMII %d register %02x with %04x\n", phy_id, - location, value ); +/* Timer table for kernel access */ +#define FCN_TIMER_CMD_REG_KER 0x420 +#define FCN_TIMER_MODE_LBN 12 +#define FCN_TIMER_MODE_WIDTH 2 +#define FCN_TIMER_MODE_DIS 0 +#define FCN_TIMER_MODE_INT_HLDOFF 1 +#define FCN_TIMER_VAL_LBN 0 +#define FCN_TIMER_VAL_WIDTH 12 - /* Mentor MAC connects both PHYs to MAC 0 */ - save_port = efab->port; - efab->port = 0; +/* Receive configuration register */ +#define FCN_RX_CFG_REG_KER 0x800 +#define FCN_RX_XOFF_EN_LBN 0 +#define FCN_RX_XOFF_EN_WIDTH 1 - /* Check MII not currently being accessed */ - if ( ! mentormac_gmii_wait ( efab ) ) - goto out; +/* SRAM receive descriptor cache configuration register */ +#define FCN_SRM_RX_DC_CFG_REG_KER 0x610 +#define FCN_SRM_RX_DC_BASE_ADR_LBN 0 +#define FCN_SRM_RX_DC_BASE_ADR_WIDTH 21 - /* Write the address register */ - EFAB_POPULATE_DWORD_2 ( reg, - GM_MGMT_PHY_ADDR, phy_id, - GM_MGMT_REG_ADDR, location ); - efab->mac_op->mac_writel ( efab, ®, GM_MII_MGMT_ADR_REG_MAC ); - udelay ( 10 ); +/* SRAM transmit descriptor cache configuration register */ +#define FCN_SRM_TX_DC_CFG_REG_KER 0x620 +#define FCN_SRM_TX_DC_BASE_ADR_LBN 0 +#define FCN_SRM_TX_DC_BASE_ADR_WIDTH 21 - /* Write data */ - EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_CTL, value ); - efab->mac_op->mac_writel ( efab, ®, GM_MII_MGMT_CTL_REG_MAC ); +/* SRAM configuration register */ +#define FCN_SRM_CFG_REG_KER 0x630 +#define FCN_SRAM_OOB_ADR_INTEN_LBN 5 +#define FCN_SRAM_OOB_ADR_INTEN_WIDTH 1 +#define FCN_SRAM_OOB_BUF_INTEN_LBN 4 +#define FCN_SRAM_OOB_BUF_INTEN_WIDTH 1 +#define FCN_SRAM_OOB_BT_INIT_EN_LBN 3 +#define FCN_SRAM_OOB_BT_INIT_EN_WIDTH 1 +#define FCN_SRM_NUM_BANK_LBN 2 +#define FCN_SRM_NUM_BANK_WIDTH 1 +#define FCN_SRM_BANK_SIZE_LBN 0 +#define FCN_SRM_BANK_SIZE_WIDTH 2 +#define FCN_SRM_NUM_BANKS_AND_BANK_SIZE_LBN 0 +#define FCN_SRM_NUM_BANKS_AND_BANK_SIZE_WIDTH 3 - /* Wait for data to be written */ - mentormac_gmii_wait ( efab ); +#define FCN_RX_CFG_REG_KER 0x800 +#define FCN_RX_INGR_EN_B0_LBN 47 +#define FCN_RX_INGR_EN_B0_WIDTH 1 +#define FCN_RX_USR_BUF_SIZE_B0_LBN 19 +#define FCN_RX_USR_BUF_SIZE_B0_WIDTH 9 +#define FCN_RX_XON_MAC_TH_B0_LBN 10 +#define FCN_RX_XON_MAC_TH_B0_WIDTH 9 +#define FCN_RX_XOFF_MAC_TH_B0_LBN 1 +#define FCN_RX_XOFF_MAC_TH_B0_WIDTH 9 +#define FCN_RX_XOFF_MAC_EN_B0_LBN 0 +#define FCN_RX_XOFF_MAC_EN_B0_WIDTH 1 +#define FCN_RX_USR_BUF_SIZE_A1_LBN 11 +#define FCN_RX_USR_BUF_SIZE_A1_WIDTH 9 +#define FCN_RX_XON_MAC_TH_A1_LBN 6 +#define FCN_RX_XON_MAC_TH_A1_WIDTH 5 +#define FCN_RX_XOFF_MAC_TH_A1_LBN 1 +#define FCN_RX_XOFF_MAC_TH_A1_WIDTH 5 +#define FCN_RX_XOFF_MAC_EN_A1_LBN 0 +#define FCN_RX_XOFF_MAC_EN_A1_WIDTH 1 + +#define FCN_RX_USR_BUF_SIZE_A1_LBN 11 +#define FCN_RX_USR_BUF_SIZE_A1_WIDTH 9 +#define FCN_RX_XOFF_MAC_EN_A1_LBN 0 +#define FCN_RX_XOFF_MAC_EN_A1_WIDTH 1 - out: - /* Restore efab->port */ - efab->port = save_port; -} +/* Receive filter control register */ +#define FCN_RX_FILTER_CTL_REG_KER 0x810 +#define FCN_UDP_FULL_SRCH_LIMIT_LBN 32 +#define FCN_UDP_FULL_SRCH_LIMIT_WIDTH 8 +#define FCN_NUM_KER_LBN 24 +#define FCN_NUM_KER_WIDTH 2 +#define FCN_UDP_WILD_SRCH_LIMIT_LBN 16 +#define FCN_UDP_WILD_SRCH_LIMIT_WIDTH 8 +#define FCN_TCP_WILD_SRCH_LIMIT_LBN 8 +#define FCN_TCP_WILD_SRCH_LIMIT_WIDTH 8 +#define FCN_TCP_FULL_SRCH_LIMIT_LBN 0 +#define FCN_TCP_FULL_SRCH_LIMIT_WIDTH 8 + +/* RX queue flush register */ +#define FCN_RX_FLUSH_DESCQ_REG_KER 0x0820 +#define FCN_RX_FLUSH_DESCQ_CMD_LBN 24 +#define FCN_RX_FLUSH_DESCQ_CMD_WIDTH 1 +#define FCN_RX_FLUSH_DESCQ_LBN 0 +#define FCN_RX_FLUSH_DESCQ_WIDTH 12 -/** - * Read a GMII register - * - */ -static int mentormac_mdio_read ( struct efab_nic *efab, int phy_id, - int location ) { - efab_dword_t reg; - int value = 0xffff; - int save_port; +/* Receive descriptor update register */ +#define FCN_RX_DESC_UPD_REG_KER 0x0830 +#define FCN_RX_DESC_WPTR_LBN 96 +#define FCN_RX_DESC_WPTR_WIDTH 12 +#define FCN_RX_DESC_UPD_REG_KER_DWORD ( FCN_RX_DESC_UPD_REG_KER + 12 ) +#define FCN_RX_DESC_WPTR_DWORD_LBN 0 +#define FCN_RX_DESC_WPTR_DWORD_WIDTH 12 - /* Mentor MAC connects both PHYs to MAC 0 */ - save_port = efab->port; - efab->port = 0; +/* Receive descriptor cache configuration register */ +#define FCN_RX_DC_CFG_REG_KER 0x840 +#define FCN_RX_DC_SIZE_LBN 0 +#define FCN_RX_DC_SIZE_WIDTH 2 - /* Check MII not currently being accessed */ - if ( ! mentormac_gmii_wait ( efab ) ) - goto out; +#define FCN_RX_SELF_RST_REG_KER 0x890 +#define FCN_RX_ISCSI_DIS_LBN 17 +#define FCN_RX_ISCSI_DIS_WIDTH 1 +#define FCN_RX_NODESC_WAIT_DIS_LBN 9 +#define FCN_RX_NODESC_WAIT_DIS_WIDTH 1 +#define FCN_RX_RECOVERY_EN_LBN 8 +#define FCN_RX_RECOVERY_EN_WIDTH 1 + +/* TX queue flush register */ +#define FCN_TX_FLUSH_DESCQ_REG_KER 0x0a00 +#define FCN_TX_FLUSH_DESCQ_CMD_LBN 12 +#define FCN_TX_FLUSH_DESCQ_CMD_WIDTH 1 +#define FCN_TX_FLUSH_DESCQ_LBN 0 +#define FCN_TX_FLUSH_DESCQ_WIDTH 12 + +/* Transmit configuration register 2 */ +#define FCN_TX_CFG2_REG_KER 0xa80 +#define FCN_TX_DIS_NON_IP_EV_LBN 17 +#define FCN_TX_DIS_NON_IP_EV_WIDTH 1 - /* Write the address register */ - EFAB_POPULATE_DWORD_2 ( reg, - GM_MGMT_PHY_ADDR, phy_id, - GM_MGMT_REG_ADDR, location ); - efab->mac_op->mac_writel ( efab, ®, GM_MII_MGMT_ADR_REG_MAC ); - udelay ( 10 ); +/* Transmit descriptor update register */ +#define FCN_TX_DESC_UPD_REG_KER 0x0a10 +#define FCN_TX_DESC_WPTR_LBN 96 +#define FCN_TX_DESC_WPTR_WIDTH 12 +#define FCN_TX_DESC_UPD_REG_KER_DWORD ( FCN_TX_DESC_UPD_REG_KER + 12 ) +#define FCN_TX_DESC_WPTR_DWORD_LBN 0 +#define FCN_TX_DESC_WPTR_DWORD_WIDTH 12 - /* Request data to be read */ - EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_RD_CYC, 1 ); - efab->mac_op->mac_writel ( efab, ®, GM_MII_MGMT_CMD_REG_MAC ); +/* Transmit descriptor cache configuration register */ +#define FCN_TX_DC_CFG_REG_KER 0xa20 +#define FCN_TX_DC_SIZE_LBN 0 +#define FCN_TX_DC_SIZE_WIDTH 2 - /* Wait for data to be become available */ - if ( mentormac_gmii_wait ( efab ) ) { - /* Read data */ - efab->mac_op->mac_readl ( efab, ®, GM_MII_MGMT_STAT_REG_MAC ); - value = EFAB_DWORD_FIELD ( reg, GM_MGMT_STAT ); - EFAB_TRACE ( "Read from GMII %d register %02x, got %04x\n", - phy_id, location, value ); - } +/* PHY management transmit data register */ +#define FCN_MD_TXD_REG_KER 0xc00 +#define FCN_MD_TXD_LBN 0 +#define FCN_MD_TXD_WIDTH 16 - /* Signal completion */ - EFAB_ZERO_DWORD ( reg ); - efab->mac_op->mac_writel ( efab, ®, GM_MII_MGMT_CMD_REG_MAC ); - udelay ( 10 ); +/* PHY management receive data register */ +#define FCN_MD_RXD_REG_KER 0xc10 +#define FCN_MD_RXD_LBN 0 +#define FCN_MD_RXD_WIDTH 16 - out: - /* Restore efab->port */ - efab->port = save_port; +/* PHY management configuration & status register */ +#define FCN_MD_CS_REG_KER 0xc20 +#define FCN_MD_GC_LBN 4 +#define FCN_MD_GC_WIDTH 1 +#define FCN_MD_RIC_LBN 2 +#define FCN_MD_RIC_WIDTH 1 +#define FCN_MD_RDC_LBN 1 +#define FCN_MD_RDC_WIDTH 1 +#define FCN_MD_WRC_LBN 0 +#define FCN_MD_WRC_WIDTH 1 - return value; -} +/* PHY management PHY address register */ +#define FCN_MD_PHY_ADR_REG_KER 0xc30 +#define FCN_MD_PHY_ADR_LBN 0 +#define FCN_MD_PHY_ADR_WIDTH 16 -/************************************************************************** - * - * EF1002 routines - * - ************************************************************************** - */ +/* PHY management ID register */ +#define FCN_MD_ID_REG_KER 0xc40 +#define FCN_MD_PRT_ADR_LBN 11 +#define FCN_MD_PRT_ADR_WIDTH 5 +#define FCN_MD_DEV_ADR_LBN 6 +#define FCN_MD_DEV_ADR_WIDTH 5 -/** Control and General Status */ -#define EF1_CTR_GEN_STATUS0_REG 0x0 -#define EF1_MASTER_EVENTS_LBN 12 -#define EF1_MASTER_EVENTS_WIDTH 1 -#define EF1_TX_ENGINE_EN_LBN 19 -#define EF1_TX_ENGINE_EN_WIDTH 1 -#define EF1_RX_ENGINE_EN_LBN 18 -#define EF1_RX_ENGINE_EN_WIDTH 1 -#define EF1_TURBO2_LBN 17 -#define EF1_TURBO2_WIDTH 1 -#define EF1_TURBO1_LBN 16 -#define EF1_TURBO1_WIDTH 1 -#define EF1_TURBO3_LBN 14 -#define EF1_TURBO3_WIDTH 1 -#define EF1_LB_RESET_LBN 3 -#define EF1_LB_RESET_WIDTH 1 -#define EF1_MAC_RESET_LBN 2 -#define EF1_MAC_RESET_WIDTH 1 -#define EF1_CAM_ENABLE_LBN 1 -#define EF1_CAM_ENABLE_WIDTH 1 - -/** IRQ sources */ -#define EF1_IRQ_SRC_REG 0x0008 - -/** IRQ mask */ -#define EF1_IRQ_MASK_REG 0x000c -#define EF1_IRQ_PHY1_LBN 11 -#define EF1_IRQ_PHY1_WIDTH 1 -#define EF1_IRQ_PHY0_LBN 10 -#define EF1_IRQ_PHY0_WIDTH 1 -#define EF1_IRQ_SERR_LBN 7 -#define EF1_IRQ_SERR_WIDTH 1 -#define EF1_IRQ_EVQ_LBN 3 -#define EF1_IRQ_EVQ_WIDTH 1 - -/** Event generation */ -#define EF1_EVT3_REG 0x38 - -/** EEPROMaccess */ -#define EF1_EEPROM_REG 0x40 -#define EF1_EEPROM_SDA_LBN 31 -#define EF1_EEPROM_SDA_WIDTH 1 -#define EF1_EEPROM_SCL_LBN 30 -#define EF1_EEPROM_SCL_WIDTH 1 -#define EF1_JTAG_DISCONNECT_LBN 17 -#define EF1_JTAG_DISCONNECT_WIDTH 1 -#define EF1_EEPROM_LBN 0 -#define EF1_EEPROM_WIDTH 32 - -/** Control register 2 */ -#define EF1_CTL2_REG 0x4c -#define EF1_PLL_TRAP_LBN 31 -#define EF1_PLL_TRAP_WIDTH 1 -#define EF1_MEM_MAP_4MB_LBN 11 -#define EF1_MEM_MAP_4MB_WIDTH 1 -#define EF1_EV_INTR_CLR_WRITE_LBN 6 -#define EF1_EV_INTR_CLR_WRITE_WIDTH 1 -#define EF1_BURST_MERGE_LBN 5 -#define EF1_BURST_MERGE_WIDTH 1 -#define EF1_CLEAR_NULL_PAD_LBN 4 -#define EF1_CLEAR_NULL_PAD_WIDTH 1 -#define EF1_SW_RESET_LBN 2 -#define EF1_SW_RESET_WIDTH 1 -#define EF1_INTR_AFTER_EVENT_LBN 1 -#define EF1_INTR_AFTER_EVENT_WIDTH 1 - -/** Event FIFO */ -#define EF1_EVENT_FIFO_REG 0x50 - -/** Event FIFO count */ -#define EF1_EVENT_FIFO_COUNT_REG 0x5c -#define EF1_EV_COUNT_LBN 0 -#define EF1_EV_COUNT_WIDTH 16 - -/** TX DMA control and status */ -#define EF1_DMA_TX_CSR_REG 0x80 -#define EF1_DMA_TX_CSR_CHAIN_EN_LBN 8 -#define EF1_DMA_TX_CSR_CHAIN_EN_WIDTH 1 -#define EF1_DMA_TX_CSR_ENABLE_LBN 4 -#define EF1_DMA_TX_CSR_ENABLE_WIDTH 1 -#define EF1_DMA_TX_CSR_INT_EN_LBN 0 -#define EF1_DMA_TX_CSR_INT_EN_WIDTH 1 - -/** RX DMA control and status */ -#define EF1_DMA_RX_CSR_REG 0xa0 -#define EF1_DMA_RX_ABOVE_1GB_EN_LBN 6 -#define EF1_DMA_RX_ABOVE_1GB_EN_WIDTH 1 -#define EF1_DMA_RX_BELOW_1MB_EN_LBN 5 -#define EF1_DMA_RX_BELOW_1MB_EN_WIDTH 1 -#define EF1_DMA_RX_CSR_ENABLE_LBN 0 -#define EF1_DMA_RX_CSR_ENABLE_WIDTH 1 - -/** Level 5 watermark register (in MAC space) */ -#define EF1_GMF_L5WM_REG_MAC 0x20 -#define EF1_L5WM_LBN 0 -#define EF1_L5WM_WIDTH 32 - -/** MAC clock */ -#define EF1_GM_MAC_CLK_REG 0x112000 -#define EF1_GM_PORT0_MAC_CLK_LBN 0 -#define EF1_GM_PORT0_MAC_CLK_WIDTH 1 -#define EF1_GM_PORT1_MAC_CLK_LBN 1 -#define EF1_GM_PORT1_MAC_CLK_WIDTH 1 - -/** TX descriptor FIFO */ -#define EF1_TX_DESC_FIFO 0x141000 -#define EF1_TX_KER_EVQ_LBN 80 -#define EF1_TX_KER_EVQ_WIDTH 12 -#define EF1_TX_KER_IDX_LBN 64 -#define EF1_TX_KER_IDX_WIDTH 16 -#define EF1_TX_KER_MODE_LBN 63 -#define EF1_TX_KER_MODE_WIDTH 1 -#define EF1_TX_KER_PORT_LBN 60 -#define EF1_TX_KER_PORT_WIDTH 1 -#define EF1_TX_KER_CONT_LBN 56 -#define EF1_TX_KER_CONT_WIDTH 1 -#define EF1_TX_KER_BYTE_CNT_LBN 32 -#define EF1_TX_KER_BYTE_CNT_WIDTH 24 -#define EF1_TX_KER_BUF_ADR_LBN 0 -#define EF1_TX_KER_BUF_ADR_WIDTH 32 - -/** TX descriptor FIFO flush */ -#define EF1_TX_DESC_FIFO_FLUSH 0x141ffc - -/** RX descriptor FIFO */ -#define EF1_RX_DESC_FIFO 0x145000 -#define EF1_RX_KER_EVQ_LBN 48 -#define EF1_RX_KER_EVQ_WIDTH 12 -#define EF1_RX_KER_IDX_LBN 32 -#define EF1_RX_KER_IDX_WIDTH 16 -#define EF1_RX_KER_BUF_ADR_LBN 0 -#define EF1_RX_KER_BUF_ADR_WIDTH 32 - -/** RX descriptor FIFO flush */ -#define EF1_RX_DESC_FIFO_FLUSH 0x145ffc - -/** CAM */ -#define EF1_CAM_BASE 0x1c0000 -#define EF1_CAM_WTF_DOES_THIS_DO_LBN 0 -#define EF1_CAM_WTF_DOES_THIS_DO_WIDTH 32 - -/** Event queue pointers */ -#define EF1_EVQ_PTR_BASE 0x260000 -#define EF1_EVQ_SIZE_LBN 29 -#define EF1_EVQ_SIZE_WIDTH 2 -#define EF1_EVQ_SIZE_4K 3 -#define EF1_EVQ_SIZE_2K 2 -#define EF1_EVQ_SIZE_1K 1 -#define EF1_EVQ_SIZE_512 0 -#define EF1_EVQ_BUF_BASE_ID_LBN 0 -#define EF1_EVQ_BUF_BASE_ID_WIDTH 29 - -/* MAC registers */ -#define EF1002_MAC_REGBANK 0x110000 -#define EF1002_MAC_REGBANK_SIZE 0x1000 -#define EF1002_MAC_REG_SIZE 0x08 - -/** Offset of a MAC register within EF1002 */ -#define EF1002_MAC_REG( efab, mac_reg ) \ - ( EF1002_MAC_REGBANK + \ - ( (efab)->port * EF1002_MAC_REGBANK_SIZE ) + \ - ( (mac_reg) * EF1002_MAC_REG_SIZE ) ) +/* PHY management status & mask register */ +#define FCN_MD_STAT_REG_KER 0xc50 +#define FCN_MD_PINT_LBN 4 +#define FCN_MD_PINT_WIDTH 1 +#define FCN_MD_DONE_LBN 3 +#define FCN_MD_DONE_WIDTH 1 +#define FCN_MD_BSERR_LBN 2 +#define FCN_MD_BSERR_WIDTH 1 +#define FCN_MD_LNFL_LBN 1 +#define FCN_MD_LNFL_WIDTH 1 +#define FCN_MD_BSY_LBN 0 +#define FCN_MD_BSY_WIDTH 1 -/* Event queue entries */ -#define EF1_EV_CODE_LBN 20 -#define EF1_EV_CODE_WIDTH 8 -#define EF1_RX_EV_DECODE 0x01 -#define EF1_TX_EV_DECODE 0x02 -#define EF1_TIMER_EV_DECODE 0x0b -#define EF1_DRV_GEN_EV_DECODE 0x0f +/* Port 0 and 1 MAC control registers */ +#define FCN_MAC0_CTRL_REG_KER 0xc80 +#define FCN_MAC1_CTRL_REG_KER 0xc90 +#define FCN_MAC_XOFF_VAL_LBN 16 +#define FCN_MAC_XOFF_VAL_WIDTH 16 +#define FCN_MAC_BCAD_ACPT_LBN 4 +#define FCN_MAC_BCAD_ACPT_WIDTH 1 +#define FCN_MAC_UC_PROM_LBN 3 +#define FCN_MAC_UC_PROM_WIDTH 1 +#define FCN_MAC_LINK_STATUS_LBN 2 +#define FCN_MAC_LINK_STATUS_WIDTH 1 +#define FCN_MAC_SPEED_LBN 0 +#define FCN_MAC_SPEED_WIDTH 2 -/* Receive events */ -#define EF1_RX_EV_LEN_LBN 48 -#define EF1_RX_EV_LEN_WIDTH 16 -#define EF1_RX_EV_PORT_LBN 17 -#define EF1_RX_EV_PORT_WIDTH 3 -#define EF1_RX_EV_OK_LBN 16 -#define EF1_RX_EV_OK_WIDTH 1 -#define EF1_RX_EV_IDX_LBN 0 -#define EF1_RX_EV_IDX_WIDTH 16 +/* 10Gig Xaui XGXS Default Values */ +#define XX_TXDRV_DEQ_DEFAULT 0xe /* deq=.6 */ +#define XX_TXDRV_DTX_DEFAULT 0x5 /* 1.25 */ +#define XX_SD_CTL_DRV_DEFAULT 0 /* 20mA */ -/* Transmit events */ -#define EF1_TX_EV_PORT_LBN 17 -#define EF1_TX_EV_PORT_WIDTH 3 -#define EF1_TX_EV_OK_LBN 16 -#define EF1_TX_EV_OK_WIDTH 1 -#define EF1_TX_EV_IDX_LBN 0 -#define EF1_TX_EV_IDX_WIDTH 16 +/* GMAC registers */ +#define FALCON_GMAC_REGBANK 0xe00 +#define FALCON_GMAC_REGBANK_SIZE 0x200 +#define FALCON_GMAC_REG_SIZE 0x10 -/* forward decleration */ -static struct efab_mac_operations ef1002_mac_operations; +/* XGMAC registers */ +#define FALCON_XMAC_REGBANK 0x1200 +#define FALCON_XMAC_REGBANK_SIZE 0x200 +#define FALCON_XMAC_REG_SIZE 0x10 -/* I2C ID of the EEPROM */ -#define EF1_EEPROM_I2C_ID 0x50 +/* XGMAC address register low */ +#define FCN_XM_ADR_LO_REG_MAC 0x00 +#define FCN_XM_ADR_3_LBN 24 +#define FCN_XM_ADR_3_WIDTH 8 +#define FCN_XM_ADR_2_LBN 16 +#define FCN_XM_ADR_2_WIDTH 8 +#define FCN_XM_ADR_1_LBN 8 +#define FCN_XM_ADR_1_WIDTH 8 +#define FCN_XM_ADR_0_LBN 0 +#define FCN_XM_ADR_0_WIDTH 8 -/* Offset of MAC address within EEPROM */ -#define EF1_EEPROM_HWADDR_OFFSET 0x0 +/* XGMAC address register high */ +#define FCN_XM_ADR_HI_REG_MAC 0x01 +#define FCN_XM_ADR_5_LBN 8 +#define FCN_XM_ADR_5_WIDTH 8 +#define FCN_XM_ADR_4_LBN 0 +#define FCN_XM_ADR_4_WIDTH 8 -/** - * Write dword to EF1002 register - * - */ -static inline void ef1002_writel ( struct efab_nic *efab, efab_dword_t *value, - unsigned int reg ) { - EFAB_REGDUMP ( "Writing register %x with " EFAB_DWORD_FMT "\n", - reg, EFAB_DWORD_VAL ( *value ) ); - writel ( value->u32[0], efab->membase + reg ); -} +/* XGMAC global configuration - port 0*/ +#define FCN_XM_GLB_CFG_REG_MAC 0x02 +#define FCN_XM_RX_STAT_EN_LBN 11 +#define FCN_XM_RX_STAT_EN_WIDTH 1 +#define FCN_XM_TX_STAT_EN_LBN 10 +#define FCN_XM_TX_STAT_EN_WIDTH 1 +#define FCN_XM_RX_JUMBO_MODE_LBN 6 +#define FCN_XM_RX_JUMBO_MODE_WIDTH 1 +#define FCN_XM_CORE_RST_LBN 0 +#define FCN_XM_CORE_RST_WIDTH 1 -/** - * Read dword from an EF1002 register - * - */ -static inline void ef1002_readl ( struct efab_nic *efab, efab_dword_t *value, - unsigned int reg ) { - value->u32[0] = readl ( efab->membase + reg ); - EFAB_REGDUMP ( "Read from register %x, got " EFAB_DWORD_FMT "\n", - reg, EFAB_DWORD_VAL ( *value ) ); -} +/* XGMAC transmit configuration - port 0 */ +#define FCN_XM_TX_CFG_REG_MAC 0x03 +#define FCN_XM_IPG_LBN 16 +#define FCN_XM_IPG_WIDTH 4 +#define FCN_XM_FCNTL_LBN 10 +#define FCN_XM_FCNTL_WIDTH 1 +#define FCN_XM_TXCRC_LBN 8 +#define FCN_XM_TXCRC_WIDTH 1 +#define FCN_XM_AUTO_PAD_LBN 5 +#define FCN_XM_AUTO_PAD_WIDTH 1 +#define FCN_XM_TX_PRMBL_LBN 2 +#define FCN_XM_TX_PRMBL_WIDTH 1 +#define FCN_XM_TXEN_LBN 1 +#define FCN_XM_TXEN_WIDTH 1 -/** - * Read dword from an EF1002 register, silently - * - */ -static inline void ef1002_readl_silent ( struct efab_nic *efab, - efab_dword_t *value, - unsigned int reg ) { - value->u32[0] = readl ( efab->membase + reg ); -} +/* XGMAC receive configuration - port 0 */ +#define FCN_XM_RX_CFG_REG_MAC 0x04 +#define FCN_XM_PASS_CRC_ERR_LBN 25 +#define FCN_XM_PASS_CRC_ERR_WIDTH 1 +#define FCN_XM_AUTO_DEPAD_LBN 8 +#define FCN_XM_AUTO_DEPAD_WIDTH 1 +#define FCN_XM_RXEN_LBN 1 +#define FCN_XM_RXEN_WIDTH 1 -/** - * Get memory base - * - */ -static void ef1002_get_membase ( struct efab_nic *efab ) { - unsigned long membase_phys; +/* XGMAC management interrupt mask register */ +#define FCN_XM_MGT_INT_MSK_REG_MAC_B0 0x5 +#define FCN_XM_MSK_PRMBLE_ERR_LBN 2 +#define FCN_XM_MSK_PRMBLE_ERR_WIDTH 1 +#define FCN_XM_MSK_RMTFLT_LBN 1 +#define FCN_XM_MSK_RMTFLT_WIDTH 1 +#define FCN_XM_MSK_LCLFLT_LBN 0 +#define FCN_XM_MSK_LCLFLT_WIDTH 1 + +/* XGMAC flow control register */ +#define FCN_XM_FC_REG_MAC 0x7 +#define FCN_XM_PAUSE_TIME_LBN 16 +#define FCN_XM_PAUSE_TIME_WIDTH 16 +#define FCN_XM_DIS_FCNTL_LBN 0 +#define FCN_XM_DIS_FCNTL_WIDTH 1 - membase_phys = pci_bar_start ( efab->pci, PCI_BASE_ADDRESS_0 ); - efab->membase = ioremap ( membase_phys, 0x800000 ); -} +/* XGMAC transmit parameter register */ +#define FCN_XM_TX_PARAM_REG_MAC 0x0d +#define FCN_XM_TX_JUMBO_MODE_LBN 31 +#define FCN_XM_TX_JUMBO_MODE_WIDTH 1 +#define FCN_XM_MAX_TX_FRM_SIZE_LBN 16 +#define FCN_XM_MAX_TX_FRM_SIZE_WIDTH 14 +#define FCN_XM_ACPT_ALL_MCAST_LBN 11 +#define FCN_XM_ACPT_ALL_MCAST_WIDTH 1 -/** PCI registers to backup/restore over a device reset */ -static const unsigned int efab_pci_reg_addr[] = { - PCI_COMMAND, 0x0c /* PCI_CACHE_LINE_SIZE */, - PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, PCI_ROM_ADDRESS, PCI_INTERRUPT_LINE, -}; -/** Number of registers in efab_pci_reg_addr */ -#define EFAB_NUM_PCI_REG \ - ( sizeof ( efab_pci_reg_addr ) / sizeof ( efab_pci_reg_addr[0] ) ) -/** PCI configuration space backup */ -struct efab_pci_reg { - uint32_t reg[EFAB_NUM_PCI_REG]; -}; +/* XGMAC receive parameter register */ +#define FCN_XM_RX_PARAM_REG_MAC 0x0e +#define FCN_XM_MAX_RX_FRM_SIZE_LBN 0 +#define FCN_XM_MAX_RX_FRM_SIZE_WIDTH 14 -/* - * I2C interface and EEPROM - * - */ +/* XGMAC management interrupt status register */ +#define FCN_XM_MGT_INT_REG_MAC_B0 0x0f +#define FCN_XM_PRMBLE_ERR 2 +#define FCN_XM_PRMBLE_WIDTH 1 +#define FCN_XM_RMTFLT_LBN 1 +#define FCN_XM_RMTFLT_WIDTH 1 +#define FCN_XM_LCLFLT_LBN 0 +#define FCN_XM_LCLFLT_WIDTH 1 -static unsigned long ef1002_i2c_bits[] = { - [I2C_BIT_SCL] = ( 1 << 30 ), - [I2C_BIT_SDA] = ( 1 << 31 ), -}; +/* XAUI XGXS core status register */ +#define FCN_XX_ALIGN_DONE_LBN 20 +#define FCN_XX_ALIGN_DONE_WIDTH 1 +#define FCN_XX_CORE_STAT_REG_MAC 0x16 +#define FCN_XX_SYNC_STAT_LBN 16 +#define FCN_XX_SYNC_STAT_WIDTH 4 +#define FCN_XX_SYNC_STAT_DECODE_SYNCED 0xf +#define FCN_XX_COMMA_DET_LBN 12 +#define FCN_XX_COMMA_DET_WIDTH 4 +#define FCN_XX_COMMA_DET_RESET 0xf +#define FCN_XX_CHARERR_LBN 4 +#define FCN_XX_CHARERR_WIDTH 4 +#define FCN_XX_CHARERR_RESET 0xf +#define FCN_XX_DISPERR_LBN 0 +#define FCN_XX_DISPERR_WIDTH 4 +#define FCN_XX_DISPERR_RESET 0xf -static void ef1002_i2c_write_bit ( struct bit_basher *basher, - unsigned int bit_id, unsigned long data ) { - struct efab_nic *efab = container_of ( basher, struct efab_nic, - ef1002_i2c.basher ); - unsigned long mask; - efab_dword_t reg; +/* XGXS/XAUI powerdown/reset register */ +#define FCN_XX_PWR_RST_REG_MAC 0x10 +#define FCN_XX_PWRDND_EN_LBN 15 +#define FCN_XX_PWRDND_EN_WIDTH 1 +#define FCN_XX_PWRDNC_EN_LBN 14 +#define FCN_XX_PWRDNC_EN_WIDTH 1 +#define FCN_XX_PWRDNB_EN_LBN 13 +#define FCN_XX_PWRDNB_EN_WIDTH 1 +#define FCN_XX_PWRDNA_EN_LBN 12 +#define FCN_XX_PWRDNA_EN_WIDTH 1 +#define FCN_XX_RSTPLLCD_EN_LBN 9 +#define FCN_XX_RSTPLLCD_EN_WIDTH 1 +#define FCN_XX_RSTPLLAB_EN_LBN 8 +#define FCN_XX_RSTPLLAB_EN_WIDTH 1 +#define FCN_XX_RESETD_EN_LBN 7 +#define FCN_XX_RESETD_EN_WIDTH 1 +#define FCN_XX_RESETC_EN_LBN 6 +#define FCN_XX_RESETC_EN_WIDTH 1 +#define FCN_XX_RESETB_EN_LBN 5 +#define FCN_XX_RESETB_EN_WIDTH 1 +#define FCN_XX_RESETA_EN_LBN 4 +#define FCN_XX_RESETA_EN_WIDTH 1 +#define FCN_XX_RSTXGXSRX_EN_LBN 2 +#define FCN_XX_RSTXGXSRX_EN_WIDTH 1 +#define FCN_XX_RSTXGXSTX_EN_LBN 1 +#define FCN_XX_RSTXGXSTX_EN_WIDTH 1 +#define FCN_XX_RST_XX_EN_LBN 0 +#define FCN_XX_RST_XX_EN_WIDTH 1 - mask = ef1002_i2c_bits[bit_id]; - efab->ef1002_i2c_outputs &= ~mask; - efab->ef1002_i2c_outputs |= ( data & mask ); - EFAB_POPULATE_DWORD_1 ( reg, EF1_EEPROM, efab->ef1002_i2c_outputs ); - ef1002_writel ( efab, ®, EF1_EEPROM_REG ); -} -static int ef1002_i2c_read_bit ( struct bit_basher *basher, - unsigned int bit_id ) { - struct efab_nic *efab = container_of ( basher, struct efab_nic, - ef1002_i2c.basher ); - unsigned long mask; - efab_dword_t reg; +/* XGXS/XAUI powerdown/reset control register */ +#define FCN_XX_SD_CTL_REG_MAC 0x11 +#define FCN_XX_TERMADJ1_LBN 17 +#define FCN_XX_TERMADJ1_WIDTH 1 +#define FCN_XX_TERMADJ0_LBN 16 +#define FCN_XX_TERMADJ0_WIDTH 1 +#define FCN_XX_HIDRVD_LBN 15 +#define FCN_XX_HIDRVD_WIDTH 1 +#define FCN_XX_LODRVD_LBN 14 +#define FCN_XX_LODRVD_WIDTH 1 +#define FCN_XX_HIDRVC_LBN 13 +#define FCN_XX_HIDRVC_WIDTH 1 +#define FCN_XX_LODRVC_LBN 12 +#define FCN_XX_LODRVC_WIDTH 1 +#define FCN_XX_HIDRVB_LBN 11 +#define FCN_XX_HIDRVB_WIDTH 1 +#define FCN_XX_LODRVB_LBN 10 +#define FCN_XX_LODRVB_WIDTH 1 +#define FCN_XX_HIDRVA_LBN 9 +#define FCN_XX_HIDRVA_WIDTH 1 +#define FCN_XX_LODRVA_LBN 8 +#define FCN_XX_LODRVA_WIDTH 1 +#define FCN_XX_LPBKD_LBN 3 +#define FCN_XX_LPBKD_WIDTH 1 +#define FCN_XX_LPBKC_LBN 2 +#define FCN_XX_LPBKC_WIDTH 1 +#define FCN_XX_LPBKB_LBN 1 +#define FCN_XX_LPBKB_WIDTH 1 +#define FCN_XX_LPBKA_LBN 0 +#define FCN_XX_LPBKA_WIDTH 1 + +#define FCN_XX_TXDRV_CTL_REG_MAC 0x12 +#define FCN_XX_DEQD_LBN 28 +#define FCN_XX_DEQD_WIDTH 4 +#define FCN_XX_DEQC_LBN 24 +#define FCN_XX_DEQC_WIDTH 4 +#define FCN_XX_DEQB_LBN 20 +#define FCN_XX_DEQB_WIDTH 4 +#define FCN_XX_DEQA_LBN 16 +#define FCN_XX_DEQA_WIDTH 4 +#define FCN_XX_DTXD_LBN 12 +#define FCN_XX_DTXD_WIDTH 4 +#define FCN_XX_DTXC_LBN 8 +#define FCN_XX_DTXC_WIDTH 4 +#define FCN_XX_DTXB_LBN 4 +#define FCN_XX_DTXB_WIDTH 4 +#define FCN_XX_DTXA_LBN 0 +#define FCN_XX_DTXA_WIDTH 4 + +/* Receive filter table */ +#define FCN_RX_FILTER_TBL0 0xF00000 - mask = ef1002_i2c_bits[bit_id]; - ef1002_readl ( efab, ®, EF1_EEPROM_REG ); - return ( EFAB_DWORD_FIELD ( reg, EF1_EEPROM ) & mask ); -} +/* Receive descriptor pointer table */ +#define FCN_RX_DESC_PTR_TBL_KER_A1 0x11800 +#define FCN_RX_DESC_PTR_TBL_KER_B0 0xF40000 +#define FCN_RX_ISCSI_DDIG_EN_LBN 88 +#define FCN_RX_ISCSI_DDIG_EN_WIDTH 1 +#define FCN_RX_ISCSI_HDIG_EN_LBN 87 +#define FCN_RX_ISCSI_HDIG_EN_WIDTH 1 +#define FCN_RX_DESCQ_BUF_BASE_ID_LBN 36 +#define FCN_RX_DESCQ_BUF_BASE_ID_WIDTH 20 +#define FCN_RX_DESCQ_EVQ_ID_LBN 24 +#define FCN_RX_DESCQ_EVQ_ID_WIDTH 12 +#define FCN_RX_DESCQ_OWNER_ID_LBN 10 +#define FCN_RX_DESCQ_OWNER_ID_WIDTH 14 +#define FCN_RX_DESCQ_SIZE_LBN 3 +#define FCN_RX_DESCQ_SIZE_WIDTH 2 +#define FCN_RX_DESCQ_SIZE_4K 3 +#define FCN_RX_DESCQ_SIZE_2K 2 +#define FCN_RX_DESCQ_SIZE_1K 1 +#define FCN_RX_DESCQ_SIZE_512 0 +#define FCN_RX_DESCQ_TYPE_LBN 2 +#define FCN_RX_DESCQ_TYPE_WIDTH 1 +#define FCN_RX_DESCQ_JUMBO_LBN 1 +#define FCN_RX_DESCQ_JUMBO_WIDTH 1 +#define FCN_RX_DESCQ_EN_LBN 0 +#define FCN_RX_DESCQ_EN_WIDTH 1 -static struct bit_basher_operations ef1002_basher_ops = { - .read = ef1002_i2c_read_bit, - .write = ef1002_i2c_write_bit, -}; +/* Transmit descriptor pointer table */ +#define FCN_TX_DESC_PTR_TBL_KER_A1 0x11900 +#define FCN_TX_DESC_PTR_TBL_KER_B0 0xF50000 +#define FCN_TX_NON_IP_DROP_DIS_B0_LBN 91 +#define FCN_TX_NON_IP_DROP_DIS_B0_WIDTH 1 +#define FCN_TX_DESCQ_EN_LBN 88 +#define FCN_TX_DESCQ_EN_WIDTH 1 +#define FCN_TX_ISCSI_DDIG_EN_LBN 87 +#define FCN_TX_ISCSI_DDIG_EN_WIDTH 1 +#define FCN_TX_ISCSI_HDIG_EN_LBN 86 +#define FCN_TX_ISCSI_HDIG_EN_WIDTH 1 +#define FCN_TX_DESCQ_BUF_BASE_ID_LBN 36 +#define FCN_TX_DESCQ_BUF_BASE_ID_WIDTH 20 +#define FCN_TX_DESCQ_EVQ_ID_LBN 24 +#define FCN_TX_DESCQ_EVQ_ID_WIDTH 12 +#define FCN_TX_DESCQ_OWNER_ID_LBN 10 +#define FCN_TX_DESCQ_OWNER_ID_WIDTH 14 +#define FCN_TX_DESCQ_SIZE_LBN 3 +#define FCN_TX_DESCQ_SIZE_WIDTH 2 +#define FCN_TX_DESCQ_SIZE_4K 3 +#define FCN_TX_DESCQ_SIZE_2K 2 +#define FCN_TX_DESCQ_SIZE_1K 1 +#define FCN_TX_DESCQ_SIZE_512 0 +#define FCN_TX_DESCQ_TYPE_LBN 1 +#define FCN_TX_DESCQ_TYPE_WIDTH 2 +#define FCN_TX_DESCQ_FLUSH_LBN 0 +#define FCN_TX_DESCQ_FLUSH_WIDTH 1 -static void ef1002_init_eeprom ( struct efab_nic *efab ) { - efab->ef1002_i2c.basher.op = &ef1002_basher_ops; - init_i2c_bit_basher ( &efab->ef1002_i2c ); - efab->ef1002_eeprom.address = EF1_EEPROM_I2C_ID; -} +/* Event queue pointer */ +#define FCN_EVQ_PTR_TBL_KER_A1 0x11a00 +#define FCN_EVQ_PTR_TBL_KER_B0 0xf60000 +#define FCN_EVQ_EN_LBN 23 +#define FCN_EVQ_EN_WIDTH 1 +#define FCN_EVQ_SIZE_LBN 20 +#define FCN_EVQ_SIZE_WIDTH 3 +#define FCN_EVQ_SIZE_32K 6 +#define FCN_EVQ_SIZE_16K 5 +#define FCN_EVQ_SIZE_8K 4 +#define FCN_EVQ_SIZE_4K 3 +#define FCN_EVQ_SIZE_2K 2 +#define FCN_EVQ_SIZE_1K 1 +#define FCN_EVQ_SIZE_512 0 +#define FCN_EVQ_BUF_BASE_ID_LBN 0 +#define FCN_EVQ_BUF_BASE_ID_WIDTH 20 -/** - * Reset device - * - */ -static int ef1002_reset ( struct efab_nic *efab ) { - struct efab_pci_reg pci_reg; - struct pci_device *pci_dev = efab->pci; - efab_dword_t reg; - unsigned int i; - uint32_t tmp; +/* RSS indirection table */ +#define FCN_RX_RSS_INDIR_TBL_B0 0xFB0000 - /* Back up PCI configuration registers */ - for ( i = 0 ; i < EFAB_NUM_PCI_REG ; i++ ) { - pci_read_config_dword ( pci_dev, efab_pci_reg_addr[i], - &pci_reg.reg[i] ); - } +/* Event queue read pointer */ +#define FCN_EVQ_RPTR_REG_KER_A1 0x11b00 +#define FCN_EVQ_RPTR_REG_KER_B0 0xfa0000 +#define FCN_EVQ_RPTR_LBN 0 +#define FCN_EVQ_RPTR_WIDTH 14 +#define FCN_EVQ_RPTR_REG_KER_DWORD_A1 ( FCN_EVQ_RPTR_REG_KER_A1 + 0 ) +#define FCN_EVQ_RPTR_REG_KER_DWORD_B0 ( FCN_EVQ_RPTR_REG_KER_B0 + 0 ) +#define FCN_EVQ_RPTR_DWORD_LBN 0 +#define FCN_EVQ_RPTR_DWORD_WIDTH 14 - /* Reset the whole device. */ - EFAB_POPULATE_DWORD_1 ( reg, EF1_SW_RESET, 1 ); - ef1002_writel ( efab, ®, EF1_CTL2_REG ); - mdelay ( 200 ); - - /* Restore PCI configuration space */ - for ( i = 0 ; i < EFAB_NUM_PCI_REG ; i++ ) { - pci_write_config_dword ( pci_dev, efab_pci_reg_addr[i], - pci_reg.reg[i] ); - } - - /* Verify PCI configuration space */ - for ( i = 0 ; i < EFAB_NUM_PCI_REG ; i++ ) { - pci_read_config_dword ( pci_dev, efab_pci_reg_addr[i], &tmp ); - if ( tmp != pci_reg.reg[i] ) { - EFAB_LOG ( "PCI restore failed on register %02x " - "(is %08lx, should be %08lx); reboot\n", - i, tmp, pci_reg.reg[i] ); - return 0; - } - } +/* Special buffer descriptors */ +#define FCN_BUF_FULL_TBL_KER_A1 0x18000 +#define FCN_BUF_FULL_TBL_KER_B0 0x800000 +#define FCN_IP_DAT_BUF_SIZE_LBN 50 +#define FCN_IP_DAT_BUF_SIZE_WIDTH 1 +#define FCN_IP_DAT_BUF_SIZE_8K 1 +#define FCN_IP_DAT_BUF_SIZE_4K 0 +#define FCN_BUF_ADR_FBUF_LBN 14 +#define FCN_BUF_ADR_FBUF_WIDTH 34 +#define FCN_BUF_OWNER_ID_FBUF_LBN 0 +#define FCN_BUF_OWNER_ID_FBUF_WIDTH 14 - /* Verify device reset complete */ - ef1002_readl ( efab, ®, EF1_CTR_GEN_STATUS0_REG ); - if ( EFAB_DWORD_IS_ALL_ONES ( reg ) ) { - EFAB_ERR ( "Reset failed\n" ); - return 0; - } +/** Offset of a GMAC register within Falcon */ +#define FALCON_GMAC_REG( efab, mac_reg ) \ + ( FALCON_GMAC_REGBANK + \ + ( (mac_reg) * FALCON_GMAC_REG_SIZE ) ) - return 1; -} +/** Offset of an XMAC register within Falcon */ +#define FALCON_XMAC_REG( efab_port, mac_reg ) \ + ( FALCON_XMAC_REGBANK + \ + ( (mac_reg) * FALCON_XMAC_REG_SIZE ) ) -/** - * Initialise NIC - * - */ -static int ef1002_init_nic ( struct efab_nic *efab ) { - efab_dword_t reg; - - /* patch in the MAC operations */ - efab->mac_op = &ef1002_mac_operations; +#define FCN_MAC_DATA_LBN 0 +#define FCN_MAC_DATA_WIDTH 32 - /* No idea what CAM is, but the 'datasheet' says that we have - * to write these values in at start of day - */ - EFAB_POPULATE_DWORD_1 ( reg, EF1_CAM_WTF_DOES_THIS_DO, 0x6 ); - ef1002_writel ( efab, ®, EF1_CAM_BASE + 0x20018 ); - udelay ( 1000 ); - EFAB_POPULATE_DWORD_1 ( reg, EF1_CAM_WTF_DOES_THIS_DO, 0x01000000 ); - ef1002_writel ( efab, ®, EF1_CAM_BASE + 0x00018 ); - udelay ( 1000 ); +/* Transmit descriptor */ +#define FCN_TX_KER_PORT_LBN 63 +#define FCN_TX_KER_PORT_WIDTH 1 +#define FCN_TX_KER_BYTE_CNT_LBN 48 +#define FCN_TX_KER_BYTE_CNT_WIDTH 14 +#define FCN_TX_KER_BUF_ADR_LBN 0 +#define FCN_TX_KER_BUF_ADR_WIDTH EFAB_DMA_TYPE_WIDTH ( 46 ) - /* General control register 0 */ - ef1002_readl ( efab, ®, EF1_CTR_GEN_STATUS0_REG ); - EFAB_SET_DWORD_FIELD ( reg, EF1_MASTER_EVENTS, 0 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_TX_ENGINE_EN, 0 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_RX_ENGINE_EN, 0 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_TURBO2, 1 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_TURBO1, 1 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_TURBO3, 1 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_CAM_ENABLE, 1 ); - ef1002_writel ( efab, ®, EF1_CTR_GEN_STATUS0_REG ); - udelay ( 1000 ); - /* General control register 2 */ - ef1002_readl ( efab, ®, EF1_CTL2_REG ); - EFAB_SET_DWORD_FIELD ( reg, EF1_PLL_TRAP, 1 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_MEM_MAP_4MB, 0 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_EV_INTR_CLR_WRITE, 0 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_BURST_MERGE, 0 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_CLEAR_NULL_PAD, 1 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_INTR_AFTER_EVENT, 1 ); - ef1002_writel ( efab, ®, EF1_CTL2_REG ); - udelay ( 1000 ); +/* Receive descriptor */ +#define FCN_RX_KER_BUF_SIZE_LBN 48 +#define FCN_RX_KER_BUF_SIZE_WIDTH 14 +#define FCN_RX_KER_BUF_ADR_LBN 0 +#define FCN_RX_KER_BUF_ADR_WIDTH EFAB_DMA_TYPE_WIDTH ( 46 ) - /* Enable RX DMA */ - ef1002_readl ( efab, ®, EF1_DMA_RX_CSR_REG ); - EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_RX_CSR_ENABLE, 1 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_RX_BELOW_1MB_EN, 1 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_RX_ABOVE_1GB_EN, 1 ); - ef1002_writel ( efab, ®, EF1_DMA_RX_CSR_REG ); - udelay ( 1000 ); +/* Event queue entries */ +#define FCN_EV_CODE_LBN 60 +#define FCN_EV_CODE_WIDTH 4 +#define FCN_RX_IP_EV_DECODE 0 +#define FCN_TX_IP_EV_DECODE 2 +#define FCN_DRIVER_EV_DECODE 5 - /* Enable TX DMA */ - ef1002_readl ( efab, ®, EF1_DMA_TX_CSR_REG ); - EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_TX_CSR_CHAIN_EN, 1 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_TX_CSR_ENABLE, 0 /* ?? */ ); - EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_TX_CSR_INT_EN, 0 /* ?? */ ); - ef1002_writel ( efab, ®, EF1_DMA_TX_CSR_REG ); - udelay ( 1000 ); +/* Receive events */ +#define FCN_RX_EV_PKT_OK_LBN 56 +#define FCN_RX_EV_PKT_OK_WIDTH 1 +#define FCN_RX_PORT_LBN 30 +#define FCN_RX_PORT_WIDTH 1 +#define FCN_RX_EV_BYTE_CNT_LBN 16 +#define FCN_RX_EV_BYTE_CNT_WIDTH 14 +#define FCN_RX_EV_DESC_PTR_LBN 0 +#define FCN_RX_EV_DESC_PTR_WIDTH 12 - /* Disconnect the JTAG chain. Read-modify-write is impossible - * on the I2C control bits, since reading gives the state of - * the line inputs rather than the last written state. - */ - ef1002_readl ( efab, ®, EF1_EEPROM_REG ); - EFAB_SET_DWORD_FIELD ( reg, EF1_EEPROM_SDA, 1 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_EEPROM_SCL, 1 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_JTAG_DISCONNECT, 1 ); - ef1002_writel ( efab, ®, EF1_EEPROM_REG ); - udelay ( 10 ); +/* Transmit events */ +#define FCN_TX_EV_DESC_PTR_LBN 0 +#define FCN_TX_EV_DESC_PTR_WIDTH 12 - /* Flush descriptor queues */ - EFAB_ZERO_DWORD ( reg ); - ef1002_writel ( efab, ®, EF1_RX_DESC_FIFO_FLUSH ); - ef1002_writel ( efab, ®, EF1_TX_DESC_FIFO_FLUSH ); - wmb(); - udelay ( 10000 ); +/******************************************************************************* + * + * + * Low-level hardware access + * + * + *******************************************************************************/ - /* Reset MAC */ - efab->mac_op->reset ( efab ); +#define FCN_REVISION_REG(efab, reg) \ + ( ( efab->pci_revision == FALCON_REV_B0 ) ? reg ## _B0 : reg ## _A1 ) - /* Attach I2C bus */ - ef1002_init_eeprom ( efab ); +#define EFAB_SET_OWORD_FIELD_VER(efab, reg, field, val) \ + if ( efab->pci_revision == FALCON_REV_B0 ) \ + EFAB_SET_OWORD_FIELD ( reg, field ## _B0, val ); \ + else \ + EFAB_SET_OWORD_FIELD ( reg, field ## _A1, val ); - return 1; +#if FALCON_USE_IO_BAR + +/* Write dword via the I/O BAR */ +static inline void _falcon_writel ( struct efab_nic *efab, uint32_t value, + unsigned int reg ) { + outl ( reg, efab->iobase + FCN_IOM_IND_ADR_REG ); + outl ( value, efab->iobase + FCN_IOM_IND_DAT_REG ); } -/** - * Read MAC address from EEPROM - * - */ -static int ef1002_read_eeprom ( struct efab_nic *efab ) { - struct i2c_interface *i2c = &efab->ef1002_i2c.i2c; - struct i2c_device *i2cdev = &efab->ef1002_eeprom; - - if ( i2c->read ( i2c, i2cdev, EF1_EEPROM_HWADDR_OFFSET, - efab->mac_addr, sizeof ( efab->mac_addr ) ) != 0 ) - return 0; +/* Read dword via the I/O BAR */ +static inline uint32_t _falcon_readl ( struct efab_nic *efab, + unsigned int reg ) { + outl ( reg, efab->iobase + FCN_IOM_IND_ADR_REG ); + return inl ( efab->iobase + FCN_IOM_IND_DAT_REG ); +} - efab->mac_addr[ETH_ALEN-1] += efab->port; +#else /* FALCON_USE_IO_BAR */ - return 1; -} +#define _falcon_writel( efab, value, reg ) \ + writel ( (value), (efab)->membase + (reg) ) +#define _falcon_readl( efab, reg ) readl ( (efab)->membase + (reg) ) -/** RX descriptor */ -typedef efab_qword_t ef1002_rx_desc_t; +#endif /* FALCON_USE_IO_BAR */ /** - * Build RX descriptor + * Write to a Falcon register * */ -static void ef1002_build_rx_desc ( struct efab_nic *efab, - struct efab_rx_buf *rx_buf ) { - ef1002_rx_desc_t rxd; - - EFAB_POPULATE_QWORD_3 ( rxd, - EF1_RX_KER_EVQ, 0, - EF1_RX_KER_IDX, rx_buf->id, - EF1_RX_KER_BUF_ADR, - virt_to_bus ( rx_buf->addr ) ); - ef1002_writel ( efab, &rxd.dword[0], EF1_RX_DESC_FIFO + 0 ); +static inline void +falcon_write ( struct efab_nic *efab, efab_oword_t *value, unsigned int reg ) +{ + + EFAB_REGDUMP ( "Writing register %x with " EFAB_OWORD_FMT "\n", + reg, EFAB_OWORD_VAL ( *value ) ); + + _falcon_writel ( efab, value->u32[0], reg + 0 ); + _falcon_writel ( efab, value->u32[1], reg + 4 ); + _falcon_writel ( efab, value->u32[2], reg + 8 ); + wmb(); + _falcon_writel ( efab, value->u32[3], reg + 12 ); wmb(); - ef1002_writel ( efab, &rxd.dword[1], EF1_RX_DESC_FIFO + 4 ); - udelay ( 10 ); } /** - * Update RX descriptor write pointer + * Write to Falcon SRAM * */ -static void ef1002_notify_rx_desc ( struct efab_nic *efab __unused ) { - /* Nothing to do */ -} +static inline void +falcon_write_sram ( struct efab_nic *efab, efab_qword_t *value, + unsigned int index ) +{ + unsigned int reg = ( FCN_REVISION_REG ( efab, FCN_BUF_FULL_TBL_KER ) + + ( index * sizeof ( *value ) ) ); -/** TX descriptor */ -typedef efab_oword_t ef1002_tx_desc_t; + EFAB_REGDUMP ( "Writing SRAM register %x with " EFAB_QWORD_FMT "\n", + reg, EFAB_QWORD_VAL ( *value ) ); -/** - * Build TX descriptor - * - */ -static void ef1002_build_tx_desc ( struct efab_nic *efab, - struct efab_tx_buf *tx_buf ) { - ef1002_tx_desc_t txd; - - EFAB_POPULATE_OWORD_7 ( txd, - EF1_TX_KER_EVQ, 0, - EF1_TX_KER_IDX, tx_buf->id, - EF1_TX_KER_MODE, 0 /* IP mode */, - EF1_TX_KER_PORT, efab->port, - EF1_TX_KER_CONT, 0, - EF1_TX_KER_BYTE_CNT, tx_buf->len, - EF1_TX_KER_BUF_ADR, - virt_to_bus ( tx_buf->addr ) ); - - ef1002_writel ( efab, &txd.dword[0], EF1_TX_DESC_FIFO + 0 ); - ef1002_writel ( efab, &txd.dword[1], EF1_TX_DESC_FIFO + 4 ); + _falcon_writel ( efab, value->u32[0], reg + 0 ); + _falcon_writel ( efab, value->u32[1], reg + 4 ); wmb(); - ef1002_writel ( efab, &txd.dword[2], EF1_TX_DESC_FIFO + 8 ); - udelay ( 10 ); } /** - * Update TX descriptor write pointer + * Write dword to Falcon register that allows partial writes * */ -static void ef1002_notify_tx_desc ( struct efab_nic *efab __unused ) { - /* Nothing to do */ +static inline void +falcon_writel ( struct efab_nic *efab, efab_dword_t *value, unsigned int reg ) +{ + EFAB_REGDUMP ( "Writing partial register %x with " EFAB_DWORD_FMT "\n", + reg, EFAB_DWORD_VAL ( *value ) ); + _falcon_writel ( efab, value->u32[0], reg ); } -/** An event */ -typedef efab_qword_t ef1002_event_t; - /** - * Retrieve event from event queue + * Read from a Falcon register * */ -static int ef1002_fetch_event ( struct efab_nic *efab, - struct efab_event *event ) { - efab_dword_t reg; - int ev_code; - int words; - - /* Check event FIFO depth */ - ef1002_readl_silent ( efab, ®, EF1_EVENT_FIFO_COUNT_REG ); - words = EFAB_DWORD_FIELD ( reg, EF1_EV_COUNT ); - if ( ! words ) - return 0; - - /* Read event data */ - ef1002_readl ( efab, ®, EF1_EVENT_FIFO_REG ); - DBG ( "Event is " EFAB_DWORD_FMT "\n", EFAB_DWORD_VAL ( reg ) ); - - /* Decode event */ - ev_code = EFAB_DWORD_FIELD ( reg, EF1_EV_CODE ); - event->drop = 0; - switch ( ev_code ) { - case EF1_TX_EV_DECODE: - event->type = EFAB_EV_TX; - break; - case EF1_RX_EV_DECODE: - event->type = EFAB_EV_RX; - event->rx_id = EFAB_DWORD_FIELD ( reg, EF1_RX_EV_IDX ); - /* RX len not available via event FIFO */ - event->rx_len = ETH_FRAME_LEN; - break; - case EF1_TIMER_EV_DECODE: - /* These are safe to ignore. We seem to get some at - * start of day, presumably due to the timers starting - * up with random contents. - */ - event->type = EFAB_EV_NONE; - break; - default: - EFAB_ERR ( "Unknown event type %d\n", ev_code ); - event->type = EFAB_EV_NONE; - } - - /* Clear any pending interrupts */ - ef1002_readl ( efab, ®, EF1_IRQ_SRC_REG ); +static inline void +falcon_read ( struct efab_nic *efab, efab_oword_t *value, unsigned int reg ) +{ + value->u32[0] = _falcon_readl ( efab, reg + 0 ); + wmb(); + value->u32[1] = _falcon_readl ( efab, reg + 4 ); + value->u32[2] = _falcon_readl ( efab, reg + 8 ); + value->u32[3] = _falcon_readl ( efab, reg + 12 ); - return 1; + EFAB_REGDUMP ( "Read from register %x, got " EFAB_OWORD_FMT "\n", + reg, EFAB_OWORD_VAL ( *value ) ); } -/** - * Enable/disable interrupts +/** + * Read from Falcon SRAM * */ -static void ef1002_mask_irq ( struct efab_nic *efab, int enabled ) { - efab_dword_t irq_mask; +static inline void +falcon_read_sram ( struct efab_nic *efab, efab_qword_t *value, + unsigned int index ) +{ + unsigned int reg = ( FCN_REVISION_REG ( efab, FCN_BUF_FULL_TBL_KER ) + + ( index * sizeof ( *value ) ) ); - EFAB_POPULATE_DWORD_2 ( irq_mask, - EF1_IRQ_SERR, enabled, - EF1_IRQ_EVQ, enabled ); - ef1002_writel ( efab, &irq_mask, EF1_IRQ_MASK_REG ); + value->u32[0] = _falcon_readl ( efab, reg + 0 ); + value->u32[1] = _falcon_readl ( efab, reg + 4 ); + EFAB_REGDUMP ( "Read from SRAM register %x, got " EFAB_QWORD_FMT "\n", + reg, EFAB_QWORD_VAL ( *value ) ); } /** - * Generate interrupt + * Read dword from a portion of a Falcon register * */ -static void ef1002_generate_irq ( struct efab_nic *efab ) { - ef1002_event_t test_event; - - EFAB_POPULATE_QWORD_1 ( test_event, - EF1_EV_CODE, EF1_DRV_GEN_EV_DECODE ); - ef1002_writel ( efab, &test_event.dword[0], EF1_EVT3_REG ); +static inline void +falcon_readl ( struct efab_nic *efab, efab_dword_t *value, unsigned int reg ) +{ + value->u32[0] = _falcon_readl ( efab, reg ); + EFAB_REGDUMP ( "Read from register %x, got " EFAB_DWORD_FMT "\n", + reg, EFAB_DWORD_VAL ( *value ) ); } -/** - * Write dword to an EF1002 MAC register - * - */ -static void ef1002_mac_writel ( struct efab_nic *efab, - efab_dword_t *value, unsigned int mac_reg ) { - ef1002_writel ( efab, value, EF1002_MAC_REG ( efab, mac_reg ) ); -} +#define FCN_DUMP_REG( efab, _reg ) do { \ + efab_oword_t reg; \ + falcon_read ( efab, ®, _reg ); \ + EFAB_LOG ( #_reg " = " EFAB_OWORD_FMT "\n", \ + EFAB_OWORD_VAL ( reg ) ); \ + } while ( 0 ); + +#define FCN_DUMP_MAC_REG( efab, _mac_reg ) do { \ + efab_dword_t reg; \ + efab->mac_op->mac_readl ( efab, ®, _mac_reg ); \ + EFAB_LOG ( #_mac_reg " = " EFAB_DWORD_FMT "\n", \ + EFAB_DWORD_VAL ( reg ) ); \ + } while ( 0 ); /** - * Read dword from an EF1002 MAC register + * See if an event is present + * + * @v event Falcon event structure + * @ret True An event is pending + * @ret False No event is pending + * + * We check both the high and low dword of the event for all ones. We + * wrote all ones when we cleared the event, and no valid event can + * have all ones in either its high or low dwords. This approach is + * robust against reordering. * + * Note that using a single 64-bit comparison is incorrect; even + * though the CPU read will be atomic, the DMA write may not be. */ -static void ef1002_mac_readl ( struct efab_nic *efab, - efab_dword_t *value, unsigned int mac_reg ) { - ef1002_readl ( efab, value, EF1002_MAC_REG ( efab, mac_reg ) ); +static inline int +falcon_event_present ( falcon_event_t* event ) +{ + return ( ! ( EFAB_DWORD_IS_ALL_ONES ( event->dword[0] ) | + EFAB_DWORD_IS_ALL_ONES ( event->dword[1] ) ) ); } -/** - * Initialise MAC - * - */ -static int ef1002_init_mac ( struct efab_nic *efab ) { - static struct efab_mentormac_parameters ef1002_mentormac_params = { - .gmf_cfgfrth = 0x13, - .gmf_cfgftth = 0x10, - .gmf_cfghwmft = 0x555, - .gmf_cfghwm = 0x2a, - .gmf_cfglwm = 0x15, - }; +static void +falcon_eventq_read_ack ( struct efab_nic *efab, struct efab_ev_queue *ev_queue ) +{ efab_dword_t reg; - unsigned int mac_clk; - - /* Initialise PHY */ - alaska_init ( efab ); - - /* Initialise MAC */ - mentormac_init ( efab, &ef1002_mentormac_params ); - /* Write Level 5 watermark register */ - EFAB_POPULATE_DWORD_1 ( reg, EF1_L5WM, 0x10040000 ); - efab->mac_op->mac_writel ( efab, ®, EF1_GMF_L5WM_REG_MAC ); - udelay ( 10 ); - - /* Set MAC clock speed */ - ef1002_readl ( efab, ®, EF1_GM_MAC_CLK_REG ); - mac_clk = ( efab->link_options & LPA_1000 ) ? 0 : 1; - if ( efab->port == 0 ) { - EFAB_SET_DWORD_FIELD ( reg, EF1_GM_PORT0_MAC_CLK, mac_clk ); - } else { - EFAB_SET_DWORD_FIELD ( reg, EF1_GM_PORT1_MAC_CLK, mac_clk ); - } - ef1002_writel ( efab, ®, EF1_GM_MAC_CLK_REG ); - udelay ( 10 ); - - return 1; + EFAB_POPULATE_DWORD_1 ( reg, FCN_EVQ_RPTR_DWORD, ev_queue->read_ptr ); + falcon_writel ( efab, ®, + FCN_REVISION_REG ( efab, FCN_EVQ_RPTR_REG_KER_DWORD ) ); } +#if 0 /** - * Reset MAC + * Dump register contents (for debugging) * + * Marked as static inline so that it will not be compiled in if not + * used. */ -static int ef1002_reset_mac ( struct efab_nic *efab ) { - mentormac_reset ( efab ); - return 1; +static inline void +falcon_dump_regs ( struct efab_nic *efab ) +{ + FCN_DUMP_REG ( efab, FCN_INT_EN_REG_KER ); + FCN_DUMP_REG ( efab, FCN_INT_ADR_REG_KER ); + FCN_DUMP_REG ( efab, FCN_GLB_CTL_REG_KER ); + FCN_DUMP_REG ( efab, FCN_TIMER_CMD_REG_KER ); + FCN_DUMP_REG ( efab, FCN_SRM_RX_DC_CFG_REG_KER ); + FCN_DUMP_REG ( efab, FCN_SRM_TX_DC_CFG_REG_KER ); + FCN_DUMP_REG ( efab, FCN_RX_FILTER_CTL_REG_KER ); + FCN_DUMP_REG ( efab, FCN_RX_DC_CFG_REG_KER ); + FCN_DUMP_REG ( efab, FCN_TX_DC_CFG_REG_KER ); + FCN_DUMP_REG ( efab, FCN_MAC0_CTRL_REG_KER ); + FCN_DUMP_REG ( efab, FCN_MAC1_CTRL_REG_KER ); + FCN_DUMP_REG ( efab, FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) ); + FCN_DUMP_REG ( efab, FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) ); + FCN_DUMP_REG ( efab, FCN_REVISION_REG ( efab, FCN_EVQ_PTR_TBL_KER ) ); + FCN_DUMP_MAC_REG ( efab, GM_CFG1_REG_MAC ); + FCN_DUMP_MAC_REG ( efab, GM_CFG2_REG_MAC ); + FCN_DUMP_MAC_REG ( efab, GM_MAX_FLEN_REG_MAC ); + FCN_DUMP_MAC_REG ( efab, GM_MII_MGMT_CFG_REG_MAC ); + FCN_DUMP_MAC_REG ( efab, GM_ADR1_REG_MAC ); + FCN_DUMP_MAC_REG ( efab, GM_ADR2_REG_MAC ); + FCN_DUMP_MAC_REG ( efab, GMF_CFG0_REG_MAC ); + FCN_DUMP_MAC_REG ( efab, GMF_CFG1_REG_MAC ); + FCN_DUMP_MAC_REG ( efab, GMF_CFG2_REG_MAC ); + FCN_DUMP_MAC_REG ( efab, GMF_CFG3_REG_MAC ); + FCN_DUMP_MAC_REG ( efab, GMF_CFG4_REG_MAC ); + FCN_DUMP_MAC_REG ( efab, GMF_CFG5_REG_MAC ); } +#endif -/** MDIO write */ -static void ef1002_mdio_write ( struct efab_nic *efab, int location, - int value ) { - mentormac_mdio_write ( efab, efab->port + 2, location, value ); -} +static void +falcon_interrupts ( struct efab_nic *efab, int enabled, int force ) +{ + efab_oword_t int_en_reg_ker; -/** MDIO read */ -static int ef1002_mdio_read ( struct efab_nic *efab, int location ) { - return mentormac_mdio_read ( efab, efab->port + 2, location ); + EFAB_POPULATE_OWORD_2 ( int_en_reg_ker, + FCN_KER_INT_KER, force, + FCN_DRV_INT_EN_KER, enabled ); + falcon_write ( efab, &int_en_reg_ker, FCN_INT_EN_REG_KER ); } -static struct efab_operations ef1002_operations = { - .get_membase = ef1002_get_membase, - .reset = ef1002_reset, - .init_nic = ef1002_init_nic, - .read_eeprom = ef1002_read_eeprom, - .build_rx_desc = ef1002_build_rx_desc, - .notify_rx_desc = ef1002_notify_rx_desc, - .build_tx_desc = ef1002_build_tx_desc, - .notify_tx_desc = ef1002_notify_tx_desc, - .fetch_event = ef1002_fetch_event, - .mask_irq = ef1002_mask_irq, - .generate_irq = ef1002_generate_irq, - .mdio_write = ef1002_mdio_write, - .mdio_read = ef1002_mdio_read, -}; - -static struct efab_mac_operations ef1002_mac_operations = { - .mac_writel = ef1002_mac_writel, - .mac_readl = ef1002_mac_readl, - .init = ef1002_init_mac, - .reset = ef1002_reset_mac, -}; - -/************************************************************************** +/******************************************************************************* * - * Falcon routines * - ************************************************************************** - */ + * SPI access + * + * + *******************************************************************************/ -/* I/O BAR address register */ -#define FCN_IOM_IND_ADR_REG 0x0 -/* I/O BAR data register */ -#define FCN_IOM_IND_DAT_REG 0x4 +/** Maximum length for a single SPI transaction */ +#define FALCON_SPI_MAX_LEN 16 -/* Interrupt enable register */ -#define FCN_INT_EN_REG_KER 0x0010 -#define FCN_MEM_PERR_INT_EN_KER_LBN 5 -#define FCN_MEM_PERR_INT_EN_KER_WIDTH 1 -#define FCN_KER_INT_CHAR_LBN 4 -#define FCN_KER_INT_CHAR_WIDTH 1 -#define FCN_KER_INT_KER_LBN 3 -#define FCN_KER_INT_KER_WIDTH 1 -#define FCN_ILL_ADR_ERR_INT_EN_KER_LBN 2 -#define FCN_ILL_ADR_ERR_INT_EN_KER_WIDTH 1 -#define FCN_SRM_PERR_INT_EN_KER_LBN 1 -#define FCN_SRM_PERR_INT_EN_KER_WIDTH 1 -#define FCN_DRV_INT_EN_KER_LBN 0 -#define FCN_DRV_INT_EN_KER_WIDTH 1 +static int +falcon_spi_wait ( struct efab_nic *efab ) +{ + efab_oword_t reg; + int count; -/* Interrupt status register */ -#define FCN_INT_ADR_REG_KER 0x0030 -#define FCN_INT_ADR_KER_LBN 0 -#define FCN_INT_ADR_KER_WIDTH EFAB_DMA_TYPE_WIDTH ( 64 ) + count = 0; + do { + udelay ( 100 ); + falcon_read ( efab, ®, FCN_EE_SPI_HCMD_REG ); + if ( EFAB_OWORD_FIELD ( reg, FCN_EE_SPI_HCMD_CMD_EN ) == 0 ) + return 0; + } while ( ++count < 1000 ); -/* Interrupt acknowledge register */ -#define FCN_INT_ACK_KER_REG 0x0050 + EFAB_ERR ( "Timed out waiting for SPI\n" ); + return -ETIMEDOUT; +} -/* SPI host command register */ -#define FCN_EE_SPI_HCMD_REG_KER 0x0100 -#define FCN_EE_SPI_HCMD_CMD_EN_LBN 31 -#define FCN_EE_SPI_HCMD_CMD_EN_WIDTH 1 -#define FCN_EE_WR_TIMER_ACTIVE_LBN 28 -#define FCN_EE_WR_TIMER_ACTIVE_WIDTH 1 -#define FCN_EE_SPI_HCMD_SF_SEL_LBN 24 -#define FCN_EE_SPI_HCMD_SF_SEL_WIDTH 1 -#define FCN_EE_SPI_EEPROM 0 -#define FCN_EE_SPI_FLASH 1 -#define FCN_EE_SPI_HCMD_DABCNT_LBN 16 -#define FCN_EE_SPI_HCMD_DABCNT_WIDTH 5 -#define FCN_EE_SPI_HCMD_READ_LBN 15 -#define FCN_EE_SPI_HCMD_READ_WIDTH 1 -#define FCN_EE_SPI_READ 1 -#define FCN_EE_SPI_WRITE 0 -#define FCN_EE_SPI_HCMD_DUBCNT_LBN 12 -#define FCN_EE_SPI_HCMD_DUBCNT_WIDTH 2 -#define FCN_EE_SPI_HCMD_ADBCNT_LBN 8 -#define FCN_EE_SPI_HCMD_ADBCNT_WIDTH 2 -#define FCN_EE_SPI_HCMD_ENC_LBN 0 -#define FCN_EE_SPI_HCMD_ENC_WIDTH 8 +static int +falcon_spi_rw ( struct spi_bus* bus, struct spi_device *device, + unsigned int command, int address, + const void* data_out, void *data_in, size_t len ) +{ + struct efab_nic *efab = container_of ( bus, struct efab_nic, spi_bus ); + int address_len, rc, device_id, read_cmd; + efab_oword_t reg; -/* SPI host address register */ -#define FCN_EE_SPI_HADR_REG_KER 0x0110 -#define FCN_EE_SPI_HADR_DUBYTE_LBN 24 -#define FCN_EE_SPI_HADR_DUBYTE_WIDTH 8 -#define FCN_EE_SPI_HADR_ADR_LBN 0 -#define FCN_EE_SPI_HADR_ADR_WIDTH 24 + /* falcon_init_spi_device() should have reduced the block size + * down so this constraint holds */ + assert ( len <= FALCON_SPI_MAX_LEN ); -/* SPI host data register */ -#define FCN_EE_SPI_HDATA_REG_KER 0x0120 -#define FCN_EE_SPI_HDATA3_LBN 96 -#define FCN_EE_SPI_HDATA3_WIDTH 32 -#define FCN_EE_SPI_HDATA2_LBN 64 -#define FCN_EE_SPI_HDATA2_WIDTH 32 -#define FCN_EE_SPI_HDATA1_LBN 32 -#define FCN_EE_SPI_HDATA1_WIDTH 32 -#define FCN_EE_SPI_HDATA0_LBN 0 -#define FCN_EE_SPI_HDATA0_WIDTH 32 + /* Is this the FLASH or EEPROM device? */ + if ( device == &efab->spi_flash ) + device_id = FCN_EE_SPI_FLASH; + else if ( device == &efab->spi_eeprom ) + device_id = FCN_EE_SPI_EEPROM; + else { + EFAB_ERR ( "Unknown device %p\n", device ); + return -EINVAL; + } -/* VPI configuration register */ -#define FCN_VPD_CONFIG_REG_KER 0x0140 -#define FCN_VPD_9BIT_LBN 1 -#define FCN_VPD_9BIT_WIDTH 1 + EFAB_TRACE ( "Executing spi command %d on device %d at %d for %d bytes\n", + command, device_id, address, len ); -/* NIC status register */ -#define FCN_NIC_STAT_REG 0x0200 -#define ONCHIP_SRAM_LBN 16 -#define ONCHIP_SRAM_WIDTH 1 -#define SF_PRST_LBN 9 -#define SF_PRST_WIDTH 1 -#define EE_PRST_LBN 8 -#define EE_PRST_WIDTH 1 -#define EE_STRAP_LBN 7 -#define EE_STRAP_WIDTH 1 -#define PCI_PCIX_MODE_LBN 4 -#define PCI_PCIX_MODE_WIDTH 3 -#define PCI_PCIX_MODE_PCI33_DECODE 0 -#define PCI_PCIX_MODE_PCI66_DECODE 1 -#define PCI_PCIX_MODE_PCIX66_DECODE 5 -#define PCI_PCIX_MODE_PCIX100_DECODE 6 -#define PCI_PCIX_MODE_PCIX133_DECODE 7 -#define STRAP_ISCSI_EN_LBN 3 -#define STRAP_ISCSI_EN_WIDTH 1 -#define STRAP_PINS_LBN 0 -#define STRAP_PINS_WIDTH 3 -/* These bit definitions are extrapolated from the list of numerical - * values for STRAP_PINS. If you want a laugh, read the datasheet's - * definition for when bits 2:0 are set to 7. - */ -#define STRAP_10G_LBN 2 -#define STRAP_10G_WIDTH 1 -#define STRAP_DUAL_PORT_LBN 1 -#define STRAP_DUAL_PORT_WIDTH 1 -#define STRAP_PCIE_LBN 0 -#define STRAP_PCIE_WIDTH 1 + /* The bus must be idle */ + rc = falcon_spi_wait ( efab ); + if ( rc ) + goto fail1; -/* GPIO control register */ -#define FCN_GPIO_CTL_REG_KER 0x0210 -#define FCN_FLASH_PRESENT_LBN 7 -#define FCN_FLASH_PRESENT_WIDTH 1 -#define FCN_EEPROM_PRESENT_LBN 6 -#define FCN_EEPROM_PRESENT_WIDTH 1 + /* Copy data out */ + if ( data_out ) { + memcpy ( ®, data_out, len ); + falcon_write ( efab, ®, FCN_EE_SPI_HDATA_REG ); + } -/* Global control register */ -#define FCN_GLB_CTL_REG_KER 0x0220 -#define EXT_PHY_RST_CTL_LBN 63 -#define EXT_PHY_RST_CTL_WIDTH 1 -#define PCIE_SD_RST_CTL_LBN 61 -#define PCIE_SD_RST_CTL_WIDTH 1 -#define PCIX_RST_CTL_LBN 60 -#define PCIX_RST_CTL_WIDTH 1 -#define PCIE_STCK_RST_CTL_LBN 59 -#define PCIE_STCK_RST_CTL_WIDTH 1 -#define PCIE_NSTCK_RST_CTL_LBN 58 -#define PCIE_NSTCK_RST_CTL_WIDTH 1 -#define PCIE_CORE_RST_CTL_LBN 57 -#define PCIE_CORE_RST_CTL_WIDTH 1 -#define EE_RST_CTL_LBN 49 -#define EE_RST_CTL_WIDTH 1 -#define CS_RST_CTL_LBN 48 -#define CS_RST_CTL_WIDTH 1 -#define RST_EXT_PHY_LBN 31 -#define RST_EXT_PHY_WIDTH 1 -#define INT_RST_DUR_LBN 4 -#define INT_RST_DUR_WIDTH 3 -#define EXT_PHY_RST_DUR_LBN 1 -#define EXT_PHY_RST_DUR_WIDTH 3 -#define SWRST_LBN 0 -#define SWRST_WIDTH 1 -#define INCLUDE_IN_RESET 0 -#define EXCLUDE_FROM_RESET 1 + /* Program address register */ + if ( address >= 0 ) { + EFAB_POPULATE_OWORD_1 ( reg, FCN_EE_SPI_HADR_ADR, address ); + falcon_write ( efab, ®, FCN_EE_SPI_HADR_REG ); + } -/* FPGA build version */ -#define ALTERA_BUILD_REG_KER 0x0300 -#define VER_MAJOR_LBN 24 -#define VER_MAJOR_WIDTH 8 -#define VER_MINOR_LBN 16 -#define VER_MINOR_WIDTH 8 -#define VER_BUILD_LBN 0 -#define VER_BUILD_WIDTH 16 -#define VER_ALL_LBN 0 -#define VER_ALL_WIDTH 32 + /* Issue command */ + address_len = ( address >= 0 ) ? device->address_len / 8 : 0; + read_cmd = ( data_in ? FCN_EE_SPI_READ : FCN_EE_SPI_WRITE ); + EFAB_POPULATE_OWORD_7 ( reg, + FCN_EE_SPI_HCMD_CMD_EN, 1, + FCN_EE_SPI_HCMD_SF_SEL, device_id, + FCN_EE_SPI_HCMD_DABCNT, len, + FCN_EE_SPI_HCMD_READ, read_cmd, + FCN_EE_SPI_HCMD_DUBCNT, 0, + FCN_EE_SPI_HCMD_ADBCNT, address_len, + FCN_EE_SPI_HCMD_ENC, command ); + falcon_write ( efab, ®, FCN_EE_SPI_HCMD_REG ); -/* Timer table for kernel access */ -#define FCN_TIMER_CMD_REG_KER 0x420 -#define FCN_TIMER_MODE_LBN 12 -#define FCN_TIMER_MODE_WIDTH 2 -#define FCN_TIMER_MODE_DIS 0 -#define FCN_TIMER_MODE_INT_HLDOFF 1 -#define FCN_TIMER_VAL_LBN 0 -#define FCN_TIMER_VAL_WIDTH 12 + /* Wait for the command to complete */ + rc = falcon_spi_wait ( efab ); + if ( rc ) + goto fail2; -/* Receive configuration register */ -#define FCN_RX_CFG_REG_KER 0x800 -#define FCN_RX_XOFF_EN_LBN 0 -#define FCN_RX_XOFF_EN_WIDTH 1 + /* Copy data in */ + if ( data_in ) { + falcon_read ( efab, ®, FCN_EE_SPI_HDATA_REG ); + memcpy ( data_in, ®, len ); + } -/* SRAM receive descriptor cache configuration register */ -#define FCN_SRM_RX_DC_CFG_REG_KER 0x610 -#define FCN_SRM_RX_DC_BASE_ADR_LBN 0 -#define FCN_SRM_RX_DC_BASE_ADR_WIDTH 21 + return 0; -/* SRAM transmit descriptor cache configuration register */ -#define FCN_SRM_TX_DC_CFG_REG_KER 0x620 -#define FCN_SRM_TX_DC_BASE_ADR_LBN 0 -#define FCN_SRM_TX_DC_BASE_ADR_WIDTH 21 +fail2: +fail1: + EFAB_ERR ( "Failed SPI command %d to device %d address 0x%x len 0x%x\n", + command, device_id, address, len ); -/* Receive filter control register */ -#define FCN_RX_FILTER_CTL_REG_KER 0x810 -#define FCN_NUM_KER_LBN 24 -#define FCN_NUM_KER_WIDTH 2 + return rc; +} -/* Receive descriptor update register */ -#define FCN_RX_DESC_UPD_REG_KER 0x0830 -#define FCN_RX_DESC_WPTR_LBN 96 -#define FCN_RX_DESC_WPTR_WIDTH 12 -#define FCN_RX_DESC_UPD_REG_KER_DWORD ( FCN_RX_DESC_UPD_REG_KER + 12 ) -#define FCN_RX_DESC_WPTR_DWORD_LBN 0 -#define FCN_RX_DESC_WPTR_DWORD_WIDTH 12 +/** Portion of EEPROM available for non-volatile options */ +static struct nvo_fragment falcon_nvo_fragments[] = { + { 0x100, 0xf0 }, + { 0, 0 } +}; -/* Receive descriptor cache configuration register */ -#define FCN_RX_DC_CFG_REG_KER 0x840 -#define FCN_RX_DC_SIZE_LBN 0 -#define FCN_RX_DC_SIZE_WIDTH 2 +/******************************************************************************* + * + * + * Falcon bit-bashed I2C interface + * + * + *******************************************************************************/ -/* Transmit descriptor update register */ -#define FCN_TX_DESC_UPD_REG_KER 0x0a10 -#define FCN_TX_DESC_WPTR_LBN 96 -#define FCN_TX_DESC_WPTR_WIDTH 12 -#define FCN_TX_DESC_UPD_REG_KER_DWORD ( FCN_TX_DESC_UPD_REG_KER + 12 ) -#define FCN_TX_DESC_WPTR_DWORD_LBN 0 -#define FCN_TX_DESC_WPTR_DWORD_WIDTH 12 +static void +falcon_i2c_bit_write ( struct bit_basher *basher, unsigned int bit_id, + unsigned long data ) +{ + struct efab_nic *efab = container_of ( basher, struct efab_nic, + i2c_bb.basher ); + efab_oword_t reg; -/* Transmit descriptor cache configuration register */ -#define FCN_TX_DC_CFG_REG_KER 0xa20 -#define FCN_TX_DC_SIZE_LBN 0 -#define FCN_TX_DC_SIZE_WIDTH 2 + falcon_read ( efab, ®, FCN_GPIO_CTL_REG_KER ); + switch ( bit_id ) { + case I2C_BIT_SCL: + EFAB_SET_OWORD_FIELD ( reg, FCN_GPIO0_OEN, ( data ? 0 : 1 ) ); + break; + case I2C_BIT_SDA: + EFAB_SET_OWORD_FIELD ( reg, FCN_GPIO3_OEN, ( data ? 0 : 1 ) ); + break; + default: + EFAB_ERR ( "%s bit=%d\n", __func__, bit_id ); + break; + } -/* PHY management transmit data register */ -#define FCN_MD_TXD_REG_KER 0xc00 -#define FCN_MD_TXD_LBN 0 -#define FCN_MD_TXD_WIDTH 16 + falcon_write ( efab, ®, FCN_GPIO_CTL_REG_KER ); +} -/* PHY management receive data register */ -#define FCN_MD_RXD_REG_KER 0xc10 -#define FCN_MD_RXD_LBN 0 -#define FCN_MD_RXD_WIDTH 16 +static int +falcon_i2c_bit_read ( struct bit_basher *basher, unsigned int bit_id ) +{ + struct efab_nic *efab = container_of ( basher, struct efab_nic, + i2c_bb.basher ); + efab_oword_t reg; + + falcon_read ( efab, ®, FCN_GPIO_CTL_REG_KER ); + switch ( bit_id ) { + case I2C_BIT_SCL: + return EFAB_OWORD_FIELD ( reg, FCN_GPIO0_IN ); + break; + case I2C_BIT_SDA: + return EFAB_OWORD_FIELD ( reg, FCN_GPIO3_IN ); + break; + default: + EFAB_ERR ( "%s bit=%d\n", __func__, bit_id ); + break; + } -/* PHY management configuration & status register */ -#define FCN_MD_CS_REG_KER 0xc20 -#define FCN_MD_GC_LBN 4 -#define FCN_MD_GC_WIDTH 1 -#define FCN_MD_RIC_LBN 2 -#define FCN_MD_RIC_WIDTH 1 -#define FCN_MD_WRC_LBN 0 -#define FCN_MD_WRC_WIDTH 1 + return -1; +} -/* PHY management PHY address register */ -#define FCN_MD_PHY_ADR_REG_KER 0xc30 -#define FCN_MD_PHY_ADR_LBN 0 -#define FCN_MD_PHY_ADR_WIDTH 16 +static struct bit_basher_operations falcon_i2c_bit_ops = { + .read = falcon_i2c_bit_read, + .write = falcon_i2c_bit_write, +}; -/* PHY management ID register */ -#define FCN_MD_ID_REG_KER 0xc40 -#define FCN_MD_PRT_ADR_LBN 11 -#define FCN_MD_PRT_ADR_WIDTH 5 -#define FCN_MD_DEV_ADR_LBN 6 -#define FCN_MD_DEV_ADR_WIDTH 5 -/* PHY management status & mask register */ -#define FCN_MD_STAT_REG_KER 0xc50 -#define FCN_MD_BSY_LBN 0 -#define FCN_MD_BSY_WIDTH 1 +/******************************************************************************* + * + * + * MDIO access + * + * + *******************************************************************************/ -/* Port 0 and 1 MAC control registers */ -#define FCN_MAC0_CTRL_REG_KER 0xc80 -#define FCN_MAC1_CTRL_REG_KER 0xc90 -#define FCN_MAC_XOFF_VAL_LBN 16 -#define FCN_MAC_XOFF_VAL_WIDTH 16 -#define FCN_MAC_BCAD_ACPT_LBN 4 -#define FCN_MAC_BCAD_ACPT_WIDTH 1 -#define FCN_MAC_UC_PROM_LBN 3 -#define FCN_MAC_UC_PROM_WIDTH 1 -#define FCN_MAC_LINK_STATUS_LBN 2 -#define FCN_MAC_LINK_STATUS_WIDTH 1 -#define FCN_MAC_SPEED_LBN 0 -#define FCN_MAC_SPEED_WIDTH 2 +static int +falcon_gmii_wait ( struct efab_nic *efab ) +{ + efab_dword_t md_stat; + int count; -/* GMAC registers */ -#define FALCON_GMAC_REGBANK 0xe00 -#define FALCON_GMAC_REGBANK_SIZE 0x200 -#define FALCON_GMAC_REG_SIZE 0x10 + /* wait upto 10ms */ + for (count = 0; count < 1000; count++) { + falcon_readl ( efab, &md_stat, FCN_MD_STAT_REG_KER ); + if ( EFAB_DWORD_FIELD ( md_stat, FCN_MD_BSY ) == 0 ) { + if ( EFAB_DWORD_FIELD ( md_stat, FCN_MD_LNFL ) != 0 || + EFAB_DWORD_FIELD ( md_stat, FCN_MD_BSERR ) != 0 ) { + EFAB_ERR ( "Error from GMII access " + EFAB_DWORD_FMT"\n", + EFAB_DWORD_VAL ( md_stat )); + return -EIO; + } + return 0; + } + udelay(10); + } -/* XGMAC registers */ -#define FALCON_XMAC_REGBANK 0x1200 -#define FALCON_XMAC_REGBANK_SIZE 0x200 -#define FALCON_XMAC_REG_SIZE 0x10 + EFAB_ERR ( "Timed out waiting for GMII\n" ); + return -ETIMEDOUT; +} -/* XGMAC address register low */ -#define FCN_XM_ADR_LO_REG_MAC 0x00 -#define FCN_XM_ADR_3_LBN 24 -#define FCN_XM_ADR_3_WIDTH 8 -#define FCN_XM_ADR_2_LBN 16 -#define FCN_XM_ADR_2_WIDTH 8 -#define FCN_XM_ADR_1_LBN 8 -#define FCN_XM_ADR_1_WIDTH 8 -#define FCN_XM_ADR_0_LBN 0 -#define FCN_XM_ADR_0_WIDTH 8 +static void +falcon_mdio_write ( struct efab_nic *efab, int device, + int location, int value ) +{ + efab_oword_t reg; -/* XGMAC address register high */ -#define FCN_XM_ADR_HI_REG_MAC 0x01 -#define FCN_XM_ADR_5_LBN 8 -#define FCN_XM_ADR_5_WIDTH 8 -#define FCN_XM_ADR_4_LBN 0 -#define FCN_XM_ADR_4_WIDTH 8 + EFAB_TRACE ( "Writing GMII %d register %02x with %04x\n", + device, location, value ); -/* XGMAC global configuration - port 0*/ -#define FCN_XM_GLB_CFG_REG_MAC 0x02 -#define FCN_XM_RX_STAT_EN_LBN 11 -#define FCN_XM_RX_STAT_EN_WIDTH 1 -#define FCN_XM_TX_STAT_EN_LBN 10 -#define FCN_XM_TX_STAT_EN_WIDTH 1 -#define FCN_XM_RX_JUMBO_MODE_LBN 6 -#define FCN_XM_RX_JUMBO_MODE_WIDTH 1 -#define FCN_XM_CORE_RST_LBN 0 -#define FCN_XM_CORE_RST_WIDTH 1 + /* Check MII not currently being accessed */ + if ( falcon_gmii_wait ( efab ) ) + return; -/* XGMAC transmit configuration - port 0 */ -#define FCN_XM_TX_CFG_REG_MAC 0x03 -#define FCN_XM_IPG_LBN 16 -#define FCN_XM_IPG_WIDTH 4 -#define FCN_XM_FCNTL_LBN 10 -#define FCN_XM_FCNTL_WIDTH 1 -#define FCN_XM_TXCRC_LBN 8 -#define FCN_XM_TXCRC_WIDTH 1 -#define FCN_XM_AUTO_PAD_LBN 5 -#define FCN_XM_AUTO_PAD_WIDTH 1 -#define FCN_XM_TX_PRMBL_LBN 2 -#define FCN_XM_TX_PRMBL_WIDTH 1 -#define FCN_XM_TXEN_LBN 1 -#define FCN_XM_TXEN_WIDTH 1 + /* Write the address/ID register */ + EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, location ); + falcon_write ( efab, ®, FCN_MD_PHY_ADR_REG_KER ); -/* XGMAC receive configuration - port 0 */ -#define FCN_XM_RX_CFG_REG_MAC 0x04 -#define FCN_XM_PASS_CRC_ERR_LBN 25 -#define FCN_XM_PASS_CRC_ERR_WIDTH 1 -#define FCN_XM_AUTO_DEPAD_LBN 8 -#define FCN_XM_AUTO_DEPAD_WIDTH 1 -#define FCN_XM_RXEN_LBN 1 -#define FCN_XM_RXEN_WIDTH 1 + if ( efab->phy_10g ) { + /* clause45 */ + EFAB_POPULATE_OWORD_2 ( reg, + FCN_MD_PRT_ADR, efab->phy_addr, + FCN_MD_DEV_ADR, device ); + } + else { + /* clause22 */ + assert ( device == 0 ); -/* XGMAC transmit parameter register */ -#define FCN_XM_TX_PARAM_REG_MAC 0x0d -#define FCN_XM_TX_JUMBO_MODE_LBN 31 -#define FCN_XM_TX_JUMBO_MODE_WIDTH 1 -#define FCN_XM_MAX_TX_FRM_SIZE_LBN 16 -#define FCN_XM_MAX_TX_FRM_SIZE_WIDTH 14 + EFAB_POPULATE_OWORD_2 ( reg, + FCN_MD_PRT_ADR, efab->phy_addr, + FCN_MD_DEV_ADR, location ); + } + falcon_write ( efab, ®, FCN_MD_ID_REG_KER ); + -/* XGMAC receive parameter register */ -#define FCN_XM_RX_PARAM_REG_MAC 0x0e -#define FCN_XM_MAX_RX_FRM_SIZE_LBN 0 -#define FCN_XM_MAX_RX_FRM_SIZE_WIDTH 14 + /* Write data */ + EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_TXD, value ); + falcon_write ( efab, ®, FCN_MD_TXD_REG_KER ); -/* XAUI XGXS core status register */ -#define FCN_XX_ALIGN_DONE_LBN 20 -#define FCN_XX_ALIGN_DONE_WIDTH 1 -#define FCN_XX_CORE_STAT_REG_MAC 0x16 -#define FCN_XX_SYNC_STAT_LBN 16 -#define FCN_XX_SYNC_STAT_WIDTH 4 -#define FCN_XX_SYNC_STAT_DECODE_SYNCED 0xf -#define FCN_XX_COMMA_DET_LBN 12 -#define FCN_XX_COMMA_DET_WIDTH 4 -#define FCN_XX_COMMA_DET_RESET 0xf + EFAB_POPULATE_OWORD_2 ( reg, + FCN_MD_WRC, 1, + FCN_MD_GC, ( efab->phy_10g ? 0 : 1 ) ); + falcon_write ( efab, ®, FCN_MD_CS_REG_KER ); + + /* Wait for data to be written */ + if ( falcon_gmii_wait ( efab ) ) { + /* Abort the write operation */ + EFAB_POPULATE_OWORD_2 ( reg, + FCN_MD_WRC, 0, + FCN_MD_GC, 1); + falcon_write ( efab, ®, FCN_MD_CS_REG_KER ); + udelay(10); + } +} +static int +falcon_mdio_read ( struct efab_nic *efab, int device, int location ) +{ + efab_oword_t reg; + int value; -/* XGXS/XAUI powerdown/reset register */ -#define FCN_XX_PWR_RST_REG_MAC 0x10 -#define FCN_XX_RSTXGXSRX_EN_LBN 2 -#define FCN_XX_RSTXGXSRX_EN_WIDTH 1 -#define FCN_XX_RSTXGXSTX_EN_LBN 1 -#define FCN_XX_RSTXGXSTX_EN_WIDTH 1 -#define FCN_XX_RST_XX_EN_LBN 0 -#define FCN_XX_RST_XX_EN_WIDTH 1 + /* Check MII not currently being accessed */ + if ( falcon_gmii_wait ( efab ) ) + return -1; + + if ( efab->phy_10g ) { + /* clause45 */ + EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, location ); + falcon_write ( efab, ®, FCN_MD_PHY_ADR_REG_KER ); + + EFAB_POPULATE_OWORD_2 ( reg, + FCN_MD_PRT_ADR, efab->phy_addr, + FCN_MD_DEV_ADR, device ); + falcon_write ( efab, ®, FCN_MD_ID_REG_KER); + + /* request data to be read */ + EFAB_POPULATE_OWORD_2 ( reg, + FCN_MD_RDC, 1, + FCN_MD_GC, 0 ); + } + else { + /* clause22 */ + assert ( device == 0 ); + + EFAB_POPULATE_OWORD_2 ( reg, + FCN_MD_PRT_ADR, efab->phy_addr, + FCN_MD_DEV_ADR, location ); + falcon_write ( efab, ®, FCN_MD_ID_REG_KER ); + + /* Request data to be read */ + EFAB_POPULATE_OWORD_2 ( reg, + FCN_MD_RIC, 1, + FCN_MD_GC, 1 ); + } -/* Receive descriptor pointer table */ -#define FCN_RX_DESC_PTR_TBL_KER 0x11800 -#define FCN_RX_DESCQ_BUF_BASE_ID_LBN 36 -#define FCN_RX_DESCQ_BUF_BASE_ID_WIDTH 20 -#define FCN_RX_DESCQ_EVQ_ID_LBN 24 -#define FCN_RX_DESCQ_EVQ_ID_WIDTH 12 -#define FCN_RX_DESCQ_OWNER_ID_LBN 10 -#define FCN_RX_DESCQ_OWNER_ID_WIDTH 14 -#define FCN_RX_DESCQ_SIZE_LBN 3 -#define FCN_RX_DESCQ_SIZE_WIDTH 2 -#define FCN_RX_DESCQ_SIZE_4K 3 -#define FCN_RX_DESCQ_SIZE_2K 2 -#define FCN_RX_DESCQ_SIZE_1K 1 -#define FCN_RX_DESCQ_SIZE_512 0 -#define FCN_RX_DESCQ_TYPE_LBN 2 -#define FCN_RX_DESCQ_TYPE_WIDTH 1 -#define FCN_RX_DESCQ_JUMBO_LBN 1 -#define FCN_RX_DESCQ_JUMBO_WIDTH 1 -#define FCN_RX_DESCQ_EN_LBN 0 -#define FCN_RX_DESCQ_EN_WIDTH 1 + falcon_write ( efab, ®, FCN_MD_CS_REG_KER ); + + /* Wait for data to become available */ + if ( falcon_gmii_wait ( efab ) ) { + /* Abort the read operation */ + EFAB_POPULATE_OWORD_2 ( reg, + FCN_MD_RIC, 0, + FCN_MD_GC, 1 ); + falcon_write ( efab, ®, FCN_MD_CS_REG_KER ); + udelay ( 10 ); + value = -1; + } + else { + /* Read the data */ + falcon_read ( efab, ®, FCN_MD_RXD_REG_KER ); + value = EFAB_OWORD_FIELD ( reg, FCN_MD_RXD ); + } -/* Transmit descriptor pointer table */ -#define FCN_TX_DESC_PTR_TBL_KER 0x11900 -#define FCN_TX_DESCQ_EN_LBN 88 -#define FCN_TX_DESCQ_EN_WIDTH 1 -#define FCN_TX_DESCQ_BUF_BASE_ID_LBN 36 -#define FCN_TX_DESCQ_BUF_BASE_ID_WIDTH 20 -#define FCN_TX_DESCQ_EVQ_ID_LBN 24 -#define FCN_TX_DESCQ_EVQ_ID_WIDTH 12 -#define FCN_TX_DESCQ_OWNER_ID_LBN 10 -#define FCN_TX_DESCQ_OWNER_ID_WIDTH 14 -#define FCN_TX_DESCQ_SIZE_LBN 3 -#define FCN_TX_DESCQ_SIZE_WIDTH 2 -#define FCN_TX_DESCQ_SIZE_4K 3 -#define FCN_TX_DESCQ_SIZE_2K 2 -#define FCN_TX_DESCQ_SIZE_1K 1 -#define FCN_TX_DESCQ_SIZE_512 0 -#define FCN_TX_DESCQ_TYPE_LBN 1 -#define FCN_TX_DESCQ_TYPE_WIDTH 2 -#define FCN_TX_DESCQ_FLUSH_LBN 0 -#define FCN_TX_DESCQ_FLUSH_WIDTH 1 + EFAB_TRACE ( "Read from GMII %d register %02x, got %04x\n", + device, location, value ); -/* Event queue pointer */ -#define FCN_EVQ_PTR_TBL_KER 0x11a00 -#define FCN_EVQ_EN_LBN 23 -#define FCN_EVQ_EN_WIDTH 1 -#define FCN_EVQ_SIZE_LBN 20 -#define FCN_EVQ_SIZE_WIDTH 3 -#define FCN_EVQ_SIZE_32K 6 -#define FCN_EVQ_SIZE_16K 5 -#define FCN_EVQ_SIZE_8K 4 -#define FCN_EVQ_SIZE_4K 3 -#define FCN_EVQ_SIZE_2K 2 -#define FCN_EVQ_SIZE_1K 1 -#define FCN_EVQ_SIZE_512 0 -#define FCN_EVQ_BUF_BASE_ID_LBN 0 -#define FCN_EVQ_BUF_BASE_ID_WIDTH 20 + return value; +} -/* Event queue read pointer */ -#define FCN_EVQ_RPTR_REG_KER 0x11b00 -#define FCN_EVQ_RPTR_LBN 0 -#define FCN_EVQ_RPTR_WIDTH 14 -#define FCN_EVQ_RPTR_REG_KER_DWORD ( FCN_EVQ_RPTR_REG_KER + 0 ) -#define FCN_EVQ_RPTR_DWORD_LBN 0 -#define FCN_EVQ_RPTR_DWORD_WIDTH 14 +/******************************************************************************* + * + * + * MAC wrapper + * + * + *******************************************************************************/ -/* Special buffer descriptors */ -#define FCN_BUF_FULL_TBL_KER 0x18000 -#define FCN_IP_DAT_BUF_SIZE_LBN 50 -#define FCN_IP_DAT_BUF_SIZE_WIDTH 1 -#define FCN_IP_DAT_BUF_SIZE_8K 1 -#define FCN_IP_DAT_BUF_SIZE_4K 0 -#define FCN_BUF_ADR_FBUF_LBN 14 -#define FCN_BUF_ADR_FBUF_WIDTH 34 -#define FCN_BUF_OWNER_ID_FBUF_LBN 0 -#define FCN_BUF_OWNER_ID_FBUF_WIDTH 14 +static void +falcon_reconfigure_mac_wrapper ( struct efab_nic *efab ) +{ + efab_oword_t reg; + int link_speed; -/** Offset of a GMAC register within Falcon */ -#define FALCON_GMAC_REG( efab, mac_reg ) \ - ( FALCON_GMAC_REGBANK + \ - ( (efab)->port * FALCON_GMAC_REGBANK_SIZE ) + \ - ( (mac_reg) * FALCON_GMAC_REG_SIZE ) ) + if ( efab->link_options & LPA_10000 ) { + link_speed = 0x3; + } else if ( efab->link_options & LPA_1000 ) { + link_speed = 0x2; + } else if ( efab->link_options & LPA_100 ) { + link_speed = 0x1; + } else { + link_speed = 0x0; + } + EFAB_POPULATE_OWORD_5 ( reg, + FCN_MAC_XOFF_VAL, 0xffff /* datasheet */, + FCN_MAC_BCAD_ACPT, 1, + FCN_MAC_UC_PROM, 0, + FCN_MAC_LINK_STATUS, 1, + FCN_MAC_SPEED, link_speed ); -/** Offset of an XMAC register within Falcon */ -#define FALCON_XMAC_REG( efab_port, mac_reg ) \ - ( FALCON_XMAC_REGBANK + \ - ( (efab_port)->port * FALCON_XMAC_REGBANK_SIZE ) + \ - ( (mac_reg) * FALCON_XMAC_REG_SIZE ) ) + falcon_write ( efab, ®, FCN_MAC0_CTRL_REG_KER ); +} -#define FCN_MAC_DATA_LBN 0 -#define FCN_MAC_DATA_WIDTH 32 +/******************************************************************************* + * + * + * GMAC handling + * + * + *******************************************************************************/ -/* Transmit descriptor */ -#define FCN_TX_KER_PORT_LBN 63 -#define FCN_TX_KER_PORT_WIDTH 1 -#define FCN_TX_KER_BYTE_CNT_LBN 48 -#define FCN_TX_KER_BYTE_CNT_WIDTH 14 -#define FCN_TX_KER_BUF_ADR_LBN 0 -#define FCN_TX_KER_BUF_ADR_WIDTH EFAB_DMA_TYPE_WIDTH ( 46 ) +/* GMAC configuration register 1 */ +#define GM_CFG1_REG_MAC 0x00 +#define GM_SW_RST_LBN 31 +#define GM_SW_RST_WIDTH 1 +#define GM_RX_FC_EN_LBN 5 +#define GM_RX_FC_EN_WIDTH 1 +#define GM_TX_FC_EN_LBN 4 +#define GM_TX_FC_EN_WIDTH 1 +#define GM_RX_EN_LBN 2 +#define GM_RX_EN_WIDTH 1 +#define GM_TX_EN_LBN 0 +#define GM_TX_EN_WIDTH 1 +/* GMAC configuration register 2 */ +#define GM_CFG2_REG_MAC 0x01 +#define GM_PAMBL_LEN_LBN 12 +#define GM_PAMBL_LEN_WIDTH 4 +#define GM_IF_MODE_LBN 8 +#define GM_IF_MODE_WIDTH 2 +#define GM_PAD_CRC_EN_LBN 2 +#define GM_PAD_CRC_EN_WIDTH 1 +#define GM_FD_LBN 0 +#define GM_FD_WIDTH 1 -/* Receive descriptor */ -#define FCN_RX_KER_BUF_SIZE_LBN 48 -#define FCN_RX_KER_BUF_SIZE_WIDTH 14 -#define FCN_RX_KER_BUF_ADR_LBN 0 -#define FCN_RX_KER_BUF_ADR_WIDTH EFAB_DMA_TYPE_WIDTH ( 46 ) +/* GMAC maximum frame length register */ +#define GM_MAX_FLEN_REG_MAC 0x04 +#define GM_MAX_FLEN_LBN 0 +#define GM_MAX_FLEN_WIDTH 16 -/* Event queue entries */ -#define FCN_EV_CODE_LBN 60 -#define FCN_EV_CODE_WIDTH 4 -#define FCN_RX_IP_EV_DECODE 0 -#define FCN_TX_IP_EV_DECODE 2 -#define FCN_DRIVER_EV_DECODE 5 +/* GMAC MII management configuration register */ +#define GM_MII_MGMT_CFG_REG_MAC 0x08 +#define GM_MGMT_CLK_SEL_LBN 0 +#define GM_MGMT_CLK_SEL_WIDTH 3 -/* Receive events */ -#define FCN_RX_EV_PKT_OK_LBN 56 -#define FCN_RX_EV_PKT_OK_WIDTH 1 -#define FCN_RX_PORT_LBN 30 -#define FCN_RX_PORT_WIDTH 1 -#define FCN_RX_EV_BYTE_CNT_LBN 16 -#define FCN_RX_EV_BYTE_CNT_WIDTH 14 -#define FCN_RX_EV_DESC_PTR_LBN 0 -#define FCN_RX_EV_DESC_PTR_WIDTH 12 +/* GMAC MII management command register */ +#define GM_MII_MGMT_CMD_REG_MAC 0x09 +#define GM_MGMT_SCAN_CYC_LBN 1 +#define GM_MGMT_SCAN_CYC_WIDTH 1 +#define GM_MGMT_RD_CYC_LBN 0 +#define GM_MGMT_RD_CYC_WIDTH 1 + +/* GMAC MII management address register */ +#define GM_MII_MGMT_ADR_REG_MAC 0x0a +#define GM_MGMT_PHY_ADDR_LBN 8 +#define GM_MGMT_PHY_ADDR_WIDTH 5 +#define GM_MGMT_REG_ADDR_LBN 0 +#define GM_MGMT_REG_ADDR_WIDTH 5 + +/* GMAC MII management control register */ +#define GM_MII_MGMT_CTL_REG_MAC 0x0b +#define GM_MGMT_CTL_LBN 0 +#define GM_MGMT_CTL_WIDTH 16 + +/* GMAC MII management status register */ +#define GM_MII_MGMT_STAT_REG_MAC 0x0c +#define GM_MGMT_STAT_LBN 0 +#define GM_MGMT_STAT_WIDTH 16 + +/* GMAC MII management indicators register */ +#define GM_MII_MGMT_IND_REG_MAC 0x0d +#define GM_MGMT_BUSY_LBN 0 +#define GM_MGMT_BUSY_WIDTH 1 + +/* GMAC station address register 1 */ +#define GM_ADR1_REG_MAC 0x10 +#define GM_HWADDR_5_LBN 24 +#define GM_HWADDR_5_WIDTH 8 +#define GM_HWADDR_4_LBN 16 +#define GM_HWADDR_4_WIDTH 8 +#define GM_HWADDR_3_LBN 8 +#define GM_HWADDR_3_WIDTH 8 +#define GM_HWADDR_2_LBN 0 +#define GM_HWADDR_2_WIDTH 8 + +/* GMAC station address register 2 */ +#define GM_ADR2_REG_MAC 0x11 +#define GM_HWADDR_1_LBN 24 +#define GM_HWADDR_1_WIDTH 8 +#define GM_HWADDR_0_LBN 16 +#define GM_HWADDR_0_WIDTH 8 + +/* GMAC FIFO configuration register 0 */ +#define GMF_CFG0_REG_MAC 0x12 +#define GMF_FTFENREQ_LBN 12 +#define GMF_FTFENREQ_WIDTH 1 +#define GMF_STFENREQ_LBN 11 +#define GMF_STFENREQ_WIDTH 1 +#define GMF_FRFENREQ_LBN 10 +#define GMF_FRFENREQ_WIDTH 1 +#define GMF_SRFENREQ_LBN 9 +#define GMF_SRFENREQ_WIDTH 1 +#define GMF_WTMENREQ_LBN 8 +#define GMF_WTMENREQ_WIDTH 1 + +/* GMAC FIFO configuration register 1 */ +#define GMF_CFG1_REG_MAC 0x13 +#define GMF_CFGFRTH_LBN 16 +#define GMF_CFGFRTH_WIDTH 5 +#define GMF_CFGXOFFRTX_LBN 0 +#define GMF_CFGXOFFRTX_WIDTH 16 + +/* GMAC FIFO configuration register 2 */ +#define GMF_CFG2_REG_MAC 0x14 +#define GMF_CFGHWM_LBN 16 +#define GMF_CFGHWM_WIDTH 6 +#define GMF_CFGLWM_LBN 0 +#define GMF_CFGLWM_WIDTH 6 + +/* GMAC FIFO configuration register 3 */ +#define GMF_CFG3_REG_MAC 0x15 +#define GMF_CFGHWMFT_LBN 16 +#define GMF_CFGHWMFT_WIDTH 6 +#define GMF_CFGFTTH_LBN 0 +#define GMF_CFGFTTH_WIDTH 6 + +/* GMAC FIFO configuration register 4 */ +#define GMF_CFG4_REG_MAC 0x16 +#define GMF_HSTFLTRFRM_PAUSE_LBN 12 +#define GMF_HSTFLTRFRM_PAUSE_WIDTH 12 + +/* GMAC FIFO configuration register 5 */ +#define GMF_CFG5_REG_MAC 0x17 +#define GMF_CFGHDPLX_LBN 22 +#define GMF_CFGHDPLX_WIDTH 1 +#define GMF_CFGBYTMODE_LBN 19 +#define GMF_CFGBYTMODE_WIDTH 1 +#define GMF_HSTDRPLT64_LBN 18 +#define GMF_HSTDRPLT64_WIDTH 1 +#define GMF_HSTFLTRFRMDC_PAUSE_LBN 12 +#define GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1 + +static void +falcon_gmac_writel ( struct efab_nic *efab, efab_dword_t *value, + unsigned int mac_reg ) +{ + efab_oword_t temp; + + EFAB_POPULATE_OWORD_1 ( temp, FCN_MAC_DATA, + EFAB_DWORD_FIELD ( *value, FCN_MAC_DATA ) ); + falcon_write ( efab, &temp, FALCON_GMAC_REG ( efab, mac_reg ) ); +} + +static void +falcon_gmac_readl ( struct efab_nic *efab, efab_dword_t *value, + unsigned int mac_reg ) +{ + efab_oword_t temp; + + falcon_read ( efab, &temp, FALCON_GMAC_REG ( efab, mac_reg ) ); + EFAB_POPULATE_DWORD_1 ( *value, FCN_MAC_DATA, + EFAB_OWORD_FIELD ( temp, FCN_MAC_DATA ) ); +} + +static void +mentormac_reset ( struct efab_nic *efab ) +{ + efab_dword_t reg; + + /* Take into reset */ + EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 1 ); + falcon_gmac_writel ( efab, ®, GM_CFG1_REG_MAC ); + udelay ( 1000 ); + + /* Take out of reset */ + EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 0 ); + falcon_gmac_writel ( efab, ®, GM_CFG1_REG_MAC ); + udelay ( 1000 ); + + /* Configure GMII interface so PHY is accessible. Note that + * GMII interface is connected only to port 0, and that on + * Falcon this is a no-op. + */ + EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_CLK_SEL, 0x4 ); + falcon_gmac_writel ( efab, ®, GM_MII_MGMT_CFG_REG_MAC ); + udelay ( 10 ); +} + +static void +mentormac_init ( struct efab_nic *efab ) +{ + int pause, if_mode, full_duplex, bytemode, half_duplex; + efab_dword_t reg; + + /* Configuration register 1 */ + pause = ( efab->link_options & LPA_PAUSE ) ? 1 : 0; + if ( ! ( efab->link_options & LPA_DUPLEX ) ) { + /* Half-duplex operation requires TX flow control */ + pause = 1; + } + EFAB_POPULATE_DWORD_4 ( reg, + GM_TX_EN, 1, + GM_TX_FC_EN, pause, + GM_RX_EN, 1, + GM_RX_FC_EN, 1 ); + falcon_gmac_writel ( efab, ®, GM_CFG1_REG_MAC ); + udelay ( 10 ); + + /* Configuration register 2 */ + if_mode = ( efab->link_options & LPA_1000 ) ? 2 : 1; + full_duplex = ( efab->link_options & LPA_DUPLEX ) ? 1 : 0; + EFAB_POPULATE_DWORD_4 ( reg, + GM_IF_MODE, if_mode, + GM_PAD_CRC_EN, 1, + GM_FD, full_duplex, + GM_PAMBL_LEN, 0x7 /* ? */ ); + falcon_gmac_writel ( efab, ®, GM_CFG2_REG_MAC ); + udelay ( 10 ); + + /* Max frame len register */ + EFAB_POPULATE_DWORD_1 ( reg, GM_MAX_FLEN, + EFAB_MAX_FRAME_LEN ( ETH_FRAME_LEN ) ); + falcon_gmac_writel ( efab, ®, GM_MAX_FLEN_REG_MAC ); + udelay ( 10 ); + + /* FIFO configuration register 0 */ + EFAB_POPULATE_DWORD_5 ( reg, + GMF_FTFENREQ, 1, + GMF_STFENREQ, 1, + GMF_FRFENREQ, 1, + GMF_SRFENREQ, 1, + GMF_WTMENREQ, 1 ); + falcon_gmac_writel ( efab, ®, GMF_CFG0_REG_MAC ); + udelay ( 10 ); + + /* FIFO configuration register 1 */ + EFAB_POPULATE_DWORD_2 ( reg, + GMF_CFGFRTH, 0x12, + GMF_CFGXOFFRTX, 0xffff ); + falcon_gmac_writel ( efab, ®, GMF_CFG1_REG_MAC ); + udelay ( 10 ); + + /* FIFO configuration register 2 */ + EFAB_POPULATE_DWORD_2 ( reg, + GMF_CFGHWM, 0x3f, + GMF_CFGLWM, 0xa ); + falcon_gmac_writel ( efab, ®, GMF_CFG2_REG_MAC ); + udelay ( 10 ); + + /* FIFO configuration register 3 */ + EFAB_POPULATE_DWORD_2 ( reg, + GMF_CFGHWMFT, 0x1c, + GMF_CFGFTTH, 0x08 ); + falcon_gmac_writel ( efab, ®, GMF_CFG3_REG_MAC ); + udelay ( 10 ); + + /* FIFO configuration register 4 */ + EFAB_POPULATE_DWORD_1 ( reg, GMF_HSTFLTRFRM_PAUSE, 1 ); + falcon_gmac_writel ( efab, ®, GMF_CFG4_REG_MAC ); + udelay ( 10 ); + + /* FIFO configuration register 5 */ + bytemode = ( efab->link_options & LPA_1000 ) ? 1 : 0; + half_duplex = ( efab->link_options & LPA_DUPLEX ) ? 0 : 1; + falcon_gmac_readl ( efab, ®, GMF_CFG5_REG_MAC ); + EFAB_SET_DWORD_FIELD ( reg, GMF_CFGBYTMODE, bytemode ); + EFAB_SET_DWORD_FIELD ( reg, GMF_CFGHDPLX, half_duplex ); + EFAB_SET_DWORD_FIELD ( reg, GMF_HSTDRPLT64, half_duplex ); + EFAB_SET_DWORD_FIELD ( reg, GMF_HSTFLTRFRMDC_PAUSE, 0 ); + falcon_gmac_writel ( efab, ®, GMF_CFG5_REG_MAC ); + udelay ( 10 ); + + /* MAC address */ + EFAB_POPULATE_DWORD_4 ( reg, + GM_HWADDR_5, efab->mac_addr[5], + GM_HWADDR_4, efab->mac_addr[4], + GM_HWADDR_3, efab->mac_addr[3], + GM_HWADDR_2, efab->mac_addr[2] ); + falcon_gmac_writel ( efab, ®, GM_ADR1_REG_MAC ); + udelay ( 10 ); + EFAB_POPULATE_DWORD_2 ( reg, + GM_HWADDR_1, efab->mac_addr[1], + GM_HWADDR_0, efab->mac_addr[0] ); + falcon_gmac_writel ( efab, ®, GM_ADR2_REG_MAC ); + udelay ( 10 ); +} -/* Transmit events */ -#define FCN_TX_EV_DESC_PTR_LBN 0 -#define FCN_TX_EV_DESC_PTR_WIDTH 12 +static int +falcon_init_gmac ( struct efab_nic *efab ) +{ + /* Reset the MAC */ + mentormac_reset ( efab ); -/* Fixed special buffer numbers to use */ -#define FALCON_EVQ_ID 0 -#define FALCON_TXD_ID 1 -#define FALCON_RXD_ID 2 + /* Initialise PHY */ + efab->phy_op->init ( efab ); -#if FALCON_USE_IO_BAR + /* check the link is up */ + if ( !efab->link_up ) + return -EAGAIN; -/* Write dword via the I/O BAR */ -static inline void _falcon_writel ( struct efab_nic *efab, uint32_t value, - unsigned int reg ) { - outl ( reg, efab->iobase + FCN_IOM_IND_ADR_REG ); - outl ( value, efab->iobase + FCN_IOM_IND_DAT_REG ); -} + /* Initialise MAC */ + mentormac_init ( efab ); -/* Read dword via the I/O BAR */ -static inline uint32_t _falcon_readl ( struct efab_nic *efab, - unsigned int reg ) { - outl ( reg, efab->iobase + FCN_IOM_IND_ADR_REG ); - return inl ( efab->iobase + FCN_IOM_IND_DAT_REG ); + /* reconfigure the MAC wrapper */ + falcon_reconfigure_mac_wrapper ( efab ); + + return 0; } -#else /* FALCON_USE_IO_BAR */ +static struct efab_mac_operations falcon_gmac_operations = { + .init = falcon_init_gmac, +}; -#define _falcon_writel( efab, value, reg ) \ - writel ( (value), (efab)->membase + (reg) ) -#define _falcon_readl( efab, reg ) readl ( (efab)->membase + (reg) ) -#endif /* FALCON_USE_IO_BAR */ +/******************************************************************************* + * + * + * XMAC handling + * + * + *******************************************************************************/ /** - * Write to a Falcon register + * Write dword to a Falcon XMAC register * */ -static inline void falcon_write ( struct efab_nic *efab, efab_oword_t *value, - unsigned int reg ) { - - EFAB_REGDUMP ( "Writing register %x with " EFAB_OWORD_FMT "\n", - reg, EFAB_OWORD_VAL ( *value ) ); +static void +falcon_xmac_writel ( struct efab_nic *efab, efab_dword_t *value, + unsigned int mac_reg ) +{ + efab_oword_t temp; - _falcon_writel ( efab, value->u32[0], reg + 0 ); - _falcon_writel ( efab, value->u32[1], reg + 4 ); - _falcon_writel ( efab, value->u32[2], reg + 8 ); - _falcon_writel ( efab, value->u32[3], reg + 12 ); - wmb(); + EFAB_POPULATE_OWORD_1 ( temp, FCN_MAC_DATA, + EFAB_DWORD_FIELD ( *value, FCN_MAC_DATA ) ); + falcon_write ( efab, &temp, + FALCON_XMAC_REG ( efab, mac_reg ) ); } /** - * Write to Falcon SRAM + * Read dword from a Falcon XMAC register * */ -static inline void falcon_write_sram ( struct efab_nic *efab, - efab_qword_t *value, - unsigned int index ) { - unsigned int reg = ( FCN_BUF_FULL_TBL_KER + - ( index * sizeof ( *value ) ) ); - - EFAB_REGDUMP ( "Writing SRAM register %x with " EFAB_QWORD_FMT "\n", - reg, EFAB_QWORD_VAL ( *value ) ); +static void +falcon_xmac_readl ( struct efab_nic *efab, efab_dword_t *value, + unsigned int mac_reg ) +{ + efab_oword_t temp; - _falcon_writel ( efab, value->u32[0], reg + 0 ); - _falcon_writel ( efab, value->u32[1], reg + 4 ); - wmb(); + falcon_read ( efab, &temp, + FALCON_XMAC_REG ( efab, mac_reg ) ); + EFAB_POPULATE_DWORD_1 ( *value, FCN_MAC_DATA, + EFAB_OWORD_FIELD ( temp, FCN_MAC_DATA ) ); } /** - * Write dword to Falcon register that allows partial writes - * + * Configure Falcon XAUI output */ -static inline void falcon_writel ( struct efab_nic *efab, efab_dword_t *value, - unsigned int reg ) { - EFAB_REGDUMP ( "Writing partial register %x with " EFAB_DWORD_FMT "\n", - reg, EFAB_DWORD_VAL ( *value ) ); - _falcon_writel ( efab, value->u32[0], reg ); +static void +falcon_setup_xaui ( struct efab_nic *efab ) +{ + efab_dword_t sdctl, txdrv; + + falcon_xmac_readl ( efab, &sdctl, FCN_XX_SD_CTL_REG_MAC ); + EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT ); + EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVD, XX_SD_CTL_DRV_DEFAULT ); + EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT ); + EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVC, XX_SD_CTL_DRV_DEFAULT ); + EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT ); + EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVB, XX_SD_CTL_DRV_DEFAULT ); + EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT ); + EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVA, XX_SD_CTL_DRV_DEFAULT ); + falcon_xmac_writel ( efab, &sdctl, FCN_XX_SD_CTL_REG_MAC ); + + EFAB_POPULATE_DWORD_8 ( txdrv, + FCN_XX_DEQD, XX_TXDRV_DEQ_DEFAULT, + FCN_XX_DEQC, XX_TXDRV_DEQ_DEFAULT, + FCN_XX_DEQB, XX_TXDRV_DEQ_DEFAULT, + FCN_XX_DEQA, XX_TXDRV_DEQ_DEFAULT, + FCN_XX_DTXD, XX_TXDRV_DTX_DEFAULT, + FCN_XX_DTXC, XX_TXDRV_DTX_DEFAULT, + FCN_XX_DTXB, XX_TXDRV_DTX_DEFAULT, + FCN_XX_DTXA, XX_TXDRV_DTX_DEFAULT); + falcon_xmac_writel ( efab, &txdrv, FCN_XX_TXDRV_CTL_REG_MAC); } -/** - * Read from a Falcon register - * - */ -static inline void falcon_read ( struct efab_nic *efab, efab_oword_t *value, - unsigned int reg ) { - value->u32[0] = _falcon_readl ( efab, reg + 0 ); - value->u32[1] = _falcon_readl ( efab, reg + 4 ); - value->u32[2] = _falcon_readl ( efab, reg + 8 ); - value->u32[3] = _falcon_readl ( efab, reg + 12 ); +static int +falcon_xgmii_status ( struct efab_nic *efab ) +{ + efab_dword_t reg; - EFAB_REGDUMP ( "Read from register %x, got " EFAB_OWORD_FMT "\n", - reg, EFAB_OWORD_VAL ( *value ) ); + if ( efab->pci_revision < FALCON_REV_B0 ) + return 1; + /* The ISR latches, so clear it and re-read */ + falcon_xmac_readl ( efab, ®, FCN_XM_MGT_INT_REG_MAC_B0 ); + falcon_xmac_readl ( efab, ®, FCN_XM_MGT_INT_REG_MAC_B0 ); + + if ( EFAB_DWORD_FIELD ( reg, FCN_XM_LCLFLT ) || + EFAB_DWORD_FIELD ( reg, FCN_XM_RMTFLT ) ) { + EFAB_TRACE ( "MGT_INT: "EFAB_DWORD_FMT"\n", + EFAB_DWORD_VAL ( reg ) ); + return 0; + } + + return 1; } -/** - * Read from Falcon SRAM - * - */ -static inline void falcon_read_sram ( struct efab_nic *efab, - efab_qword_t *value, - unsigned int index ) { - unsigned int reg = ( FCN_BUF_FULL_TBL_KER + - ( index * sizeof ( *value ) ) ); +static void +falcon_mask_status_intr ( struct efab_nic *efab, int enable ) +{ + efab_dword_t reg; - value->u32[0] = _falcon_readl ( efab, reg + 0 ); - value->u32[1] = _falcon_readl ( efab, reg + 4 ); - EFAB_REGDUMP ( "Read from SRAM register %x, got " EFAB_QWORD_FMT "\n", - reg, EFAB_QWORD_VAL ( *value ) ); -} + if ( efab->pci_revision < FALCON_REV_B0 ) + return; -/** - * Read dword from a portion of a Falcon register - * - */ -static inline void falcon_readl ( struct efab_nic *efab, efab_dword_t *value, - unsigned int reg ) { - value->u32[0] = _falcon_readl ( efab, reg ); - EFAB_REGDUMP ( "Read from register %x, got " EFAB_DWORD_FMT "\n", - reg, EFAB_DWORD_VAL ( *value ) ); + /* Flush the ISR */ + if ( enable ) + falcon_xmac_readl ( efab, ®, FCN_XM_MGT_INT_REG_MAC_B0 ); + + EFAB_POPULATE_DWORD_2 ( reg, + FCN_XM_MSK_RMTFLT, !enable, + FCN_XM_MSK_LCLFLT, !enable); + falcon_xmac_readl ( efab, ®, FCN_XM_MGT_INT_MSK_REG_MAC_B0 ); } /** - * Verified write to Falcon SRAM + * Reset 10G MAC connected to port * */ -static inline void falcon_write_sram_verify ( struct efab_nic *efab, - efab_qword_t *value, - unsigned int index ) { - efab_qword_t verify; - - falcon_write_sram ( efab, value, index ); - udelay ( 1000 ); - falcon_read_sram ( efab, &verify, index ); - if ( memcmp ( &verify, value, sizeof ( verify ) ) != 0 ) { - EFAB_ERR ( "SRAM index %x failure: wrote " EFAB_QWORD_FMT - " got " EFAB_QWORD_FMT "\n", index, - EFAB_QWORD_VAL ( *value ), - EFAB_QWORD_VAL ( verify ) ); +static int +falcon_reset_xmac ( struct efab_nic *efab ) +{ + efab_dword_t reg; + int count; + + EFAB_POPULATE_DWORD_1 ( reg, FCN_XM_CORE_RST, 1 ); + falcon_xmac_writel ( efab, ®, FCN_XM_GLB_CFG_REG_MAC ); + + for ( count = 0 ; count < 1000 ; count++ ) { + udelay ( 10 ); + falcon_xmac_readl ( efab, ®, + FCN_XM_GLB_CFG_REG_MAC ); + if ( EFAB_DWORD_FIELD ( reg, FCN_XM_CORE_RST ) == 0 ) + return 0; } + return -ETIMEDOUT; } -/** - * Get memory base - * - */ -static void falcon_get_membase ( struct efab_nic *efab ) { - unsigned long membase_phys; - membase_phys = pci_bar_start ( efab->pci, PCI_BASE_ADDRESS_2 ); - efab->membase = ioremap ( membase_phys, 0x20000 ); -} +static int +falcon_reset_xaui ( struct efab_nic *efab ) +{ + efab_dword_t reg; + int count; -#define FCN_DUMP_REG( efab, _reg ) do { \ - efab_oword_t reg; \ - falcon_read ( efab, ®, _reg ); \ - EFAB_LOG ( #_reg " = " EFAB_OWORD_FMT "\n", \ - EFAB_OWORD_VAL ( reg ) ); \ - } while ( 0 ); + if (!efab->is_asic) + return 0; -#define FCN_DUMP_MAC_REG( efab, _mac_reg ) do { \ - efab_dword_t reg; \ - efab->mac_op->mac_readl ( efab, ®, _mac_reg ); \ - EFAB_LOG ( #_mac_reg " = " EFAB_DWORD_FMT "\n", \ - EFAB_DWORD_VAL ( reg ) ); \ - } while ( 0 ); + EFAB_POPULATE_DWORD_1 ( reg, FCN_XX_RST_XX_EN, 1 ); + falcon_xmac_writel ( efab, ®, FCN_XX_PWR_RST_REG_MAC ); -/** - * Dump register contents (for debugging) - * - * Marked as static inline so that it will not be compiled in if not - * used. - */ -static inline void falcon_dump_regs ( struct efab_nic *efab ) { - FCN_DUMP_REG ( efab, FCN_INT_EN_REG_KER ); - FCN_DUMP_REG ( efab, FCN_INT_ADR_REG_KER ); - FCN_DUMP_REG ( efab, FCN_GLB_CTL_REG_KER ); - FCN_DUMP_REG ( efab, FCN_TIMER_CMD_REG_KER ); - FCN_DUMP_REG ( efab, FCN_SRM_RX_DC_CFG_REG_KER ); - FCN_DUMP_REG ( efab, FCN_SRM_TX_DC_CFG_REG_KER ); - FCN_DUMP_REG ( efab, FCN_RX_FILTER_CTL_REG_KER ); - FCN_DUMP_REG ( efab, FCN_RX_DC_CFG_REG_KER ); - FCN_DUMP_REG ( efab, FCN_TX_DC_CFG_REG_KER ); - FCN_DUMP_REG ( efab, FCN_MAC0_CTRL_REG_KER ); - FCN_DUMP_REG ( efab, FCN_MAC1_CTRL_REG_KER ); - FCN_DUMP_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ); - FCN_DUMP_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ); - FCN_DUMP_REG ( efab, FCN_EVQ_PTR_TBL_KER ); - FCN_DUMP_MAC_REG ( efab, GM_CFG1_REG_MAC ); - FCN_DUMP_MAC_REG ( efab, GM_CFG2_REG_MAC ); - FCN_DUMP_MAC_REG ( efab, GM_MAX_FLEN_REG_MAC ); - FCN_DUMP_MAC_REG ( efab, GM_MII_MGMT_CFG_REG_MAC ); - FCN_DUMP_MAC_REG ( efab, GM_ADR1_REG_MAC ); - FCN_DUMP_MAC_REG ( efab, GM_ADR2_REG_MAC ); - FCN_DUMP_MAC_REG ( efab, GMF_CFG0_REG_MAC ); - FCN_DUMP_MAC_REG ( efab, GMF_CFG1_REG_MAC ); - FCN_DUMP_MAC_REG ( efab, GMF_CFG2_REG_MAC ); - FCN_DUMP_MAC_REG ( efab, GMF_CFG3_REG_MAC ); - FCN_DUMP_MAC_REG ( efab, GMF_CFG4_REG_MAC ); - FCN_DUMP_MAC_REG ( efab, GMF_CFG5_REG_MAC ); + /* Give some time for the link to establish */ + for (count = 0; count < 1000; count++) { /* wait upto 10ms */ + falcon_xmac_readl ( efab, ®, FCN_XX_PWR_RST_REG_MAC ); + if ( EFAB_DWORD_FIELD ( reg, FCN_XX_RST_XX_EN ) == 0 ) { + falcon_setup_xaui ( efab ); + return 0; + } + udelay(10); + } + EFAB_ERR ( "timed out waiting for XAUI/XGXS reset\n" ); + return -ETIMEDOUT; } -/** - * Create special buffer - * - */ -static void falcon_create_special_buffer ( struct efab_nic *efab, - void *addr, unsigned int index ) { - efab_qword_t buf_desc; - unsigned long dma_addr; +static int +falcon_xaui_link_ok ( struct efab_nic *efab ) +{ + efab_dword_t reg; + int align_done, lane_status, sync; + int has_phyxs; + int link_ok = 1; + + /* Read Falcon XAUI side */ + if ( efab->is_asic ) { + /* Read link status */ + falcon_xmac_readl ( efab, ®, FCN_XX_CORE_STAT_REG_MAC ); + align_done = EFAB_DWORD_FIELD ( reg, FCN_XX_ALIGN_DONE ); + + sync = EFAB_DWORD_FIELD ( reg, FCN_XX_SYNC_STAT ); + sync = ( sync == FCN_XX_SYNC_STAT_DECODE_SYNCED ); + + link_ok = align_done && sync; + } + + /* Clear link status ready for next read */ + EFAB_SET_DWORD_FIELD ( reg, FCN_XX_COMMA_DET, FCN_XX_COMMA_DET_RESET ); + EFAB_SET_DWORD_FIELD ( reg, FCN_XX_CHARERR, FCN_XX_CHARERR_RESET); + EFAB_SET_DWORD_FIELD ( reg, FCN_XX_DISPERR, FCN_XX_DISPERR_RESET); + falcon_xmac_writel ( efab, ®, FCN_XX_CORE_STAT_REG_MAC ); + + has_phyxs = ( efab->phy_op->mmds & ( 1 << MDIO_MMD_PHYXS ) ); + if ( link_ok && has_phyxs ) { + lane_status = falcon_mdio_read ( efab, MDIO_MMD_PHYXS, + MDIO_PHYXS_LANE_STATE ); + link_ok = ( lane_status & ( 1 << MDIO_PHYXS_LANE_ALIGNED_LBN ) ); + + if (!link_ok ) + EFAB_LOG ( "XGXS lane status: %x\n", lane_status ); + } - memset ( addr, 0, 4096 ); - dma_addr = virt_to_bus ( addr ); - EFAB_ASSERT ( ( dma_addr & ( EFAB_BUF_ALIGN - 1 ) ) == 0 ); - EFAB_POPULATE_QWORD_3 ( buf_desc, - FCN_IP_DAT_BUF_SIZE, FCN_IP_DAT_BUF_SIZE_4K, - FCN_BUF_ADR_FBUF, ( dma_addr >> 12 ), - FCN_BUF_OWNER_ID_FBUF, 0 ); - falcon_write_sram_verify ( efab, &buf_desc, index ); + return link_ok; } /** - * Update event queue read pointer + * Initialise XMAC * */ -static void falcon_eventq_read_ack ( struct efab_nic *efab ) { +static void +falcon_reconfigure_xmac ( struct efab_nic *efab ) +{ efab_dword_t reg; + int max_frame_len; + + /* Configure MAC - cut-thru mode is hard wired on */ + EFAB_POPULATE_DWORD_3 ( reg, + FCN_XM_RX_JUMBO_MODE, 1, + FCN_XM_TX_STAT_EN, 1, + FCN_XM_RX_STAT_EN, 1); + falcon_xmac_writel ( efab, ®, FCN_XM_GLB_CFG_REG_MAC ); + + /* Configure TX */ + EFAB_POPULATE_DWORD_6 ( reg, + FCN_XM_TXEN, 1, + FCN_XM_TX_PRMBL, 1, + FCN_XM_AUTO_PAD, 1, + FCN_XM_TXCRC, 1, + FCN_XM_FCNTL, 1, + FCN_XM_IPG, 0x3 ); + falcon_xmac_writel ( efab, ®, FCN_XM_TX_CFG_REG_MAC ); + + /* Configure RX */ + EFAB_POPULATE_DWORD_4 ( reg, + FCN_XM_RXEN, 1, + FCN_XM_AUTO_DEPAD, 0, + FCN_XM_ACPT_ALL_MCAST, 1, + FCN_XM_PASS_CRC_ERR, 1 ); + falcon_xmac_writel ( efab, ®, FCN_XM_RX_CFG_REG_MAC ); + + /* Set frame length */ + max_frame_len = EFAB_MAX_FRAME_LEN ( ETH_FRAME_LEN ); + EFAB_POPULATE_DWORD_1 ( reg, + FCN_XM_MAX_RX_FRM_SIZE, max_frame_len ); + falcon_xmac_writel ( efab, ®, FCN_XM_RX_PARAM_REG_MAC ); + EFAB_POPULATE_DWORD_2 ( reg, + FCN_XM_MAX_TX_FRM_SIZE, max_frame_len, + FCN_XM_TX_JUMBO_MODE, 1 ); + falcon_xmac_writel ( efab, ®, FCN_XM_TX_PARAM_REG_MAC ); + + /* Enable flow control receipt */ + EFAB_POPULATE_DWORD_2 ( reg, + FCN_XM_PAUSE_TIME, 0xfffe, + FCN_XM_DIS_FCNTL, 0 ); + falcon_xmac_writel ( efab, ®, FCN_XM_FC_REG_MAC ); + + /* Set MAC address */ + EFAB_POPULATE_DWORD_4 ( reg, + FCN_XM_ADR_0, efab->mac_addr[0], + FCN_XM_ADR_1, efab->mac_addr[1], + FCN_XM_ADR_2, efab->mac_addr[2], + FCN_XM_ADR_3, efab->mac_addr[3] ); + falcon_xmac_writel ( efab, ®, FCN_XM_ADR_LO_REG_MAC ); + EFAB_POPULATE_DWORD_2 ( reg, + FCN_XM_ADR_4, efab->mac_addr[4], + FCN_XM_ADR_5, efab->mac_addr[5] ); + falcon_xmac_writel ( efab, ®, FCN_XM_ADR_HI_REG_MAC ); +} + +static int +falcon_init_xmac ( struct efab_nic *efab ) +{ + int count, rc; + + /* Mask the PHY management interrupt */ + falcon_mask_status_intr ( efab, 0 ); + + /* Initialise the PHY to instantiate the clock. */ + rc = efab->phy_op->init ( efab ); + if ( rc ) { + EFAB_ERR ( "unable to initialise PHY\n" ); + goto fail1; + } + + falcon_reset_xaui ( efab ); + + /* Give the PHY and MAC time to faff */ + mdelay ( 100 ); + + /* Reset and reconfigure the XMAC */ + rc = falcon_reset_xmac ( efab ); + if ( rc ) + goto fail2; + falcon_reconfigure_xmac ( efab ); + falcon_reconfigure_mac_wrapper ( efab ); + /** + * Now wait for the link to come up. This may take a while + * for some slower PHY's. + */ + for (count=0; count<50; count++) { + int link_ok = 1; + + /* Wait a while for the link to come up. */ + mdelay ( 100 ); + if ((count % 5) == 0) + putchar ( '.' ); + + /* Does the PHY think the wire-side link is up? */ + link_ok = mdio_clause45_links_ok ( efab ); + /* Ensure the XAUI link to the PHY is good */ + if ( link_ok ) { + link_ok = falcon_xaui_link_ok ( efab ); + if ( !link_ok ) + falcon_reset_xaui ( efab ); + } + + /* Check fault indication */ + if ( link_ok ) + link_ok = falcon_xgmii_status ( efab ); + + efab->link_up = link_ok; + if ( link_ok ) { + /* unmask the status interrupt */ + falcon_mask_status_intr ( efab, 1 ); + return 0; + } + } - EFAB_ASSERT ( efab->eventq_read_ptr < EFAB_EVQ_SIZE ); + /* Link failed to come up, but initialisation was fine. */ + rc = -ETIMEDOUT; - EFAB_POPULATE_DWORD_1 ( reg, FCN_EVQ_RPTR_DWORD, - efab->eventq_read_ptr ); - falcon_writel ( efab, ®, FCN_EVQ_RPTR_REG_KER_DWORD ); +fail2: +fail1: + return rc; } -/** - * Reset device +static struct efab_mac_operations falcon_xmac_operations = { + .init = falcon_init_xmac, +}; + +/******************************************************************************* * - */ -static int falcon_reset ( struct efab_nic *efab ) { - efab_oword_t glb_ctl_reg_ker; + * + * Null PHY handling + * + * + *******************************************************************************/ - /* Initiate software reset */ - EFAB_POPULATE_OWORD_7 ( glb_ctl_reg_ker, - PCIE_CORE_RST_CTL, EXCLUDE_FROM_RESET, - PCIE_NSTCK_RST_CTL, EXCLUDE_FROM_RESET, - PCIE_SD_RST_CTL, EXCLUDE_FROM_RESET, - EE_RST_CTL, EXCLUDE_FROM_RESET, - PCIX_RST_CTL, EXCLUDE_FROM_RESET, - EXT_PHY_RST_DUR, 0x7 /* datasheet recommended */, - SWRST, 1 ); +static int +falcon_xaui_phy_init ( struct efab_nic *efab ) +{ + /* CX4 is always 10000FD only */ + efab->link_options = LPA_10000FULL; - falcon_write ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER ); + /* There is no PHY! */ + return 0; +} - /* Allow 20ms for reset */ - mdelay ( 20 ); +static struct efab_phy_operations falcon_xaui_phy_ops = { + .init = falcon_xaui_phy_init, + .mmds = 0, +}; - /* Check for device reset complete */ - falcon_read ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER ); - if ( EFAB_OWORD_FIELD ( glb_ctl_reg_ker, SWRST ) != 0 ) { - EFAB_ERR ( "Reset failed\n" ); - return 0; - } - return 1; -} +/******************************************************************************* + * + * + * Alaska PHY + * + * + *******************************************************************************/ /** - * Wait for SPI command completion + * Initialise Alaska PHY * */ -static int falcon_spi_wait ( struct efab_nic *efab ) { - efab_oword_t reg; - int count; +static int +alaska_init ( struct efab_nic *efab ) +{ + unsigned int advertised, lpa; + + /* Read link up status */ + efab->link_up = gmii_link_ok ( efab ); + + if ( ! efab->link_up ) + return -EIO; + + /* Determine link options from PHY. */ + advertised = gmii_autoneg_advertised ( efab ); + lpa = gmii_autoneg_lpa ( efab ); + efab->link_options = gmii_nway_result ( advertised & lpa ); - count = 0; - do { - udelay ( 100 ); - falcon_read ( efab, ®, FCN_EE_SPI_HCMD_REG_KER ); - if ( EFAB_OWORD_FIELD ( reg, FCN_EE_SPI_HCMD_CMD_EN ) == 0 ) - return 1; - } while ( ++count < 1000 ); - printf ( "Timed out waiting for SPI\n" ); return 0; } -/** - * Perform SPI read/write +static struct efab_phy_operations falcon_alaska_phy_ops = { + .init = alaska_init, +}; + +/******************************************************************************* * - */ -static int falcon_spi_rw ( struct spi_bus *bus, struct spi_device *device, - unsigned int command, int address, - const void *data_out, void *data_in, size_t len ) { - struct efab_nic *efab = container_of ( bus, struct efab_nic, spi ); - efab_oword_t reg; + * + * xfp + * + * + *******************************************************************************/ - /* Program address register */ - EFAB_POPULATE_OWORD_1 ( reg, FCN_EE_SPI_HADR_ADR, address ); - falcon_write ( efab, ®, FCN_EE_SPI_HADR_REG_KER ); - - /* Program data register, if applicable */ - if ( data_out ) { - memcpy ( ®, data_out, len ); - falcon_write ( efab, ®, FCN_EE_SPI_HDATA_REG_KER ); - } +#define XFP_REQUIRED_DEVS ( MDIO_MMDREG_DEVS0_PCS | \ + MDIO_MMDREG_DEVS0_PMAPMD | \ + MDIO_MMDREG_DEVS0_PHYXS ) - /* Issue command */ - EFAB_POPULATE_OWORD_7 ( reg, - FCN_EE_SPI_HCMD_CMD_EN, 1, - FCN_EE_SPI_HCMD_SF_SEL, device->slave, - FCN_EE_SPI_HCMD_DABCNT, len, - FCN_EE_SPI_HCMD_READ, ( data_out ? - FCN_EE_SPI_WRITE : FCN_EE_SPI_READ ), - FCN_EE_SPI_HCMD_DUBCNT, 0, - FCN_EE_SPI_HCMD_ADBCNT, - ( device->address_len / 8 ), - FCN_EE_SPI_HCMD_ENC, command ); - falcon_write ( efab, ®, FCN_EE_SPI_HCMD_REG_KER ); - - /* Wait for operation to complete */ - if ( ! falcon_spi_wait ( efab ) ) - return 0; +static int +falcon_xfp_phy_init ( struct efab_nic *efab ) +{ + int rc; + + /* Optical link is always 10000FD only */ + efab->link_options = LPA_10000FULL; + + /* Reset the PHY */ + rc = mdio_clause45_reset_mmd ( efab, MDIO_MMD_PHYXS ); + if ( rc ) + return rc; - /* Read data, if applicable */ - if ( data_in ) { - falcon_read ( efab, ®, FCN_EE_SPI_HDATA_REG_KER ); - memcpy ( data_in, ®, len ); - } - return 0; } -/** - * Initialise SPI bus and devices +static struct efab_phy_operations falcon_xfp_phy_ops = { + .init = falcon_xfp_phy_init, + .mmds = XFP_REQUIRED_DEVS, +}; + +/******************************************************************************* * - */ -static void falcon_init_spi ( struct efab_nic *efab ) { - efab_oword_t reg; - int eeprom_9bit; - - /* Initialise SPI bus */ - efab->spi.rw = falcon_spi_rw; - efab->falcon_eeprom.bus = &efab->spi; - efab->falcon_eeprom.slave = FCN_EE_SPI_EEPROM; - efab->falcon_flash.bus = &efab->spi; - efab->falcon_flash.slave = FCN_EE_SPI_FLASH; - - /* Initialise flash if present */ - if ( efab->has_flash ) { - DBG ( "Flash is present\n" ); - init_at25f1024 ( &efab->falcon_flash ); - } - - /* Initialise EEPROM if present */ - if ( efab->has_eeprom ) { - if ( efab->is_asic ) { - falcon_read ( efab, ®, FCN_VPD_CONFIG_REG_KER ); - eeprom_9bit = EFAB_OWORD_FIELD ( reg, FCN_VPD_9BIT ); - } else { - eeprom_9bit = 1; - } - if ( eeprom_9bit ) { - DBG ( "Small EEPROM is present\n" ); - init_at25040 ( &efab->falcon_eeprom ); - } else { - DBG ( "Large EEPROM is present\n" ); - init_mc25xx640 ( &efab->falcon_eeprom ); - /* Falcon's SPI interface cannot support a block - size larger than 16, so forcibly reduce it - */ - efab->falcon_eeprom.nvs.block_size = 16; - } + * + * txc43128 + * + * + *******************************************************************************/ + +/* Command register */ +#define TXC_GLRGS_GLCMD (0xc004) +#define TXC_GLCMD_LMTSWRST_LBN (14) + +/* Amplitude on lanes 0+1, 2+3 */ +#define TXC_ALRGS_ATXAMP0 (0xc041) +#define TXC_ALRGS_ATXAMP1 (0xc042) +/* Bit position of value for lane 0+2, 1+3 */ +#define TXC_ATXAMP_LANE02_LBN (3) +#define TXC_ATXAMP_LANE13_LBN (11) + +#define TXC_ATXAMP_1280_mV (0) +#define TXC_ATXAMP_1200_mV (8) +#define TXC_ATXAMP_1120_mV (12) +#define TXC_ATXAMP_1060_mV (14) +#define TXC_ATXAMP_0820_mV (25) +#define TXC_ATXAMP_0720_mV (26) +#define TXC_ATXAMP_0580_mV (27) +#define TXC_ATXAMP_0440_mV (28) + +#define TXC_ATXAMP_0820_BOTH ( (TXC_ATXAMP_0820_mV << TXC_ATXAMP_LANE02_LBN) | \ + (TXC_ATXAMP_0820_mV << TXC_ATXAMP_LANE13_LBN) ) + +#define TXC_ATXAMP_DEFAULT (0x6060) /* From databook */ + +/* Preemphasis on lanes 0+1, 2+3 */ +#define TXC_ALRGS_ATXPRE0 (0xc043) +#define TXC_ALRGS_ATXPRE1 (0xc044) + +#define TXC_ATXPRE_NONE (0) +#define TXC_ATXPRE_DEFAULT (0x1010) /* From databook */ + +#define TXC_REQUIRED_DEVS ( MDIO_MMDREG_DEVS0_PCS | \ + MDIO_MMDREG_DEVS0_PMAPMD | \ + MDIO_MMDREG_DEVS0_PHYXS ) + +static int +falcon_txc_logic_reset ( struct efab_nic *efab ) +{ + int val; + int tries = 50; + + val = falcon_mdio_read ( efab, MDIO_MMD_PCS, TXC_GLRGS_GLCMD ); + val |= (1 << TXC_GLCMD_LMTSWRST_LBN); + falcon_mdio_write ( efab, MDIO_MMD_PCS, TXC_GLRGS_GLCMD, val ); + + while ( tries--) { + val = falcon_mdio_read ( efab, MDIO_MMD_PCS, TXC_GLRGS_GLCMD ); + if ( ~val & ( 1 << TXC_GLCMD_LMTSWRST_LBN ) ) + return 0; + udelay(1); } + + EFAB_ERR ( "logic reset failed\n" ); + + return -ETIMEDOUT; } -/** Offset of MAC address within EEPROM or Flash */ -#define FALCON_MAC_ADDRESS_OFFSET(port) ( 0x310 + 0x08 * (port) ) +static int +falcon_txc_phy_init ( struct efab_nic *efab ) +{ + int rc; -static struct nvo_fragment falcon_eeprom_fragments[] = { - { 0x100, 0x100 }, - { 0, 0 } -}; + /* CX4 is always 10000FD only */ + efab->link_options = LPA_10000FULL; -/** - * Read MAC address from EEPROM - * - */ -static int falcon_read_eeprom ( struct efab_nic *efab ) { - struct nvs_device *nvs; + /* reset the phy */ + rc = mdio_clause45_reset_mmd ( efab, MDIO_MMD_PMAPMD ); + if ( rc ) + goto fail1; + + rc = mdio_clause45_check_mmds ( efab ); + if ( rc ) + goto fail2; + + /* Turn amplitude down and preemphasis off on the host side + * (PHY<->MAC) as this is believed less likely to upset falcon + * and no adverse effects have been noted. It probably also + * saves a picowatt or two */ + + /* Turn off preemphasis */ + falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXPRE0, + TXC_ATXPRE_NONE ); + falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXPRE1, + TXC_ATXPRE_NONE ); + + /* Turn down the amplitude */ + falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXAMP0, + TXC_ATXAMP_0820_BOTH ); + falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXAMP1, + TXC_ATXAMP_0820_BOTH ); + + /* Set the line side amplitude and preemphasis to the databook + * defaults as an erratum causes them to be 0 on at least some + * PHY rev.s */ + falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXPRE0, + TXC_ATXPRE_DEFAULT ); + falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXPRE1, + TXC_ATXPRE_DEFAULT ); + falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXAMP0, + TXC_ATXAMP_DEFAULT ); + falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXAMP1, + TXC_ATXAMP_DEFAULT ); + + rc = falcon_txc_logic_reset ( efab ); + if ( rc ) + goto fail3; - /* Determine the NVS device containing the MAC address */ - nvs = ( efab->has_flash ? - &efab->falcon_flash.nvs : &efab->falcon_eeprom.nvs ); + return 0; - return ( nvs_read ( nvs, FALCON_MAC_ADDRESS_OFFSET ( efab->port ), - efab->mac_addr, sizeof ( efab->mac_addr ) ) == 0 ); +fail3: +fail2: +fail1: + return rc; } -/** RX descriptor */ -typedef efab_qword_t falcon_rx_desc_t; +static struct efab_phy_operations falcon_txc_phy_ops = { + .init = falcon_txc_phy_init, + .mmds = TXC_REQUIRED_DEVS, +}; -/** - * Build RX descriptor +/******************************************************************************* * - */ -static void falcon_build_rx_desc ( struct efab_nic *efab, - struct efab_rx_buf *rx_buf ) { - falcon_rx_desc_t *rxd; + * + * tenxpress + * + * + *******************************************************************************/ - rxd = ( ( falcon_rx_desc_t * ) efab->rxd ) + rx_buf->id; - EFAB_POPULATE_QWORD_2 ( *rxd, - FCN_RX_KER_BUF_SIZE, EFAB_DATA_BUF_SIZE, - FCN_RX_KER_BUF_ADR, - virt_to_bus ( rx_buf->addr ) ); -} -/** - * Update RX descriptor write pointer - * - */ -static void falcon_notify_rx_desc ( struct efab_nic *efab ) { - efab_dword_t reg; +#define TENXPRESS_REQUIRED_DEVS ( MDIO_MMDREG_DEVS0_PMAPMD | \ + MDIO_MMDREG_DEVS0_PCS | \ + MDIO_MMDREG_DEVS0_PHYXS ) - EFAB_POPULATE_DWORD_1 ( reg, FCN_RX_DESC_WPTR_DWORD, - efab->rx_write_ptr ); - falcon_writel ( efab, ®, FCN_RX_DESC_UPD_REG_KER_DWORD ); -} +#define PCS_TEST_SELECT_REG 0xd807 /* PRM 10.5.8 */ +#define CLK312_EN_LBN 3 +#define CLK312_EN_WIDTH 1 -/** TX descriptor */ -typedef efab_qword_t falcon_tx_desc_t; +#define PCS_CLOCK_CTRL_REG 0xd801 +#define PLL312_RST_N_LBN 2 -/** - * Build TX descriptor - * - */ -static void falcon_build_tx_desc ( struct efab_nic *efab, - struct efab_tx_buf *tx_buf ) { - falcon_rx_desc_t *txd; +/* Special Software reset register */ +#define PMA_PMD_EXT_CTRL_REG 49152 +#define PMA_PMD_EXT_SSR_LBN 15 + +/* Boot status register */ +#define PCS_BOOT_STATUS_REG 0xd000 +#define PCS_BOOT_FATAL_ERR_LBN 0 +#define PCS_BOOT_PROGRESS_LBN 1 +#define PCS_BOOT_PROGRESS_WIDTH 2 +#define PCS_BOOT_COMPLETE_LBN 3 + +#define PCS_SOFT_RST2_REG 0xd806 +#define SERDES_RST_N_LBN 13 +#define XGXS_RST_N_LBN 12 + +static int +falcon_tenxpress_check_c11 ( struct efab_nic *efab ) +{ + int count; + uint32_t boot_stat; + + /* Check that the C11 CPU has booted */ + for (count=0; count<10; count++) { + boot_stat = falcon_mdio_read ( efab, MDIO_MMD_PCS, + PCS_BOOT_STATUS_REG ); + if ( boot_stat & ( 1 << PCS_BOOT_COMPLETE_LBN ) ) + return 0; + + udelay(10); + } - txd = ( ( falcon_rx_desc_t * ) efab->txd ) + tx_buf->id; - EFAB_POPULATE_QWORD_3 ( *txd, - FCN_TX_KER_PORT, efab->port, - FCN_TX_KER_BYTE_CNT, tx_buf->len, - FCN_TX_KER_BUF_ADR, - virt_to_bus ( tx_buf->addr ) ); + EFAB_ERR ( "C11 failed to boot\n" ); + return -ETIMEDOUT; } -/** - * Update TX descriptor write pointer - * - */ -static void falcon_notify_tx_desc ( struct efab_nic *efab ) { - efab_dword_t reg; +static int +falcon_tenxpress_phy_init ( struct efab_nic *efab ) +{ + int rc, reg; - EFAB_POPULATE_DWORD_1 ( reg, FCN_TX_DESC_WPTR_DWORD, - efab->tx_write_ptr ); - falcon_writel ( efab, ®, FCN_TX_DESC_UPD_REG_KER_DWORD ); + /* 10XPRESS is always 10000FD (at the moment) */ + efab->link_options = LPA_10000FULL; + + /* Wait for the blocks to come out of reset */ + rc = mdio_clause45_wait_reset_mmds ( efab ); + if ( rc ) + goto fail1; + + rc = mdio_clause45_check_mmds ( efab ); + if ( rc ) + goto fail2; + + /* Turn on the clock */ + reg = (1 << CLK312_EN_LBN); + falcon_mdio_write ( efab, MDIO_MMD_PCS, PCS_TEST_SELECT_REG, reg); + + /* Wait 200ms for the PHY to boot */ + mdelay(200); + + rc = falcon_tenxpress_check_c11 ( efab ); + if ( rc ) + goto fail3; + + return 0; + +fail3: +fail2: +fail1: + return rc; } -/** An event */ -typedef efab_qword_t falcon_event_t; +static struct efab_phy_operations falcon_tenxpress_phy_ops = { + .init = falcon_tenxpress_phy_init, + .mmds = TENXPRESS_REQUIRED_DEVS, +}; -/** - * See if an event is present +/******************************************************************************* * - * @v event Falcon event structure - * @ret True An event is pending - * @ret False No event is pending * - * We check both the high and low dword of the event for all ones. We - * wrote all ones when we cleared the event, and no valid event can - * have all ones in either its high or low dwords. This approach is - * robust against reordering. + * PM8358 * - * Note that using a single 64-bit comparison is incorrect; even - * though the CPU read will be atomic, the DMA write may not be. - */ -static inline int falcon_event_present ( falcon_event_t* event ) { - return ( ! ( EFAB_DWORD_IS_ALL_ONES ( event->dword[0] ) | - EFAB_DWORD_IS_ALL_ONES ( event->dword[1] ) ) ); -} - -/** - * Retrieve event from event queue * - */ -static int falcon_fetch_event ( struct efab_nic *efab, - struct efab_event *event ) { - falcon_event_t *evt; - int ev_code; - int rx_port; + *******************************************************************************/ + +/* The PM8358 just presents a DTE XS */ +#define PM8358_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_DTEXS) + +/* PHY-specific definitions */ +/* Master ID and Global Performance Monitor Update */ +#define PMC_MASTER_REG (0xd000) +/* Analog Tx Rx settings under software control */ +#define PMC_MASTER_ANLG_CTRL (1<< 11) + +/* Master Configuration register 2 */ +#define PMC_MCONF2_REG (0xd002) +/* Drive Tx off centre of data eye (1) vs. clock edge (0) */ +#define PMC_MCONF2_TEDGE (1 << 2) +/* Drive Rx off centre of data eye (1) vs. clock edge (0) */ +#define PMC_MCONF2_REDGE (1 << 3) + +/* Analog Rx settings */ +#define PMC_ANALOG_RX_CFG0 (0xd025) +#define PMC_ANALOG_RX_CFG1 (0xd02d) +#define PMC_ANALOG_RX_CFG2 (0xd035) +#define PMC_ANALOG_RX_CFG3 (0xd03d) + + +#define PMC_ANALOG_RX_TERM (1 << 15) /* Bit 15 of RX CFG: 0 for 100 ohms float, + 1 for 50 to 1.2V */ +#define PMC_ANALOG_RX_EQ_MASK (3 << 8) +#define PMC_ANALOG_RX_EQ_NONE (0 << 8) +#define PMC_ANALOG_RX_EQ_HALF (1 << 8) +#define PMC_ANALOG_RX_EQ_FULL (2 << 8) +#define PMC_ANALOG_RX_EQ_RSVD (3 << 8) + +static int +falcon_pm8358_phy_init ( struct efab_nic *efab ) +{ + int rc, reg, i; - /* Check for event */ - evt = ( ( falcon_event_t * ) efab->eventq ) + efab->eventq_read_ptr; - if ( !falcon_event_present ( evt ) ) { - /* No event */ - return 0; - } - - DBG ( "Event is " EFAB_QWORD_FMT "\n", EFAB_QWORD_VAL ( *evt ) ); + /* This is a XAUI retimer part */ + efab->link_options = LPA_10000FULL; - /* Decode event */ - ev_code = EFAB_QWORD_FIELD ( *evt, FCN_EV_CODE ); - event->drop = 0; - switch ( ev_code ) { - case FCN_TX_IP_EV_DECODE: - event->type = EFAB_EV_TX; - break; - case FCN_RX_IP_EV_DECODE: - event->type = EFAB_EV_RX; - event->rx_id = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_DESC_PTR ); - event->rx_len = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_BYTE_CNT ); - event->drop = !EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_PKT_OK ); - rx_port = EFAB_QWORD_FIELD ( *evt, FCN_RX_PORT ); - if ( rx_port != efab->port ) { - /* Ignore packets on the wrong port. We can't - * just set event->type = EFAB_EV_NONE, - * because then the descriptor ring won't get - * refilled. - */ - event->rx_len = 0; - } - break; - case FCN_DRIVER_EV_DECODE: - /* Ignore start-of-day events */ - event->type = EFAB_EV_NONE; - break; - default: - EFAB_ERR ( "Unknown event type %d data %08lx\n", ev_code, - EFAB_DWORD_FIELD ( *evt, EFAB_DWORD_0 ) ); - event->type = EFAB_EV_NONE; + rc = mdio_clause45_reset_mmd ( efab, MDIO_MMDREG_DEVS0_DTEXS ); + if ( rc ) + return rc; + + /* Enable software control of analogue settings */ + reg = falcon_mdio_read ( efab, MDIO_MMD_DTEXS, PMC_MASTER_REG ); + reg |= PMC_MASTER_ANLG_CTRL; + falcon_mdio_write ( efab, MDIO_MMD_DTEXS, PMC_MASTER_REG, reg ); + + /* Turn rx eq on for all channels */ + for (i=0; i< 3; i++) { + /* The analog CFG registers are evenly spaced 8 apart */ + uint16_t addr = PMC_ANALOG_RX_CFG0 + 8*i; + reg = falcon_mdio_read ( efab, MDIO_MMD_DTEXS, addr ); + reg = ( reg & ~PMC_ANALOG_RX_EQ_MASK ) | PMC_ANALOG_RX_EQ_FULL; + falcon_mdio_write ( efab, MDIO_MMD_DTEXS, addr, reg ); } - /* Clear event and any pending interrupts */ - EFAB_SET_QWORD ( *evt ); - falcon_writel ( efab, 0, FCN_INT_ACK_KER_REG ); - udelay ( 10 ); - - /* Increment and update event queue read pointer */ - efab->eventq_read_ptr = ( ( efab->eventq_read_ptr + 1 ) - % EFAB_EVQ_SIZE ); - falcon_eventq_read_ack ( efab ); + /* Set TEDGE, clear REDGE */ + reg = falcon_mdio_read ( efab, MDIO_MMD_DTEXS, PMC_MCONF2_REG ); + reg = ( reg & ~PMC_MCONF2_REDGE) | PMC_MCONF2_TEDGE; + falcon_mdio_write ( efab, MDIO_MMD_DTEXS, PMC_MCONF2_REG, reg ); - return 1; + return 0; } -/** - * Enable/disable/generate interrupt +static struct efab_phy_operations falcon_pm8358_phy_ops = { + .init = falcon_pm8358_phy_init, + .mmds = PM8358_REQUIRED_DEVS, +}; + +/******************************************************************************* * - */ -static inline void falcon_interrupts ( struct efab_nic *efab, int enabled, - int force ) { - efab_oword_t int_en_reg_ker; + * + * SFE4001 support + * + * + *******************************************************************************/ + +#define MAX_TEMP_THRESH 90 + +/* I2C Expander */ +#define PCA9539 0x74 + +#define P0_IN 0x00 +#define P0_OUT 0x02 +#define P0_CONFIG 0x06 + +#define P0_EN_1V0X_LBN 0 +#define P0_EN_1V0X_WIDTH 1 +#define P0_EN_1V2_LBN 1 +#define P0_EN_1V2_WIDTH 1 +#define P0_EN_2V5_LBN 2 +#define P0_EN_2V5_WIDTH 1 +#define P0_EN_3V3X_LBN 3 +#define P0_EN_3V3X_WIDTH 1 +#define P0_EN_5V_LBN 4 +#define P0_EN_5V_WIDTH 1 +#define P0_X_TRST_LBN 6 +#define P0_X_TRST_WIDTH 1 + +#define P1_IN 0x01 +#define P1_CONFIG 0x07 + +#define P1_AFE_PWD_LBN 0 +#define P1_AFE_PWD_WIDTH 1 +#define P1_DSP_PWD25_LBN 1 +#define P1_DSP_PWD25_WIDTH 1 +#define P1_SPARE_LBN 4 +#define P1_SPARE_WIDTH 4 + +/* Temperature Sensor */ +#define MAX6647 0x4e + +#define RSL 0x02 +#define RLHN 0x05 +#define WLHO 0x0b + +static struct i2c_device i2c_pca9539 = { + .dev_addr = PCA9539, + .dev_addr_len = 1, + .word_addr_len = 1, +}; - EFAB_POPULATE_OWORD_2 ( int_en_reg_ker, - FCN_KER_INT_KER, force, - FCN_DRV_INT_EN_KER, enabled ); - falcon_write ( efab, &int_en_reg_ker, FCN_INT_EN_REG_KER ); -} -/** - * Enable/disable interrupts - * - */ -static void falcon_mask_irq ( struct efab_nic *efab, int enabled ) { - falcon_interrupts ( efab, enabled, 0 ); - if ( enabled ) { - /* Events won't trigger interrupts until we do this */ - falcon_eventq_read_ack ( efab ); +static struct i2c_device i2c_max6647 = { + .dev_addr = MAX6647, + .dev_addr_len = 1, + .word_addr_len = 1, +}; + +static int +sfe4001_init ( struct efab_nic *efab ) +{ + struct i2c_interface *i2c = &efab->i2c_bb.i2c; + efab_dword_t reg; + uint8_t in, cfg, out; + int count, rc; + + EFAB_LOG ( "Initialise SFE4001 board\n" ); + + /* Ensure XGXS and XAUI SerDes are held in reset */ + EFAB_POPULATE_DWORD_7 ( reg, + FCN_XX_PWRDNA_EN, 1, + FCN_XX_PWRDNB_EN, 1, + FCN_XX_RSTPLLAB_EN, 1, + FCN_XX_RESETA_EN, 1, + FCN_XX_RESETB_EN, 1, + FCN_XX_RSTXGXSRX_EN, 1, + FCN_XX_RSTXGXSTX_EN, 1 ); + falcon_xmac_writel ( efab, ®, FCN_XX_PWR_RST_REG_MAC); + udelay(10); + + /* Set DSP over-temperature alert threshold */ + cfg = MAX_TEMP_THRESH; + rc = i2c->write ( i2c, &i2c_max6647, WLHO, &cfg, EFAB_BYTE ); + if ( rc ) + goto fail1; + + /* Read it back and verify */ + rc = i2c->read ( i2c, &i2c_max6647, RLHN, &in, EFAB_BYTE ); + if ( rc ) + goto fail2; + + if ( in != MAX_TEMP_THRESH ) { + EFAB_ERR ( "Unable to verify MAX6647 limit (requested=%d " + "confirmed=%d)\n", cfg, in ); + rc = -EIO; + goto fail3; } -} -/** - * Generate interrupt - * - */ -static void falcon_generate_irq ( struct efab_nic *efab ) { - falcon_interrupts ( efab, 1, 1 ); -} + /* Clear any previous over-temperature alert */ + rc = i2c->read ( i2c, &i2c_max6647, RSL, &in, EFAB_BYTE ); + if ( rc ) + goto fail4; + + /* Enable port 0 and 1 outputs on IO expander */ + cfg = 0x00; + rc = i2c->write ( i2c, &i2c_pca9539, P0_CONFIG, &cfg, EFAB_BYTE ); + if ( rc ) + goto fail5; + cfg = 0xff & ~(1 << P1_SPARE_LBN); + rc = i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &cfg, EFAB_BYTE ); + if ( rc ) + goto fail6; + + /* Turn all power off then wait 1 sec. This ensures PHY is reset */ + out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) | + (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) | + (0 << P0_EN_1V0X_LBN)); + + rc = i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE ); + if ( rc ) + goto fail7; + + mdelay(1000); + + for (count=0; count<20; count++) { + /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */ + out = 0xff & ~( (1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) | + (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) | + (1 << P0_X_TRST_LBN) ); + + rc = i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE ); + if ( rc ) + goto fail8; + + mdelay ( 10 ); + + /* Turn on the 1V power rail */ + out &= ~( 1 << P0_EN_1V0X_LBN ); + rc = i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE ); + if ( rc ) + goto fail9; + EFAB_LOG ( "Waiting for power...(attempt %d)\n", count); + mdelay ( 1000 ); -/** - * Reconfigure MAC wrapper - * - */ -static void falcon_reconfigure_mac_wrapper ( struct efab_nic *efab ) { - efab_oword_t reg; - int link_speed; + /* Check DSP is powered */ + rc = i2c->read ( i2c, &i2c_pca9539, P1_IN, &in, EFAB_BYTE ); + if ( rc ) + goto fail10; - if ( efab->link_options & LPA_10000 ) { - link_speed = 0x3; - } else if ( efab->link_options & LPA_1000 ) { - link_speed = 0x2; - } else if ( efab->link_options & LPA_100 ) { - link_speed = 0x1; - } else { - link_speed = 0x0; + if ( in & ( 1 << P1_AFE_PWD_LBN ) ) + return 0; } - EFAB_POPULATE_OWORD_5 ( reg, - FCN_MAC_XOFF_VAL, 0xffff /* datasheet */, - FCN_MAC_BCAD_ACPT, 1, - FCN_MAC_UC_PROM, 0, - FCN_MAC_LINK_STATUS, 1, - FCN_MAC_SPEED, link_speed ); - falcon_write ( efab, ®, - ( efab->port == 0 ? - FCN_MAC0_CTRL_REG_KER : FCN_MAC1_CTRL_REG_KER ) ); - /* Disable flow-control (i.e. never generate pause frames) */ - falcon_read ( efab, ®, FCN_RX_CFG_REG_KER ); - EFAB_SET_OWORD_FIELD ( reg, FCN_RX_XOFF_EN, 0 ); - falcon_write ( efab, ®, FCN_RX_CFG_REG_KER ); + rc = -ETIMEDOUT; + +fail10: +fail9: +fail8: +fail7: + /* Turn off power rails */ + out = 0xff; + (void) i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE ); + /* Disable port 1 outputs on IO expander */ + out = 0xff; + (void) i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &out, EFAB_BYTE ); +fail6: + /* Disable port 0 outputs */ + out = 0xff; + (void) i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &out, EFAB_BYTE ); +fail5: +fail4: +fail3: +fail2: +fail1: + EFAB_ERR ( "Failed initialising SFE4001 board\n" ); + return rc; } -/** - * Write dword to a Falcon MAC register - * - */ -static void falcon_gmac_writel ( struct efab_nic *efab, - efab_dword_t *value, unsigned int mac_reg ) { - efab_oword_t temp; +static void +sfe4001_fini ( struct efab_nic *efab ) +{ + struct i2c_interface *i2c = &efab->i2c_bb.i2c; + uint8_t in, cfg, out; - EFAB_POPULATE_OWORD_1 ( temp, FCN_MAC_DATA, - EFAB_DWORD_FIELD ( *value, FCN_MAC_DATA ) ); - falcon_write ( efab, &temp, FALCON_GMAC_REG ( efab, mac_reg ) ); -} + EFAB_ERR ( "Turning off SFE4001\n" ); -/** - * Read dword from a Falcon GMAC register - * - */ -static void falcon_gmac_readl ( struct efab_nic *efab, efab_dword_t *value, - unsigned int mac_reg ) { - efab_oword_t temp; + /* Turn off all power rails */ + out = 0xff; + (void) i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE ); - falcon_read ( efab, &temp, FALCON_GMAC_REG ( efab, mac_reg ) ); - EFAB_POPULATE_DWORD_1 ( *value, FCN_MAC_DATA, - EFAB_OWORD_FIELD ( temp, FCN_MAC_DATA ) ); + /* Disable port 1 outputs on IO expander */ + cfg = 0xff; + (void) i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &cfg, EFAB_BYTE ); + + /* Disable port 0 outputs on IO expander */ + cfg = 0xff; + (void) i2c->write ( i2c, &i2c_pca9539, P0_CONFIG, &cfg, EFAB_BYTE ); + + /* Clear any over-temperature alert */ + (void) i2c->read ( i2c, &i2c_max6647, RSL, &in, EFAB_BYTE ); +} + +struct efab_board_operations sfe4001_ops = { + .init = sfe4001_init, + .fini = sfe4001_fini, +}; + +static int sfe4002_init ( struct efab_nic *efab __attribute__((unused)) ) +{ + return 0; +} +static void sfe4002_fini ( struct efab_nic *efab __attribute__((unused)) ) +{ } -/** - * Write dword to a Falcon XMAC register - * - */ -static void falcon_xmac_writel ( struct efab_nic *efab, - efab_dword_t *value, unsigned int mac_reg ) { - efab_oword_t temp; +struct efab_board_operations sfe4002_ops = { + .init = sfe4002_init, + .fini = sfe4002_fini, +}; - EFAB_POPULATE_OWORD_1 ( temp, FCN_MAC_DATA, - EFAB_DWORD_FIELD ( *value, FCN_MAC_DATA ) ); - falcon_write ( efab, &temp, - FALCON_XMAC_REG ( efab, mac_reg ) ); +static int sfe4003_init ( struct efab_nic *efab __attribute__((unused)) ) +{ + return 0; +} +static void sfe4003_fini ( struct efab_nic *efab __attribute__((unused)) ) +{ } -/** - * Read dword from a Falcon XMAC register +struct efab_board_operations sfe4003_ops = { + .init = sfe4003_init, + .fini = sfe4003_fini, +}; + +/******************************************************************************* * - */ -static void falcon_xmac_readl ( struct efab_nic *efab, - efab_dword_t *value, - unsigned int mac_reg ) { - efab_oword_t temp; + * + * Hardware initialisation + * + * + *******************************************************************************/ - falcon_read ( efab, &temp, - FALCON_XMAC_REG ( efab, mac_reg ) ); - EFAB_POPULATE_DWORD_1 ( *value, FCN_MAC_DATA, - EFAB_OWORD_FIELD ( temp, FCN_MAC_DATA ) ); +static void +falcon_free_special_buffer ( void *p ) +{ + /* We don't bother cleaning up the buffer table entries - + * we're hardly limited */ + free_dma ( p, EFAB_BUF_ALIGN ); } -/** - * Initialise GMAC - * - */ -static int falcon_init_gmac ( struct efab_nic *efab ) { - static struct efab_mentormac_parameters falcon_mentormac_params = { - .gmf_cfgfrth = 0x12, - .gmf_cfgftth = 0x08, - .gmf_cfghwmft = 0x1c, - .gmf_cfghwm = 0x3f, - .gmf_cfglwm = 0xa, - }; +static void* +falcon_alloc_special_buffer ( struct efab_nic *efab, int bytes, + struct efab_special_buffer *entry ) +{ + void* buffer; + int remaining; + efab_qword_t buf_desc; + unsigned long dma_addr; - /* Initialise PHY */ - alaska_init ( efab ); + /* Allocate the buffer, aligned on a buffer address boundary */ + buffer = malloc_dma ( bytes, EFAB_BUF_ALIGN ); + if ( ! buffer ) + return NULL; - /* check the link is up */ - if ( !efab->link_up ) - return 0; + /* Push buffer table entries to back the buffer */ + entry->id = efab->buffer_head; + entry->dma_addr = dma_addr = virt_to_bus ( buffer ); + assert ( ( dma_addr & ( EFAB_BUF_ALIGN - 1 ) ) == 0 ); - /* Initialise MAC */ - mentormac_init ( efab, &falcon_mentormac_params ); + remaining = bytes; + while ( remaining > 0 ) { + EFAB_POPULATE_QWORD_3 ( buf_desc, + FCN_IP_DAT_BUF_SIZE, FCN_IP_DAT_BUF_SIZE_4K, + FCN_BUF_ADR_FBUF, ( dma_addr >> 12 ), + FCN_BUF_OWNER_ID_FBUF, 0 ); - /* reconfigure the MAC wrapper */ - falcon_reconfigure_mac_wrapper ( efab ); + falcon_write_sram ( efab, &buf_desc, efab->buffer_head ); - return 1; -} + ++efab->buffer_head; + dma_addr += EFAB_BUF_ALIGN; + remaining -= EFAB_BUF_ALIGN; + } -/** - * Reset GMAC - * - */ -static int falcon_reset_gmac ( struct efab_nic *efab ) { - mentormac_reset ( efab ); - return 1; + EFAB_TRACE ( "Allocated 0x%x bytes at %p backed by buffer table " + "entries 0x%x..0x%x\n", bytes, buffer, entry->id, + efab->buffer_head - 1 ); + + return buffer; } -/** - * Reset XAUI/XGXS block - * - */ -static int falcon_reset_xaui ( struct efab_nic *efab ) +static void +clear_b0_fpga_memories ( struct efab_nic *efab) { - efab_dword_t reg; - int count; + efab_oword_t blanko, temp; + efab_dword_t blankd; + int offset; + + EFAB_ZERO_OWORD ( blanko ); + EFAB_ZERO_DWORD ( blankd ); + + /* Clear the address region register */ + EFAB_POPULATE_OWORD_4 ( temp, + FCN_ADR_REGION0, 0, + FCN_ADR_REGION1, ( 1 << 16 ), + FCN_ADR_REGION2, ( 2 << 16 ), + FCN_ADR_REGION3, ( 3 << 16 ) ); + falcon_write ( efab, &temp, FCN_ADR_REGION_REG_KER ); - EFAB_POPULATE_DWORD_1 ( reg, FCN_XX_RST_XX_EN, 1 ); - efab->mac_op->mac_writel ( efab, ®, FCN_XX_PWR_RST_REG_MAC ); + EFAB_TRACE ( "Clearing filter and RSS tables\n" ); - for ( count = 0 ; count < 1000 ; count++ ) { - udelay ( 10 ); - efab->mac_op->mac_readl ( efab, ®, - FCN_XX_PWR_RST_REG_MAC ); - if ( EFAB_DWORD_FIELD ( reg, FCN_XX_RST_XX_EN ) == 0 ) - return 1; + for ( offset = FCN_RX_FILTER_TBL0 ; + offset < FCN_RX_RSS_INDIR_TBL_B0+0x800 ; + offset += 0x10 ) { + falcon_write ( efab, &blanko, offset ); } - - /* an error of some kind */ - return 0; -} - -/** - * Reset 10G MAC connected to port - * - */ -static int falcon_reset_xmac ( struct efab_nic *efab ) { - efab_dword_t reg; - int count; - EFAB_POPULATE_DWORD_1 ( reg, FCN_XM_CORE_RST, 1 ); - efab->mac_op->mac_writel ( efab, ®, FCN_XM_GLB_CFG_REG_MAC ); + EFAB_TRACE ( "Wiping buffer tables\n" ); - for ( count = 0 ; count < 1000 ; count++ ) { - udelay ( 10 ); - efab->mac_op->mac_readl ( efab, ®, - FCN_XM_GLB_CFG_REG_MAC ); - if ( EFAB_DWORD_FIELD ( reg, FCN_XM_CORE_RST ) == 0 ) - return 1; + /* Notice the 8 byte access mode */ + for ( offset = 0x2800000 ; + offset < 0x3000000 ; + offset += 0x8) { + _falcon_writel ( efab, 0, offset ); + _falcon_writel ( efab, 0, offset + 4 ); + wmb(); } - return 0; } -/** - * Get status of 10G link - * - */ -static int falcon_xaui_link_ok ( struct efab_nic *efab ) { - efab_dword_t reg; - int align_done; - int sync_status; - int link_ok = 0; +static int +falcon_reset ( struct efab_nic *efab ) +{ + efab_oword_t glb_ctl_reg_ker; + + /* Initiate software reset */ + EFAB_POPULATE_OWORD_6 ( glb_ctl_reg_ker, + FCN_PCIE_CORE_RST_CTL, EXCLUDE_FROM_RESET, + FCN_PCIE_NSTCK_RST_CTL, EXCLUDE_FROM_RESET, + FCN_PCIE_SD_RST_CTL, EXCLUDE_FROM_RESET, + FCN_EE_RST_CTL, EXCLUDE_FROM_RESET, + FCN_EXT_PHY_RST_DUR, 0x7, /* 10ms */ + FCN_SWRST, 1 ); + + falcon_write ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER ); + + /* Allow 50ms for reset */ + mdelay ( 50 ); - /* Read link status */ - efab->mac_op->mac_readl ( efab, ®, FCN_XX_CORE_STAT_REG_MAC ); - align_done = EFAB_DWORD_FIELD ( reg, FCN_XX_ALIGN_DONE ); - sync_status = EFAB_DWORD_FIELD ( reg, FCN_XX_SYNC_STAT ); - if ( align_done && ( sync_status == FCN_XX_SYNC_STAT_DECODE_SYNCED ) ) { - link_ok = 1; + /* Check for device reset complete */ + falcon_read ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER ); + if ( EFAB_OWORD_FIELD ( glb_ctl_reg_ker, FCN_SWRST ) != 0 ) { + EFAB_ERR ( "Reset failed\n" ); + return -ETIMEDOUT; } - /* Clear link status ready for next read */ - EFAB_SET_DWORD_FIELD ( reg, FCN_XX_COMMA_DET, FCN_XX_COMMA_DET_RESET ); - efab->mac_op->mac_writel ( efab, ®, FCN_XX_CORE_STAT_REG_MAC ); + if ( ( efab->pci_revision == FALCON_REV_B0 ) && !efab->is_asic ) { + clear_b0_fpga_memories ( efab ); + } - return link_ok; + return 0; } -/** - * Initialise XMAC - * +/** Offset of MAC address within EEPROM or Flash */ +#define FALCON_MAC_ADDRESS_OFFSET 0x310 + +/* + * Falcon EEPROM structure */ -static int falcon_init_xmac ( struct efab_nic *efab ) { - efab_dword_t reg; - int count; +#define SF_NV_CONFIG_BASE 0x300 +#define SF_NV_CONFIG_EXTRA 0xA0 + +struct falcon_nv_config_ver2 { + uint16_t nports; + uint8_t port0_phy_addr; + uint8_t port0_phy_type; + uint8_t port1_phy_addr; + uint8_t port1_phy_type; + uint16_t asic_sub_revision; + uint16_t board_revision; + uint8_t mac_location; +}; - if ( !falcon_reset_xmac ( efab ) ) { - EFAB_ERR ( "failed resetting XMAC\n" ); - return 0; +struct falcon_nv_extra { + uint16_t magicnumber; + uint16_t structure_version; + uint16_t checksum; + union { + struct falcon_nv_config_ver2 ver2; + } ver_specific; +}; + +#define BOARD_TYPE(_rev) (_rev >> 8) + +static void +falcon_probe_nic_variant ( struct efab_nic *efab, struct pci_device *pci ) +{ + efab_oword_t altera_build, nic_stat; + int is_pcie, fpga_version; + uint8_t revision; + + /* PCI revision */ + pci_read_config_byte ( pci, PCI_CLASS_REVISION, &revision ); + efab->pci_revision = revision; + + /* Asic vs FPGA */ + falcon_read ( efab, &altera_build, FCN_ALTERA_BUILD_REG_KER ); + fpga_version = EFAB_OWORD_FIELD ( altera_build, FCN_VER_ALL ); + efab->is_asic = (fpga_version == 0); + + /* MAC and PCI type */ + falcon_read ( efab, &nic_stat, FCN_NIC_STAT_REG ); + if ( efab->pci_revision == FALCON_REV_B0 ) { + is_pcie = 1; + efab->phy_10g = EFAB_OWORD_FIELD ( nic_stat, FCN_STRAP_10G ); } - if ( !falcon_reset_xaui ( efab ) ) { - EFAB_ERR ( "failed resetting XAUI\n"); - return 0; + else if ( efab->is_asic ) { + is_pcie = EFAB_OWORD_FIELD ( nic_stat, FCN_STRAP_PCIE ); + efab->phy_10g = EFAB_OWORD_FIELD ( nic_stat, FCN_STRAP_10G ); } + else { + int minor = EFAB_OWORD_FIELD ( altera_build, FCN_VER_MINOR ); + is_pcie = 0; + efab->phy_10g = ( minor == 0x14 ); + } +} - /* CX4 is always 10000FD only */ - efab->link_options = LPA_10000FULL; - - /* Configure MAC */ - EFAB_POPULATE_DWORD_3 ( reg, - FCN_XM_RX_JUMBO_MODE, 1, - FCN_XM_TX_STAT_EN, 1, - FCN_XM_RX_STAT_EN, 1); - efab->mac_op->mac_writel ( efab, ®, FCN_XM_GLB_CFG_REG_MAC ); - - /* Configure TX */ - EFAB_POPULATE_DWORD_6 ( reg, - FCN_XM_TXEN, 1, - FCN_XM_TX_PRMBL, 1, - FCN_XM_AUTO_PAD, 1, - FCN_XM_TXCRC, 1, - FCN_XM_FCNTL, 1, - FCN_XM_IPG, 0x3 ); - efab->mac_op->mac_writel ( efab, ®, FCN_XM_TX_CFG_REG_MAC ); +static void +falcon_init_spi_device ( struct efab_nic *efab, struct spi_device *spi ) +{ + /* Falcon's SPI interface only supports reads/writes of up to 16 bytes. + * Reduce the nvs block size down to satisfy this - which means callers + * should use the nvs_* functions rather than spi_*. */ + if ( spi->nvs.block_size > FALCON_SPI_MAX_LEN ) + spi->nvs.block_size = FALCON_SPI_MAX_LEN; + + spi->bus = &efab->spi_bus; + efab->spi = spi; +} - /* Configure RX */ - EFAB_POPULATE_DWORD_3 ( reg, - FCN_XM_RXEN, 1, - FCN_XM_AUTO_DEPAD, 1, - FCN_XM_PASS_CRC_ERR, 1 ); - efab->mac_op->mac_writel ( efab, ®, FCN_XM_RX_CFG_REG_MAC ); +static int +falcon_probe_spi ( struct efab_nic *efab ) +{ + efab_oword_t nic_stat, gpio_ctl, ee_vpd_cfg; + int has_flash, has_eeprom, ad9bit; - /* Set frame length */ - EFAB_POPULATE_DWORD_1 ( reg, - FCN_XM_MAX_RX_FRM_SIZE, ETH_FRAME_LEN ); - efab->mac_op->mac_writel ( efab, ®, FCN_XM_RX_PARAM_REG_MAC ); - EFAB_POPULATE_DWORD_2 ( reg, - FCN_XM_MAX_TX_FRM_SIZE, ETH_FRAME_LEN, - FCN_XM_TX_JUMBO_MODE, 1 ); - efab->mac_op->mac_writel ( efab, ®, FCN_XM_TX_PARAM_REG_MAC ); + falcon_read ( efab, &nic_stat, FCN_NIC_STAT_REG ); + falcon_read ( efab, &gpio_ctl, FCN_GPIO_CTL_REG_KER ); + falcon_read ( efab, &ee_vpd_cfg, FCN_EE_VPD_CFG_REG ); - /* Set MAC address */ - EFAB_POPULATE_DWORD_4 ( reg, - FCN_XM_ADR_0, efab->mac_addr[0], - FCN_XM_ADR_1, efab->mac_addr[1], - FCN_XM_ADR_2, efab->mac_addr[2], - FCN_XM_ADR_3, efab->mac_addr[3] ); - efab->mac_op->mac_writel ( efab, ®, FCN_XM_ADR_LO_REG_MAC ); - EFAB_POPULATE_DWORD_2 ( reg, - FCN_XM_ADR_4, efab->mac_addr[4], - FCN_XM_ADR_5, efab->mac_addr[5] ); - efab->mac_op->mac_writel ( efab, ®, FCN_XM_ADR_HI_REG_MAC ); + /* determine if FLASH / EEPROM is present */ + if ( ( efab->pci_revision >= FALCON_REV_B0 ) || efab->is_asic ) { + has_flash = EFAB_OWORD_FIELD ( nic_stat, FCN_SF_PRST ); + has_eeprom = EFAB_OWORD_FIELD ( nic_stat, FCN_EE_PRST ); + } else { + has_flash = EFAB_OWORD_FIELD ( gpio_ctl, FCN_FLASH_PRESENT ); + has_eeprom = EFAB_OWORD_FIELD ( gpio_ctl, FCN_EEPROM_PRESENT ); + } + ad9bit = EFAB_OWORD_FIELD ( ee_vpd_cfg, FCN_EE_VPD_EN_AD9_MODE ); - /* Reconfigure MAC wrapper */ - falcon_reconfigure_mac_wrapper ( efab ); + /* Configure the SPI and I2C bus */ + efab->spi_bus.rw = falcon_spi_rw; + init_i2c_bit_basher ( &efab->i2c_bb, &falcon_i2c_bit_ops ); - /** - * Try resetting XAUI on its own waiting for the link - * to come up + /* Configure the EEPROM SPI device. Generally, an Atmel 25040 + * (or similar) is used, but this is only possible if there is also + * a flash device present to store the boot-time chip configuration. */ - for(count=0; count<5; count++) { - /* Check link status */ - efab->link_up = falcon_xaui_link_ok ( efab ); - if ( efab->link_up ) { - /** - * Print out a speed message since we don't have a PHY - */ - EFAB_LOG ( "%dMbps %s-duplex\n", - ( efab->link_options & LPA_10000 ? 1000 : - ( efab->link_options & LPA_1000 ? 1000 : - ( efab->link_options & LPA_100 ? 100 : 10 ) ) ), - ( efab->link_options & LPA_DUPLEX ? "full" : "half" ) ); - break; - } - - if ( !falcon_reset_xaui ( efab ) ) { - EFAB_ERR ( "failed resetting xaui\n" ); - return 0; - } - udelay(100); + if ( has_eeprom ) { + if ( has_flash && ad9bit ) + init_at25040 ( &efab->spi_eeprom ); + else + init_mc25xx640 ( &efab->spi_eeprom ); + falcon_init_spi_device ( efab, &efab->spi_eeprom ); } - return 1; -} + /* Configure the FLASH SPI device */ + if ( has_flash ) { + init_at25f1024 ( &efab->spi_flash ); + falcon_init_spi_device ( efab, &efab->spi_flash ); + } -/** - * Wait for GMII access to complete - * - */ -static int falcon_gmii_wait ( struct efab_nic *efab ) { - efab_oword_t md_stat; - int count; + EFAB_LOG ( "flash is %s, EEPROM is %s%s\n", + ( has_flash ? "present" : "absent" ), + ( has_eeprom ? "present " : "absent" ), + ( has_eeprom ? (ad9bit ? "(9bit)" : "(16bit)") : "") ); - for ( count = 0 ; count < 1000 ; count++ ) { - udelay ( 10 ); - falcon_read ( efab, &md_stat, FCN_MD_STAT_REG_KER ); - if ( EFAB_OWORD_FIELD ( md_stat, FCN_MD_BSY ) == 0 ) - return 1; + /* The device MUST have flash or eeprom */ + if ( ! efab->spi ) { + EFAB_ERR ( "Device appears to have no flash or eeprom\n" ); + return -EIO; } - EFAB_ERR ( "Timed out waiting for GMII\n" ); + + /* If the device has EEPROM attached, then advertise NVO space */ + if ( has_eeprom ) + nvo_init ( &efab->nvo, &efab->spi_eeprom.nvs, falcon_nvo_fragments, + &efab->netdev->refcnt ); + return 0; } +static int +falcon_probe_nvram ( struct efab_nic *efab ) +{ + struct nvs_device *nvs = &efab->spi->nvs; + struct falcon_nv_extra nv; + int rc, board_revision; + + /* Read the MAC address */ + rc = nvs_read ( nvs, FALCON_MAC_ADDRESS_OFFSET, + efab->mac_addr, ETH_ALEN ); + if ( rc ) + return rc; + + /* Poke through the NVRAM structure for the PHY type. */ + rc = nvs_read ( nvs, SF_NV_CONFIG_BASE + SF_NV_CONFIG_EXTRA, + &nv, sizeof ( nv ) ); + if ( rc ) + return rc; + + /* Handle each supported NVRAM version */ + if ( ( le16_to_cpu ( nv.magicnumber ) == FCN_NV_MAGIC_NUMBER ) && + ( le16_to_cpu ( nv.structure_version ) >= 2 ) ) { + struct falcon_nv_config_ver2* ver2 = &nv.ver_specific.ver2; + + /* Get the PHY type */ + efab->phy_addr = le16_to_cpu ( ver2->port0_phy_addr ); + efab->phy_type = le16_to_cpu ( ver2->port0_phy_type ); + board_revision = le16_to_cpu ( ver2->board_revision ); + } + else { + EFAB_ERR ( "NVram is not recognised\n" ); + return -EINVAL; + } + + efab->board_type = BOARD_TYPE ( board_revision ); + + EFAB_TRACE ( "Falcon board %d phy %d @ addr %d\n", + efab->board_type, efab->phy_type, efab->phy_addr ); -static struct efab_mac_operations falcon_xmac_operations = { - .mac_readl = falcon_xmac_readl, - .mac_writel = falcon_xmac_writel, - .init = falcon_init_xmac, - .reset = falcon_reset_xmac, -}; + /* Patch in the board operations */ + switch ( efab->board_type ) { + case EFAB_BOARD_SFE4001: + efab->board_op = &sfe4001_ops; + break; + case EFAB_BOARD_SFE4002: + efab->board_op = &sfe4002_ops; + break; + case EFAB_BOARD_SFE4003: + efab->board_op = &sfe4003_ops; + break; + default: + EFAB_ERR ( "Unrecognised board type\n" ); + return -EINVAL; + } -static struct efab_mac_operations falcon_gmac_operations = { - .mac_readl = falcon_gmac_readl, - .mac_writel = falcon_gmac_writel, - .init = falcon_init_gmac, - .reset = falcon_reset_gmac, -}; + /* Patch in MAC operations */ + if ( efab->phy_10g ) + efab->mac_op = &falcon_xmac_operations; + else + efab->mac_op = &falcon_gmac_operations; + + /* Hook in the PHY ops */ + switch ( efab->phy_type ) { + case PHY_TYPE_10XPRESS: + efab->phy_op = &falcon_tenxpress_phy_ops; + break; + case PHY_TYPE_CX4: + efab->phy_op = &falcon_xaui_phy_ops; + break; + case PHY_TYPE_XFP: + efab->phy_op = &falcon_xfp_phy_ops; + break; + case PHY_TYPE_CX4_RTMR: + efab->phy_op = &falcon_txc_phy_ops; + break; + case PHY_TYPE_PM8358: + efab->phy_op = &falcon_pm8358_phy_ops; + break; + case PHY_TYPE_1GIG_ALASKA: + efab->phy_op = &falcon_alaska_phy_ops; + break; + default: + EFAB_ERR ( "Unknown PHY type: %d\n", efab->phy_type ); + return -EINVAL; + } + return 0; +} -/** - * Initialise NIC - * - */ -static int falcon_init_nic ( struct efab_nic *efab ) { +static int +falcon_init_sram ( struct efab_nic *efab ) +{ efab_oword_t reg; - efab_dword_t timer_cmd; - int version, minor; + int count; /* use card in internal SRAM mode */ falcon_read ( efab, ®, FCN_NIC_STAT_REG ); - EFAB_SET_OWORD_FIELD ( reg, ONCHIP_SRAM, 1 ); + EFAB_SET_OWORD_FIELD ( reg, FCN_ONCHIP_SRAM, 1 ); falcon_write ( efab, ®, FCN_NIC_STAT_REG ); - wmb(); - /* identify FPGA/ASIC, and strapping mode */ - falcon_read ( efab, ®, ALTERA_BUILD_REG_KER ); - version = EFAB_OWORD_FIELD ( reg, VER_ALL ); - efab->is_asic = version ? 0 : 1; - - if ( efab->is_asic ) { - falcon_read ( efab, ®, FCN_NIC_STAT_REG ); - if ( EFAB_OWORD_FIELD ( reg, STRAP_10G ) ) { - efab->is_10g = 1; - } - if ( EFAB_OWORD_FIELD ( reg, STRAP_DUAL_PORT ) ) { - efab->is_dual = 1; - } - } - else { - falcon_read ( efab, ®, ALTERA_BUILD_REG_KER ); - minor = EFAB_OWORD_FIELD ( reg, VER_MINOR ); - - if ( minor == 0x14 ) { - efab->is_10g = 1; - } else if ( minor == 0x13 ) { - efab->is_dual = 1; - } - } + /* Deactivate any external SRAM that might be present */ + EFAB_POPULATE_OWORD_2 ( reg, + FCN_GPIO1_OEN, 1, + FCN_GPIO1_OUT, 1 ); + falcon_write ( efab, ®, FCN_GPIO_CTL_REG_KER ); - DBG ( "NIC type: %s %dx%s\n", - efab->is_asic ? "ASIC" : "FPGA", - efab->is_dual ? 2 : 1, - efab->is_10g ? "10G" : "1G" ); + /* Initiate SRAM reset */ + EFAB_POPULATE_OWORD_2 ( reg, + FCN_SRAM_OOB_BT_INIT_EN, 1, + FCN_SRM_NUM_BANKS_AND_BANK_SIZE, 0 ); + falcon_write ( efab, ®, FCN_SRM_CFG_REG_KER ); - /* patch in MAC operations */ - if ( efab->is_10g ) - efab->mac_op = &falcon_xmac_operations; - else - efab->mac_op = &falcon_gmac_operations; - - if ( !efab->is_dual && ( efab->port == 1 ) ) { - /* device doesn't exist */ - return 0; - } + /* Wait for SRAM reset to complete */ + count = 0; + do { + /* SRAM reset is slow; expect around 16ms */ + mdelay ( 20 ); - /* determine EEPROM / FLASH */ - if ( efab->is_asic ) { - falcon_read ( efab, ®, FCN_NIC_STAT_REG ); - efab->has_flash = EFAB_OWORD_FIELD ( reg, SF_PRST ); - efab->has_eeprom = EFAB_OWORD_FIELD ( reg, EE_PRST ); - } else { - falcon_read ( efab, ®, FCN_GPIO_CTL_REG_KER ); - efab->has_flash = EFAB_OWORD_FIELD ( reg, FCN_FLASH_PRESENT ); - efab->has_eeprom = EFAB_OWORD_FIELD ( reg, FCN_EEPROM_PRESENT); - } - DBG ( "flash is %s, EEPROM is %s\n", - ( efab->has_flash ? "present" : "absent" ), - ( efab->has_eeprom ? "present" : "absent" ) ); - falcon_init_spi ( efab ); + /* Check for reset complete */ + falcon_read ( efab, ®, FCN_SRM_CFG_REG_KER ); + if ( !EFAB_OWORD_FIELD ( reg, FCN_SRAM_OOB_BT_INIT_EN ) ) + return 0; + } while (++count < 20); /* wait upto 0.4 sec */ + + EFAB_ERR ( "timed out waiting for SRAM reset\n"); + return -ETIMEDOUT; +} + +static void +falcon_setup_nic ( struct efab_nic *efab ) +{ + efab_dword_t timer_cmd; + efab_oword_t reg; + int tx_fc, xoff_thresh, xon_thresh; + /* bug5129: Clear the parity enables on the TX data fifos as + * they produce false parity errors because of timing issues + */ + falcon_read ( efab, ®, FCN_SPARE_REG_KER ); + EFAB_SET_OWORD_FIELD ( reg, FCN_MEM_PERR_EN_TX_DATA, 0 ); + falcon_write ( efab, ®, FCN_SPARE_REG_KER ); + /* Set up TX and RX descriptor caches in SRAM */ - EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_TX_DC_BASE_ADR, - 0x130000 /* recommended in datasheet */ ); + EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_TX_DC_BASE_ADR, 0x130000 ); falcon_write ( efab, ®, FCN_SRM_TX_DC_CFG_REG_KER ); - EFAB_POPULATE_OWORD_1 ( reg, FCN_TX_DC_SIZE, 2 /* 32 descriptors */ ); + EFAB_POPULATE_OWORD_1 ( reg, FCN_TX_DC_SIZE, 1 /* 16 descriptors */ ); falcon_write ( efab, ®, FCN_TX_DC_CFG_REG_KER ); - EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_RX_DC_BASE_ADR, - 0x100000 /* recommended in datasheet */ ); + EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_RX_DC_BASE_ADR, 0x100000 ); falcon_write ( efab, ®, FCN_SRM_RX_DC_CFG_REG_KER ); EFAB_POPULATE_OWORD_1 ( reg, FCN_RX_DC_SIZE, 2 /* 32 descriptors */ ); falcon_write ( efab, ®, FCN_RX_DC_CFG_REG_KER ); - /* Set number of RSS CPUs */ - EFAB_POPULATE_OWORD_1 ( reg, FCN_NUM_KER, 0 ); + /* Set number of RSS CPUs + * bug7244: Increase filter depth to reduce RX_RESET likelyhood + */ + EFAB_POPULATE_OWORD_5 ( reg, + FCN_NUM_KER, 0, + FCN_UDP_FULL_SRCH_LIMIT, 8, + FCN_UDP_WILD_SRCH_LIMIT, 8, + FCN_TCP_WILD_SRCH_LIMIT, 8, + FCN_TCP_FULL_SRCH_LIMIT, 8); falcon_write ( efab, ®, FCN_RX_FILTER_CTL_REG_KER ); udelay ( 1000 ); + + /* Setup RX. Wait for descriptor is broken and must + * be disabled. RXDP recovery shouldn't be needed, but is. + * disable ISCSI parsing because we don't need it + */ + falcon_read ( efab, ®, FCN_RX_SELF_RST_REG_KER ); + EFAB_SET_OWORD_FIELD ( reg, FCN_RX_NODESC_WAIT_DIS, 1 ); + EFAB_SET_OWORD_FIELD ( reg, FCN_RX_RECOVERY_EN, 1 ); + EFAB_SET_OWORD_FIELD ( reg, FCN_RX_ISCSI_DIS, 1 ); + falcon_write ( efab, ®, FCN_RX_SELF_RST_REG_KER ); - /* Reset the MAC */ - mentormac_reset ( efab ); + /* Determine recommended flow control settings. * + * Flow control is qualified on B0 and A1/1G, not on A1/10G */ + if ( efab->pci_revision == FALCON_REV_B0 ) { + tx_fc = 1; + xoff_thresh = 54272; /* ~80Kb - 3*max MTU */ + xon_thresh = 27648; /* ~3*max MTU */ + } + else if ( !efab->phy_10g ) { + tx_fc = 1; + xoff_thresh = 2048; + xon_thresh = 512; + } + else { + tx_fc = xoff_thresh = xon_thresh = 0; + } - /* Set up event queue */ - falcon_create_special_buffer ( efab, efab->eventq, FALCON_EVQ_ID ); - /* Fill eventq with all ones ( empty events ) */ - memset(efab->eventq, 0xff, 4096); - /* push eventq to card */ - EFAB_POPULATE_OWORD_3 ( reg, - FCN_EVQ_EN, 1, - FCN_EVQ_SIZE, FCN_EVQ_SIZE_512, - FCN_EVQ_BUF_BASE_ID, FALCON_EVQ_ID ); - falcon_write ( efab, ®, FCN_EVQ_PTR_TBL_KER ); - udelay ( 1000 ); + /* Setup TX and RX */ + falcon_read ( efab, ®, FCN_TX_CFG2_REG_KER ); + EFAB_SET_OWORD_FIELD ( reg, FCN_TX_DIS_NON_IP_EV, 1 ); + falcon_write ( efab, ®, FCN_TX_CFG2_REG_KER ); + + falcon_read ( efab, ®, FCN_RX_CFG_REG_KER ); + EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_USR_BUF_SIZE, + (3*4096) / 32 ); + if ( efab->pci_revision == FALCON_REV_B0) + EFAB_SET_OWORD_FIELD ( reg, FCN_RX_INGR_EN_B0, 1 ); + EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_XON_MAC_TH, + xon_thresh / 256); + EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_XOFF_MAC_TH, + xoff_thresh / 256); + EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_XOFF_MAC_EN, tx_fc); + falcon_write ( efab, ®, FCN_RX_CFG_REG_KER ); /* Set timer register */ EFAB_POPULATE_DWORD_2 ( timer_cmd, FCN_TIMER_MODE, FCN_TIMER_MODE_DIS, FCN_TIMER_VAL, 0 ); falcon_writel ( efab, &timer_cmd, FCN_TIMER_CMD_REG_KER ); - udelay ( 1000 ); +} + +static void +falcon_init_resources ( struct efab_nic *efab ) +{ + struct efab_ev_queue *ev_queue = &efab->ev_queue; + struct efab_rx_queue *rx_queue = &efab->rx_queue; + struct efab_tx_queue *tx_queue = &efab->tx_queue; + + efab_oword_t reg; + int jumbo; - /* Initialise event queue read pointer */ - falcon_eventq_read_ack ( efab ); + /* Initialise the ptrs */ + tx_queue->read_ptr = tx_queue->write_ptr = 0; + rx_queue->read_ptr = rx_queue->write_ptr = 0; + ev_queue->read_ptr = 0; + + /* Push the event queue to the hardware */ + EFAB_POPULATE_OWORD_3 ( reg, + FCN_EVQ_EN, 1, + FCN_EVQ_SIZE, FQS(FCN_EVQ, EFAB_EVQ_SIZE), + FCN_EVQ_BUF_BASE_ID, ev_queue->entry.id ); + falcon_write ( efab, ®, + FCN_REVISION_REG ( efab, FCN_EVQ_PTR_TBL_KER ) ); - /* Set up TX descriptor ring */ - falcon_create_special_buffer ( efab, efab->txd, FALCON_TXD_ID ); - EFAB_POPULATE_OWORD_5 ( reg, + /* Push the tx queue to the hardware */ + EFAB_POPULATE_OWORD_8 ( reg, FCN_TX_DESCQ_EN, 1, - FCN_TX_DESCQ_BUF_BASE_ID, FALCON_TXD_ID, + FCN_TX_ISCSI_DDIG_EN, 0, + FCN_TX_ISCSI_DDIG_EN, 0, + FCN_TX_DESCQ_BUF_BASE_ID, tx_queue->entry.id, FCN_TX_DESCQ_EVQ_ID, 0, - FCN_TX_DESCQ_SIZE, FCN_TX_DESCQ_SIZE_512, - FCN_TX_DESCQ_TYPE, 0 /* kernel queue */ ); - falcon_write ( efab, ®, FCN_TX_DESC_PTR_TBL_KER ); - - /* Set up RX descriptor ring */ - falcon_create_special_buffer ( efab, efab->rxd, FALCON_RXD_ID ); - EFAB_POPULATE_OWORD_6 ( reg, - FCN_RX_DESCQ_BUF_BASE_ID, FALCON_RXD_ID, + FCN_TX_DESCQ_SIZE, FQS(FCN_TX_DESCQ, EFAB_TXD_SIZE), + FCN_TX_DESCQ_TYPE, 0 /* kernel queue */, + FCN_TX_NON_IP_DROP_DIS_B0, 1 ); + falcon_write ( efab, ®, + FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) ); + + /* Push the rx queue to the hardware */ + jumbo = ( efab->pci_revision == FALCON_REV_B0 ) ? 0 : 1; + EFAB_POPULATE_OWORD_8 ( reg, + FCN_RX_ISCSI_DDIG_EN, 0, + FCN_RX_ISCSI_HDIG_EN, 0, + FCN_RX_DESCQ_BUF_BASE_ID, rx_queue->entry.id, FCN_RX_DESCQ_EVQ_ID, 0, - FCN_RX_DESCQ_SIZE, FCN_RX_DESCQ_SIZE_512, + FCN_RX_DESCQ_SIZE, FQS(FCN_RX_DESCQ, EFAB_RXD_SIZE), FCN_RX_DESCQ_TYPE, 0 /* kernel queue */, - FCN_RX_DESCQ_JUMBO, 1, + FCN_RX_DESCQ_JUMBO, jumbo, FCN_RX_DESCQ_EN, 1 ); - falcon_write ( efab, ®, FCN_RX_DESC_PTR_TBL_KER ); + falcon_write ( efab, ®, + FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) ); /* Program INT_ADR_REG_KER */ EFAB_POPULATE_OWORD_1 ( reg, - FCN_INT_ADR_KER, - virt_to_bus ( &efab->int_ker ) ); + FCN_INT_ADR_KER, virt_to_bus ( &efab->int_ker ) ); falcon_write ( efab, ®, FCN_INT_ADR_REG_KER ); - udelay ( 1000 ); - /* Register non-volatile storage */ - if ( efab->has_eeprom ) { - nvo_init ( &efab->nvo, &efab->falcon_eeprom.nvs, - falcon_eeprom_fragments, NULL /* hack */ ); - if ( register_nvo ( &efab->nvo, NULL /* hack */ ) != 0 ) - return 0; - } + /* Ack the event queue */ + falcon_eventq_read_ack ( efab, ev_queue ); +} - return 1; +static void +falcon_fini_resources ( struct efab_nic *efab ) +{ + efab_oword_t cmd; + + /* Disable interrupts */ + falcon_interrupts ( efab, 0, 0 ); + + /* Flush the dma queues */ + EFAB_POPULATE_OWORD_2 ( cmd, + FCN_TX_FLUSH_DESCQ_CMD, 1, + FCN_TX_FLUSH_DESCQ, 0 ); + falcon_write ( efab, &cmd, + FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) ); + + EFAB_POPULATE_OWORD_2 ( cmd, + FCN_RX_FLUSH_DESCQ_CMD, 1, + FCN_RX_FLUSH_DESCQ, 0 ); + falcon_write ( efab, &cmd, + FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) ); + + mdelay ( 100 ); + + /* Remove descriptor rings from card */ + EFAB_ZERO_OWORD ( cmd ); + falcon_write ( efab, &cmd, + FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) ); + falcon_write ( efab, &cmd, + FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) ); + falcon_write ( efab, &cmd, + FCN_REVISION_REG ( efab, FCN_EVQ_PTR_TBL_KER ) ); } -/** MDIO write */ -static void falcon_mdio_write ( struct efab_nic *efab, int location, - int value ) { - int phy_id = efab->port + 2; - efab_oword_t reg; +/******************************************************************************* + * + * + * Hardware rx path + * + * + *******************************************************************************/ - EFAB_TRACE ( "Writing GMII %d register %02x with %04x\n", - phy_id, location, value ); +static void +falcon_build_rx_desc ( falcon_rx_desc_t *rxd, struct io_buffer *iob ) +{ + EFAB_POPULATE_QWORD_2 ( *rxd, + FCN_RX_KER_BUF_SIZE, EFAB_RX_BUF_SIZE, + FCN_RX_KER_BUF_ADR, virt_to_bus ( iob->data ) ); +} - /* Check MII not currently being accessed */ - if ( ! falcon_gmii_wait ( efab ) ) - return; +static void +falcon_notify_rx_desc ( struct efab_nic *efab, struct efab_rx_queue *rx_queue ) +{ + efab_dword_t reg; + int ptr = rx_queue->write_ptr % EFAB_RXD_SIZE; - /* Write the address registers */ - EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, 0 /* phy_id ? */ ); - falcon_write ( efab, ®, FCN_MD_PHY_ADR_REG_KER ); - udelay ( 10 ); - EFAB_POPULATE_OWORD_2 ( reg, - FCN_MD_PRT_ADR, phy_id, - FCN_MD_DEV_ADR, location ); - falcon_write ( efab, ®, FCN_MD_ID_REG_KER ); - udelay ( 10 ); + EFAB_POPULATE_DWORD_1 ( reg, FCN_RX_DESC_WPTR_DWORD, ptr ); + falcon_writel ( efab, ®, FCN_RX_DESC_UPD_REG_KER_DWORD ); +} - /* Write data */ - EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_TXD, value ); - falcon_write ( efab, ®, FCN_MD_TXD_REG_KER ); - udelay ( 10 ); - EFAB_POPULATE_OWORD_2 ( reg, - FCN_MD_WRC, 1, - FCN_MD_GC, 1 ); - falcon_write ( efab, ®, FCN_MD_CS_REG_KER ); - udelay ( 10 ); - - /* Wait for data to be written */ - falcon_gmii_wait ( efab ); + +/******************************************************************************* + * + * + * Hardware tx path + * + * + *******************************************************************************/ + +static void +falcon_build_tx_desc ( falcon_tx_desc_t *txd, struct io_buffer *iob ) +{ + EFAB_POPULATE_QWORD_2 ( *txd, + FCN_TX_KER_BYTE_CNT, iob_len ( iob ), + FCN_TX_KER_BUF_ADR, virt_to_bus ( iob->data ) ); } -/** MDIO read */ -static int falcon_mdio_read ( struct efab_nic *efab, int location ) { - int phy_id = efab->port + 2; - efab_oword_t reg; - int value; +static void +falcon_notify_tx_desc ( struct efab_nic *efab, + struct efab_tx_queue *tx_queue ) +{ + efab_dword_t reg; + int ptr = tx_queue->write_ptr % EFAB_TXD_SIZE; - /* Check MII not currently being accessed */ - if ( ! falcon_gmii_wait ( efab ) ) - return 0xffff; + EFAB_POPULATE_DWORD_1 ( reg, FCN_TX_DESC_WPTR_DWORD, ptr ); + falcon_writel ( efab, ®, FCN_TX_DESC_UPD_REG_KER_DWORD ); +} - /* Write the address registers */ - EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, 0 /* phy_id ? */ ); - falcon_write ( efab, ®, FCN_MD_PHY_ADR_REG_KER ); - udelay ( 10 ); - EFAB_POPULATE_OWORD_2 ( reg, - FCN_MD_PRT_ADR, phy_id, - FCN_MD_DEV_ADR, location ); - falcon_write ( efab, ®, FCN_MD_ID_REG_KER ); - udelay ( 10 ); - /* Request data to be read */ - EFAB_POPULATE_OWORD_2 ( reg, - FCN_MD_RIC, 1, - FCN_MD_GC, 1 ); - falcon_write ( efab, ®, FCN_MD_CS_REG_KER ); - udelay ( 10 ); - - /* Wait for data to become available */ - falcon_gmii_wait ( efab ); +/******************************************************************************* + * + * + * Software receive interface + * + * + *******************************************************************************/ + +static int +efab_fill_rx_queue ( struct efab_nic *efab, + struct efab_rx_queue *rx_queue ) +{ + int fill_level = rx_queue->write_ptr - rx_queue->read_ptr; + int space = EFAB_NUM_RX_DESC - fill_level - 1; + int pushed = 0; + + while ( space ) { + int buf_id = rx_queue->write_ptr % EFAB_NUM_RX_DESC; + int desc_id = rx_queue->write_ptr % EFAB_RXD_SIZE; + struct io_buffer *iob; + falcon_rx_desc_t *rxd; + + assert ( rx_queue->buf[buf_id] == NULL ); + iob = alloc_iob ( EFAB_RX_BUF_SIZE ); + if ( !iob ) + break; - /* Read the data */ - falcon_read ( efab, ®, FCN_MD_RXD_REG_KER ); - value = EFAB_OWORD_FIELD ( reg, FCN_MD_RXD ); + EFAB_TRACE ( "pushing rx_buf[%d] iob %p data %p\n", + buf_id, iob, iob->data ); - EFAB_TRACE ( "Read from GMII %d register %02x, got %04x\n", - phy_id, location, value ); + rx_queue->buf[buf_id] = iob; + rxd = rx_queue->ring + desc_id; + falcon_build_rx_desc ( rxd, iob ); + ++rx_queue->write_ptr; + ++pushed; + --space; + } - return value; + if ( pushed ) { + /* Push the ptr to hardware */ + falcon_notify_rx_desc ( efab, rx_queue ); + + fill_level = rx_queue->write_ptr - rx_queue->read_ptr; + EFAB_TRACE ( "pushed %d rx buffers to fill level %d\n", + pushed, fill_level ); + } + + if ( fill_level == 0 ) + return -ENOMEM; + return 0; } + +static void +efab_receive ( struct efab_nic *efab, unsigned int id, int len, int drop ) +{ + struct efab_rx_queue *rx_queue = &efab->rx_queue; + struct io_buffer *iob; + unsigned int read_ptr = rx_queue->read_ptr % EFAB_RXD_SIZE; + unsigned int buf_ptr = rx_queue->read_ptr % EFAB_NUM_RX_DESC; -static struct efab_operations falcon_operations = { - .get_membase = falcon_get_membase, - .reset = falcon_reset, - .init_nic = falcon_init_nic, - .read_eeprom = falcon_read_eeprom, - .build_rx_desc = falcon_build_rx_desc, - .notify_rx_desc = falcon_notify_rx_desc, - .build_tx_desc = falcon_build_tx_desc, - .notify_tx_desc = falcon_notify_tx_desc, - .fetch_event = falcon_fetch_event, - .mask_irq = falcon_mask_irq, - .generate_irq = falcon_generate_irq, - .mdio_write = falcon_mdio_write, - .mdio_read = falcon_mdio_read, -}; + assert ( id == read_ptr ); + + /* Pop this rx buffer out of the software ring */ + iob = rx_queue->buf[buf_ptr]; + rx_queue->buf[buf_ptr] = NULL; -/************************************************************************** + EFAB_TRACE ( "popping rx_buf[%d] iob %p data %p with %d bytes %s\n", + id, iob, iob->data, len, drop ? "bad" : "ok" ); + + /* Pass the packet up if required */ + if ( drop ) + free_iob ( iob ); + else { + iob_put ( iob, len ); + netdev_rx ( efab->netdev, iob ); + } + + ++rx_queue->read_ptr; +} + +/******************************************************************************* * - * Etherfabric abstraction layer * - ************************************************************************** - */ - -/** - * Push RX buffer to RXD ring + * Software transmit interface * - */ -static inline void efab_push_rx_buffer ( struct efab_nic *efab, - struct efab_rx_buf *rx_buf ) { - /* Create RX descriptor */ - rx_buf->id = efab->rx_write_ptr; - efab->op->build_rx_desc ( efab, rx_buf ); + * + *******************************************************************************/ - /* Update RX write pointer */ - efab->rx_write_ptr = ( efab->rx_write_ptr + 1 ) % EFAB_RXD_SIZE; - efab->op->notify_rx_desc ( efab ); +static int +efab_transmit ( struct net_device *netdev, struct io_buffer *iob ) +{ + struct efab_nic *efab = netdev_priv ( netdev ); + struct efab_tx_queue *tx_queue = &efab->tx_queue; + int fill_level, space; + falcon_tx_desc_t *txd; + int buf_id; + + fill_level = tx_queue->write_ptr - tx_queue->read_ptr; + space = EFAB_TXD_SIZE - fill_level - 1; + if ( space < 1 ) + return -ENOBUFS; + + /* Save the iobuffer for later completion */ + buf_id = tx_queue->write_ptr % EFAB_TXD_SIZE; + assert ( tx_queue->buf[buf_id] == NULL ); + tx_queue->buf[buf_id] = iob; + + EFAB_TRACE ( "tx_buf[%d] for iob %p data %p len %d\n", + buf_id, iob, iob->data, iob_len ( iob ) ); + + /* Form the descriptor, and push it to hardware */ + txd = tx_queue->ring + buf_id; + falcon_build_tx_desc ( txd, iob ); + ++tx_queue->write_ptr; + falcon_notify_tx_desc ( efab, tx_queue ); - DBG ( "Added RX id %x\n", rx_buf->id ); + return 0; } -/** - * Push TX buffer to TXD ring - * - */ -static inline void efab_push_tx_buffer ( struct efab_nic *efab, - struct efab_tx_buf *tx_buf ) { - /* Create TX descriptor */ - tx_buf->id = efab->tx_write_ptr; - efab->op->build_tx_desc ( efab, tx_buf ); +static int +efab_transmit_done ( struct efab_nic *efab, int id ) +{ + struct efab_tx_queue *tx_queue = &efab->tx_queue; + unsigned int read_ptr, stop; - /* Update TX write pointer */ - efab->tx_write_ptr = ( efab->tx_write_ptr + 1 ) % EFAB_TXD_SIZE; - efab->op->notify_tx_desc ( efab ); + /* Complete all buffers from read_ptr up to and including id */ + read_ptr = tx_queue->read_ptr % EFAB_TXD_SIZE; + stop = ( id + 1 ) % EFAB_TXD_SIZE; - DBG ( "Added TX id %x\n", tx_buf->id ); + while ( read_ptr != stop ) { + struct io_buffer *iob = tx_queue->buf[read_ptr]; + assert ( iob ); + + /* Complete the tx buffer */ + if ( iob ) + netdev_tx_complete ( efab->netdev, iob ); + tx_queue->buf[read_ptr] = NULL; + + ++tx_queue->read_ptr; + read_ptr = tx_queue->read_ptr % EFAB_TXD_SIZE; + } + + return 0; } -/** - * Initialise MAC and wait for link up +/******************************************************************************* * - */ -static int efab_init_mac ( struct efab_nic *efab ) { - int count; + * + * Hardware event path + * + * + *******************************************************************************/ - /* This can take several seconds */ - EFAB_LOG ( "Waiting for link.." ); - for ( count=0; count<5; count++ ) { - putchar ( '.' ); +static void +falcon_clear_interrupts ( struct efab_nic *efab ) +{ + efab_dword_t reg; - if ( ! efab->mac_op->init ( efab ) ) { - EFAB_ERR ( "Failed reinitialising MAC\n" ); - return 0; - } - if ( efab->link_up ) { - /* PHY init printed the message for us */ - return 1; - } - EFAB_ERR( "link is down" ); - sleep ( 1 ); + if ( efab->pci_revision == FALCON_REV_B0 ) { + /* read the ISR */ + falcon_readl( efab, ®, INT_ISR0_B0 ); + } + else { + /* write to the INT_ACK register */ + falcon_writel ( efab, 0, FCN_INT_ACK_KER_REG_A1 ); + mb(); + falcon_readl ( efab, ®, + WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 ); } - EFAB_ERR ( " timed initialising MAC\n " ); +} - return 0; +static void +falcon_handle_event ( struct efab_nic *efab, falcon_event_t *evt ) +{ + int ev_code, desc_ptr, len, drop; + + /* Decode event */ + ev_code = EFAB_QWORD_FIELD ( *evt, FCN_EV_CODE ); + switch ( ev_code ) { + case FCN_TX_IP_EV_DECODE: + desc_ptr = EFAB_QWORD_FIELD ( *evt, FCN_TX_EV_DESC_PTR ); + efab_transmit_done ( efab, desc_ptr ); + break; + + case FCN_RX_IP_EV_DECODE: + desc_ptr = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_DESC_PTR ); + len = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_BYTE_CNT ); + drop = !EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_PKT_OK ); + + efab_receive ( efab, desc_ptr, len, drop ); + break; + + default: + EFAB_TRACE ( "Unknown event type %d\n", ev_code ); + break; + } } -/** - * Initialise NIC +/******************************************************************************* * - */ -static int efab_init_nic ( struct efab_nic *efab ) { - int i; + * + * Software (polling) interrupt handler + * + * + *******************************************************************************/ - /* Initialise NIC */ - if ( ! efab->op->init_nic ( efab ) ) - return 0; +static void +efab_poll ( struct net_device *netdev ) +{ + struct efab_nic *efab = netdev_priv ( netdev ); + struct efab_ev_queue *ev_queue = &efab->ev_queue; + struct efab_rx_queue *rx_queue = &efab->rx_queue; + falcon_event_t *evt; - /* Push RX descriptors */ - for ( i = 0 ; i < EFAB_RX_BUFS ; i++ ) { - efab_push_rx_buffer ( efab, &efab->rx_bufs[i] ); + /* Read the event queue by directly looking for events + * (we don't even bother to read the eventq write ptr) */ + evt = ev_queue->ring + ev_queue->read_ptr; + while ( falcon_event_present ( evt ) ) { + + EFAB_TRACE ( "Event at index 0x%x address %p is " + EFAB_QWORD_FMT "\n", ev_queue->read_ptr, + evt, EFAB_QWORD_VAL ( *evt ) ); + + falcon_handle_event ( efab, evt ); + + /* Clear the event */ + EFAB_SET_QWORD ( *evt ); + + /* Move to the next event. We don't ack the event + * queue until the end */ + ev_queue->read_ptr = ( ( ev_queue->read_ptr + 1 ) % + EFAB_EVQ_SIZE ); + evt = ev_queue->ring + ev_queue->read_ptr; } - /* Read MAC address from EEPROM */ - if ( ! efab->op->read_eeprom ( efab ) ) - return 0; + /* Push more buffers if needed */ + (void) efab_fill_rx_queue ( efab, rx_queue ); - /* Initialise MAC and wait for link up */ - if ( ! efab_init_mac ( efab ) ) - return 0; + /* Clear any pending interrupts */ + falcon_clear_interrupts ( efab ); - return 1; + /* Ack the event queue */ + falcon_eventq_read_ack ( efab, ev_queue ); } -/************************************************************************** +static void +efab_irq ( struct net_device *netdev, int enable ) +{ + struct efab_nic *efab = netdev_priv ( netdev ); + struct efab_ev_queue *ev_queue = &efab->ev_queue; + + switch ( enable ) { + case 0: + falcon_interrupts ( efab, 0, 0 ); + break; + case 1: + falcon_interrupts ( efab, 1, 0 ); + falcon_eventq_read_ack ( efab, ev_queue ); + break; + case 2: + falcon_interrupts ( efab, 1, 1 ); + break; + } +} + +/******************************************************************************* * - * Etherboot interface * - ************************************************************************** - */ + * Software open/close + * + * + *******************************************************************************/ -/************************************************************************** -POLL - Wait for a frame -***************************************************************************/ -static int etherfabric_poll ( struct nic *nic, int retrieve ) { - struct efab_nic *efab = nic->priv_data; - struct efab_event event; - static struct efab_rx_buf *rx_buf = NULL; - int i, drop = 0; - - /* Process the event queue until we hit either a packet - * received event or an empty event slot. - */ - while ( ( rx_buf == NULL ) && - efab->op->fetch_event ( efab, &event ) ) { - drop = event.drop; - if ( event.type == EFAB_EV_TX ) { - /* TX completed - mark as done */ - DBG ( "TX id %x complete\n", - efab->tx_buf.id ); - } else if ( event.type == EFAB_EV_RX ) { - /* RX - find corresponding buffer */ - for ( i = 0 ; i < EFAB_RX_BUFS ; i++ ) { - if ( efab->rx_bufs[i].id == event.rx_id ) { - rx_buf = &efab->rx_bufs[i]; - rx_buf->len = event.rx_len; - DBG ( "RX id %x (len %x) received\n", - rx_buf->id, rx_buf->len ); - break; - } - } - if ( ! rx_buf ) { - EFAB_ERR ( "Invalid RX ID %x\n", event.rx_id ); - } - } else if ( event.type == EFAB_EV_NONE ) { - DBG ( "Ignorable event\n" ); - } else { - DBG ( "Unknown event\n" ); - } - } +static void +efab_free_resources ( struct efab_nic *efab ) +{ + struct efab_ev_queue *ev_queue = &efab->ev_queue; + struct efab_rx_queue *rx_queue = &efab->rx_queue; + struct efab_tx_queue *tx_queue = &efab->tx_queue; + int i; - /* If there is no packet, return 0 */ - if ( ! rx_buf ) - return 0; + for ( i = 0; i < EFAB_NUM_RX_DESC; i++ ) { + if ( rx_queue->buf[i] ) + free_iob ( rx_queue->buf[i] ); + } - /* drop this event if necessary */ - if ( drop ) { - DBG( "discarding RX event\n" ); - return 0; + for ( i = 0; i < EFAB_TXD_SIZE; i++ ) { + if ( tx_queue->buf[i] ) + netdev_tx_complete ( efab->netdev, tx_queue->buf[i] ); } - /* If we don't want to retrieve it just yet, return 1 */ - if ( ! retrieve ) - return 1; + if ( rx_queue->ring ) + falcon_free_special_buffer ( rx_queue->ring ); - /* There seems to be a hardware race. The event can show up - * on the event FIFO before the DMA has completed, so we - * insert a tiny delay. If this proves unreliable, we should - * switch to using event DMA rather than the event FIFO, since - * event DMA ordering is guaranteed. - */ - udelay ( 2 ); + if ( tx_queue->ring ) + falcon_free_special_buffer ( tx_queue->ring ); - /* Copy packet contents */ - nic->packetlen = rx_buf->len; - memcpy ( nic->packet, rx_buf->addr, nic->packetlen ); + if ( ev_queue->ring ) + falcon_free_special_buffer ( ev_queue->ring ); - /* Give this buffer back to the NIC */ - efab_push_rx_buffer ( efab, rx_buf ); + memset ( rx_queue, 0, sizeof ( *rx_queue ) ); + memset ( tx_queue, 0, sizeof ( *tx_queue ) ); + memset ( ev_queue, 0, sizeof ( *ev_queue ) ); - /* Prepare to receive next packet */ - rx_buf = NULL; + /* Ensure subsequent buffer allocations start at id 0 */ + efab->buffer_head = 0; +} - return 1; +static int +efab_alloc_resources ( struct efab_nic *efab ) +{ + struct efab_ev_queue *ev_queue = &efab->ev_queue; + struct efab_rx_queue *rx_queue = &efab->rx_queue; + struct efab_tx_queue *tx_queue = &efab->tx_queue; + size_t bytes; + + /* Allocate the hardware event queue */ + bytes = sizeof ( falcon_event_t ) * EFAB_TXD_SIZE; + ev_queue->ring = falcon_alloc_special_buffer ( efab, bytes, + &ev_queue->entry ); + if ( !ev_queue->ring ) + goto fail1; + + /* Initialise the hardware event queue */ + memset ( ev_queue->ring, 0xff, bytes ); + + /* Allocate the hardware tx queue */ + bytes = sizeof ( falcon_tx_desc_t ) * EFAB_TXD_SIZE; + tx_queue->ring = falcon_alloc_special_buffer ( efab, bytes, + &tx_queue->entry ); + if ( ! tx_queue->ring ) + goto fail2; + + /* Allocate the hardware rx queue */ + bytes = sizeof ( falcon_rx_desc_t ) * EFAB_RXD_SIZE; + rx_queue->ring = falcon_alloc_special_buffer ( efab, bytes, + &rx_queue->entry ); + if ( ! rx_queue->ring ) + goto fail3; + + return 0; + +fail3: + falcon_free_special_buffer ( tx_queue->ring ); + tx_queue->ring = NULL; +fail2: + falcon_free_special_buffer ( ev_queue->ring ); + ev_queue->ring = NULL; +fail1: + return -ENOMEM; } -/************************************************************************** -TRANSMIT - Transmit a frame -***************************************************************************/ -static void etherfabric_transmit ( struct nic *nic, const char *dest, - unsigned int type, unsigned int size, - const char *data ) { - struct efab_nic *efab = nic->priv_data; - unsigned int nstype = htons ( type ); - - /* Fill TX buffer, pad to ETH_ZLEN */ - memcpy ( efab->tx_buf.addr, dest, ETH_ALEN ); - memcpy ( efab->tx_buf.addr + ETH_ALEN, nic->node_addr, ETH_ALEN ); - memcpy ( efab->tx_buf.addr + 2 * ETH_ALEN, &nstype, 2 ); - memcpy ( efab->tx_buf.addr + ETH_HLEN, data, size ); - size += ETH_HLEN; - while ( size < ETH_ZLEN ) { - efab->tx_buf.addr[size++] = '\0'; - } - efab->tx_buf.len = size; - - /* Push TX descriptor */ - efab_push_tx_buffer ( efab, &efab->tx_buf ); - - /* Allow enough time for the packet to be transmitted. This - * is a temporary hack until we update to the new driver API. - */ - udelay ( 20 ); +static int +efab_init_mac ( struct efab_nic *efab ) +{ + int count, rc; + + /* This can take several seconds */ + EFAB_LOG ( "Waiting for link..\n" ); + for ( count=0; count<5; count++ ) { + rc = efab->mac_op->init ( efab ); + if ( rc ) { + EFAB_ERR ( "Failed reinitialising MAC, error %s\n", + strerror ( rc )); + return rc; + } + + /* Sleep for 2s to wait for the link to settle, either + * because we want to use it, or because we're about + * to reset the mac anyway + */ + sleep ( 2 ); + + if ( ! efab->link_up ) { + EFAB_ERR ( "!\n" ); + continue; + } + + EFAB_LOG ( "\n%dMbps %s-duplex\n", + ( efab->link_options & LPA_10000 ? 10000 : + ( efab->link_options & LPA_1000 ? 1000 : + ( efab->link_options & LPA_100 ? 100 : 10 ) ) ), + ( efab->link_options & LPA_DUPLEX ? + "full" : "half" ) ); - return; + /* TODO: Move link state handling to the poll() routine */ + netdev_link_up ( efab->netdev ); + return 0; + } + + EFAB_ERR ( "timed initialising MAC\n" ); + return -ETIMEDOUT; } -/************************************************************************** -DISABLE - Turn off ethernet interface -***************************************************************************/ -static void etherfabric_disable ( struct nic *nic ) { - struct efab_nic *efab = nic->priv_data; +static void +efab_close ( struct net_device *netdev ) +{ + struct efab_nic *efab = netdev_priv ( netdev ); - efab->op->reset ( efab ); - if ( efab->membase ) - iounmap ( efab->membase ); + falcon_fini_resources ( efab ); + efab_free_resources ( efab ); + efab->board_op->fini ( efab ); + falcon_reset ( efab ); } -/************************************************************************** -IRQ - handle interrupts -***************************************************************************/ -static void etherfabric_irq ( struct nic *nic, irq_action_t action ) { - struct efab_nic *efab = nic->priv_data; - - switch ( action ) { - case DISABLE : - efab->op->mask_irq ( efab, 1 ); - break; - case ENABLE : - efab->op->mask_irq ( efab, 0 ); - break; - case FORCE : - /* Force NIC to generate a receive interrupt */ - efab->op->generate_irq ( efab ); - break; - } +static int +efab_open ( struct net_device *netdev ) +{ + struct efab_nic *efab = netdev_priv ( netdev ); + struct efab_rx_queue *rx_queue = &efab->rx_queue; + int rc; + + rc = falcon_reset ( efab ); + if ( rc ) + goto fail1; + + rc = efab->board_op->init ( efab ); + if ( rc ) + goto fail2; + + rc = falcon_init_sram ( efab ); + if ( rc ) + goto fail3; + + /* Configure descriptor caches before pushing hardware queues */ + falcon_setup_nic ( efab ); + + rc = efab_alloc_resources ( efab ); + if ( rc ) + goto fail4; - return; + falcon_init_resources ( efab ); + + /* Push rx buffers */ + rc = efab_fill_rx_queue ( efab, rx_queue ); + if ( rc ) + goto fail5; + + /* Try and bring the interface up */ + rc = efab_init_mac ( efab ); + if ( rc ) + goto fail6; + + return 0; + +fail6: +fail5: + efab_free_resources ( efab ); +fail4: +fail3: + efab->board_op->fini ( efab ); +fail2: + falcon_reset ( efab ); +fail1: + return rc; } -static struct nic_operations etherfabric_operations = { - .connect = dummy_connect, - .poll = etherfabric_poll, - .transmit = etherfabric_transmit, - .irq = etherfabric_irq, +static struct net_device_operations efab_operations = { + .open = efab_open, + .close = efab_close, + .transmit = efab_transmit, + .poll = efab_poll, + .irq = efab_irq, }; -/************************************************************************** -PROBE - Look for an adapter, this routine's visible to the outside -***************************************************************************/ -static int etherfabric_probe ( struct nic *nic, struct pci_device *pci ) { - static struct efab_nic efab; - static int nic_port = 1; - struct efab_buffers *buffers; - int i; +static void +efab_remove ( struct pci_device *pci ) +{ + struct net_device *netdev = pci_get_drvdata ( pci ); + struct efab_nic *efab = netdev_priv ( netdev ); - /* Set up our private data structure */ - nic->priv_data = &efab; - memset ( &efab, 0, sizeof ( efab ) ); - memset ( &efab_buffers, 0, sizeof ( efab_buffers ) ); + if ( efab->membase ) { + falcon_reset ( efab ); - /* Hook in appropriate operations table. Do this early. */ - if ( pci->device == EF1002_DEVID ) { - efab.op = &ef1002_operations; - } else { - efab.op = &falcon_operations; + iounmap ( efab->membase ); + efab->membase = NULL; } - /* Initialise efab data structure */ - efab.pci = pci; - buffers = ( ( struct efab_buffers * ) - ( ( ( void * ) &efab_buffers ) + - ( - virt_to_bus ( &efab_buffers ) ) % EFAB_BUF_ALIGN ) ); - efab.eventq = buffers->eventq; - efab.txd = buffers->txd; - efab.rxd = buffers->rxd; - efab.tx_buf.addr = buffers->tx_buf; - for ( i = 0 ; i < EFAB_RX_BUFS ; i++ ) { - efab.rx_bufs[i].addr = buffers->rx_buf[i]; + if ( efab->nvo.nvs ) { + unregister_nvo ( &efab->nvo ); + efab->nvo.nvs = NULL; } - /* Enable the PCI device */ - adjust_pci_device ( pci ); - nic->ioaddr = pci->ioaddr & ~3; - nic->irqno = pci->irq; + unregister_netdev ( netdev ); + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +static int +efab_probe ( struct pci_device *pci, + const struct pci_device_id *id ) +{ + struct net_device *netdev; + struct efab_nic *efab; + int rc, mmio_start, mmio_len; + + /* Create the network adapter */ + netdev = alloc_etherdev ( sizeof ( struct efab_nic ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto fail1; + } + + /* Initialise the network adapter, and initialise private storage */ + netdev_init ( netdev, &efab_operations ); + pci_set_drvdata ( pci, netdev ); + netdev->dev = &pci->dev; + + efab = netdev_priv ( netdev ); + memset ( efab, 0, sizeof ( *efab ) ); + efab->netdev = netdev; /* Get iobase/membase */ - efab.iobase = nic->ioaddr; - efab.op->get_membase ( &efab ); + mmio_start = pci_bar_start ( pci, PCI_BASE_ADDRESS_2 ); + mmio_len = pci_bar_size ( pci, PCI_BASE_ADDRESS_2 ); + efab->membase = ioremap ( mmio_start, mmio_len ); + EFAB_TRACE ( "BAR of %x bytes at phys %x mapped at %p\n", + mmio_len, mmio_start, efab->membase ); - /* Switch NIC ports (i.e. try different ports on each probe) */ - nic_port = 1 - nic_port; - efab.port = nic_port; + /* Enable the PCI device */ + adjust_pci_device ( pci ); + efab->iobase = pci->ioaddr & ~3; + + /* Determine the NIC variant */ + falcon_probe_nic_variant ( efab, pci ); + + /* Read the SPI interface and determine the MAC address, + * and the board and phy variant. Hook in the op tables */ + rc = falcon_probe_spi ( efab ); + if ( rc ) + goto fail2; + rc = falcon_probe_nvram ( efab ); + if ( rc ) + goto fail3; + + memcpy ( netdev->ll_addr, efab->mac_addr, ETH_ALEN ); + + netdev_link_up ( netdev ); + rc = register_netdev ( netdev ); + if ( rc ) + goto fail4; + + /* Advertise non-volatile storage */ + if ( efab->nvo.nvs ) { + rc = register_nvo ( &efab->nvo, netdev_settings ( netdev ) ); + if ( rc ) + goto fail5; + } - /* Initialise hardware */ - if ( ! efab_init_nic ( &efab ) ) - return 0; - memcpy ( nic->node_addr, efab.mac_addr, ETH_ALEN ); + EFAB_LOG ( "Found %s EtherFabric %s %s revision %d\n", id->name, + efab->is_asic ? "ASIC" : "FPGA", + efab->phy_10g ? "10G" : "1G", + efab->pci_revision ); - /* point to NIC specific routines */ - nic->nic_op = ðerfabric_operations; + return 0; - return 1; +fail5: + unregister_netdev ( netdev ); +fail4: +fail3: +fail2: + iounmap ( efab->membase ); + efab->membase = NULL; + netdev_put ( netdev ); +fail1: + return rc; } -static struct pci_device_id etherfabric_nics[] = { -PCI_ROM(0x1924, 0xC101, "ef1002", "EtherFabric EF1002"), -PCI_ROM(0x1924, 0x0703, "falcon", "EtherFabric Falcon"), -}; -PCI_DRIVER ( etherfabric_driver, etherfabric_nics, PCI_NO_CLASS ); +static struct pci_device_id efab_nics[] = { + PCI_ROM(0x1924, 0x0703, "falcon", "EtherFabric Falcon"), + PCI_ROM(0x1924, 0x0710, "falconb0", "EtherFabric FalconB0"), +}; -DRIVER ( "EFAB", nic_driver, pci_driver, etherfabric_driver, - etherfabric_probe, etherfabric_disable ); +struct pci_driver etherfabric_driver __pci_driver = { + .ids = efab_nics, + .id_count = sizeof ( efab_nics ) / sizeof ( efab_nics[0] ), + .probe = efab_probe, + .remove = efab_remove, +}; /* * Local variables: diff --git a/gpxe/src/drivers/net/etherfabric_nic.h b/gpxe/src/drivers/net/etherfabric_nic.h new file mode 100644 index 00000000..4be50fbb --- /dev/null +++ b/gpxe/src/drivers/net/etherfabric_nic.h @@ -0,0 +1,201 @@ +/************************************************************************** + * + * Etherboot driver for Level 5 Etherfabric network cards + * + * Written by Michael Brown + * + * Copyright Fen Systems Ltd. 2005 + * Copyright Level 5 Networks Inc. 2005 + * + * This software may be used and distributed according to the terms of + * the GNU General Public License (GPL), incorporated herein by + * reference. Drivers based on or derived from this code fall under + * the GPL and must retain the authorship, copyright and license + * notice. + * + ************************************************************************** + */ +#ifndef EFAB_NIC_H +#define EFAB_NIC_H +#include +#include +#include +#include +#include +/************************************************************************** + * + * Constants and macros + * + ************************************************************************** + */ +/* Board IDs. Early boards have no board_type, (e.g. EF1002 and 401/403) + * But newer boards are getting bigger... + */ +typedef enum { + EFAB_BOARD_INVALID = 0, /* Early boards do not have board rev. info. */ + EFAB_BOARD_SFE4001 = 1, + EFAB_BOARD_SFE4002 = 2, + EFAB_BOARD_SFE4003 = 3, + /* Insert new types before here */ + EFAB_BOARD_MAX +} efab_board_type; + +/* PHY types. */ +typedef enum { + PHY_TYPE_AUTO = 0, /* on development board detect between CX4 & alaska */ + PHY_TYPE_CX4_RTMR = 1, + PHY_TYPE_1GIG_ALASKA = 2, + PHY_TYPE_10XPRESS = 3, + PHY_TYPE_XFP = 4, + PHY_TYPE_CX4 = 5, + PHY_TYPE_PM8358 = 6, +} phy_type_t; + +/************************************************************************** + * + * Hardware data structures and sizing + * + ************************************************************************** + */ + +#define dma_addr_t unsigned long +typedef efab_qword_t falcon_rx_desc_t; +typedef efab_qword_t falcon_tx_desc_t; +typedef efab_qword_t falcon_event_t; + +#define EFAB_BUF_ALIGN 4096 +#define EFAB_RXD_SIZE 512 +#define EFAB_TXD_SIZE 512 +#define EFAB_EVQ_SIZE 512 + +#define EFAB_NUM_RX_DESC 16 +#define EFAB_RX_BUF_SIZE 1600 + +/************************************************************************** + * + * Data structures + * + ************************************************************************** + */ + +struct efab_nic; + +/* A buffer table allocation backing a tx dma, rx dma or eventq */ +struct efab_special_buffer { + dma_addr_t dma_addr; + int id; +}; + +/* A TX queue */ +struct efab_tx_queue { + /* The hardware ring */ + falcon_tx_desc_t *ring; + + /* The software ring storing io_buffers. */ + struct io_buffer *buf[EFAB_TXD_SIZE]; + + /* The buffer table reservation pushed to hardware */ + struct efab_special_buffer entry; + + /* Software descriptor write ptr */ + unsigned int write_ptr; + + /* Hardware descriptor read ptr */ + unsigned int read_ptr; +}; + +/* An RX queue */ +struct efab_rx_queue { + /* The hardware ring */ + falcon_rx_desc_t *ring; + + /* The software ring storing io_buffers */ + struct io_buffer *buf[EFAB_NUM_RX_DESC]; + + /* The buffer table reservation pushed to hardware */ + struct efab_special_buffer entry; + + /* Descriptor write ptr, into both the hardware and software rings */ + unsigned int write_ptr; + + /* Hardware completion ptr */ + unsigned int read_ptr; +}; + +/* An event queue */ +struct efab_ev_queue { + /* The hardware ring to push to hardware. + * Must be the first entry in the structure */ + falcon_event_t *ring; + + /* The buffer table reservation pushed to hardware */ + struct efab_special_buffer entry; + + /* Pointers into the ring */ + unsigned int read_ptr; +}; + +struct efab_mac_operations { + int ( * init ) ( struct efab_nic *efab ); +}; + +struct efab_phy_operations { + int ( * init ) ( struct efab_nic *efab ); + unsigned int mmds; +}; + +struct efab_board_operations { + int ( * init ) ( struct efab_nic *efab ); + void ( * fini ) ( struct efab_nic *efab ); +}; + +struct efab_nic { + struct net_device *netdev; + int pci_revision; + int is_asic; + + /* I2C bit-bashed interface */ + struct i2c_bit_basher i2c_bb; + + /** SPI bus and devices, and the user visible NVO area */ + struct spi_bus spi_bus; + struct spi_device spi_flash; + struct spi_device spi_eeprom; + struct spi_device *spi; + struct nvo_block nvo; + + /** Board, MAC, and PHY operations tables */ + struct efab_board_operations *board_op; + struct efab_mac_operations *mac_op; + struct efab_phy_operations *phy_op; + + /* PHY and board types */ + int phy_addr; + int phy_type; + int phy_10g; + int board_type; + + /** Memory and IO base */ + void *membase; + unsigned int iobase; + + /* Buffer table allocation head */ + int buffer_head; + + /* Queues */ + struct efab_rx_queue rx_queue; + struct efab_tx_queue tx_queue; + struct efab_ev_queue ev_queue; + + /** MAC address */ + uint8_t mac_addr[ETH_ALEN]; + /** GMII link options */ + unsigned int link_options; + /** Link status */ + int link_up; + + /** INT_REG_KER */ + efab_oword_t int_ker __attribute__ (( aligned ( 16 ) )); +}; +#endif /* EFAB_NIC_H */ + diff --git a/gpxe/src/drivers/net/forcedeth.c b/gpxe/src/drivers/net/forcedeth.c index 54fadbd7..a30f1378 100644 --- a/gpxe/src/drivers/net/forcedeth.c +++ b/gpxe/src/drivers/net/forcedeth.c @@ -452,7 +452,7 @@ static int reg_delay(int offset, u32 mask, delaymax -= delay; if (delaymax < 0) { if (msg) - printf(msg); + printf("%s", msg); return 1; } } while ((readl(base + offset) & mask) != target); diff --git a/gpxe/src/drivers/net/ipoib.c b/gpxe/src/drivers/net/ipoib.c index 16b2a0c8..f0d52044 100644 --- a/gpxe/src/drivers/net/ipoib.c +++ b/gpxe/src/drivers/net/ipoib.c @@ -33,9 +33,6 @@ * IP over Infiniband */ -/** IPoIB MTU */ -#define IPOIB_MTU 2048 - /** Number of IPoIB data send work queue entries */ #define IPOIB_DATA_NUM_SEND_WQES 2 @@ -60,8 +57,6 @@ struct ipoib_queue_set { struct ib_completion_queue *cq; /** Queue pair */ struct ib_queue_pair *qp; - /** Receive work queue fill level */ - unsigned int recv_fill; /** Receive work queue maximum fill level */ unsigned int recv_max_fill; }; @@ -90,49 +85,146 @@ struct ipoib_device { int broadcast_attached; }; +/** TID half used to identify get path record replies */ +#define IPOIB_TID_GET_PATH_REC 0x11111111UL + +/** TID half used to identify multicast member record replies */ +#define IPOIB_TID_MC_MEMBER_REC 0x22222222UL + +/** IPoIB metadata TID */ +static uint32_t ipoib_meta_tid = 0; + +/** Broadcast QPN used in IPoIB MAC addresses + * + * This is a guaranteed invalid real QPN + */ +#define IPOIB_BROADCAST_QPN 0xffffffffUL + +/** Broadcast IPoIB address */ +static struct ipoib_mac ipoib_broadcast = { + .qpn = ntohl ( IPOIB_BROADCAST_QPN ), + .gid.u.bytes = { 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff }, +}; + +/**************************************************************************** + * + * IPoIB peer cache + * + **************************************************************************** + */ + /** - * IPoIB path cache entry + * IPoIB peer address * * This serves a similar role to the ARP cache for Ethernet. (ARP * *is* used on IPoIB; we have two caches to maintain.) */ -struct ipoib_cached_path { - /** Destination GID */ - struct ib_gid gid; - /** Destination LID */ - unsigned int dlid; +struct ipoib_peer { + /** Key */ + uint8_t key; + /** MAC address */ + struct ipoib_mac mac; + /** LID */ + unsigned int lid; /** Service level */ unsigned int sl; /** Rate */ unsigned int rate; }; -/** Number of IPoIB path cache entries */ -#define IPOIB_NUM_CACHED_PATHS 2 +/** Number of IPoIB peer cache entries + * + * Must be a power of two. + */ +#define IPOIB_NUM_CACHED_PEERS 4 -/** IPoIB path cache */ -static struct ipoib_cached_path ipoib_path_cache[IPOIB_NUM_CACHED_PATHS]; +/** IPoIB peer address cache */ +static struct ipoib_peer ipoib_peer_cache[IPOIB_NUM_CACHED_PEERS]; -/** Oldest IPoIB path cache entry index */ -static unsigned int ipoib_path_cache_idx = 0; +/** Oldest IPoIB peer cache entry index */ +static unsigned int ipoib_peer_cache_idx = 1; -/** TID half used to identify get path record replies */ -#define IPOIB_TID_GET_PATH_REC 0x11111111UL +/** + * Look up cached peer by key + * + * @v key Peer cache key + * @ret peer Peer cache entry, or NULL + */ +static struct ipoib_peer * ipoib_lookup_peer_by_key ( unsigned int key ) { + struct ipoib_peer *peer; + unsigned int i; -/** TID half used to identify multicast member record replies */ -#define IPOIB_TID_MC_MEMBER_REC 0x22222222UL + for ( i = 0 ; i < IPOIB_NUM_CACHED_PEERS ; i++ ) { + peer = &ipoib_peer_cache[i]; + if ( peer->key == key ) + return peer; + } -/** IPoIB metadata TID */ -static uint32_t ipoib_meta_tid = 0; + if ( key != 0 ) { + DBG ( "IPoIB warning: peer cache lost track of key %x while " + "still in use\n", key ); + } + return NULL; +} -/** IPv4 broadcast GID */ -static const struct ib_gid ipv4_broadcast_gid = { - { { 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff } } -}; +/** + * Look up cached peer by GID + * + * @v gid Peer GID + * @ret peer Peer cache entry, or NULL + */ +static struct ipoib_peer * +ipoib_lookup_peer_by_gid ( const struct ib_gid *gid ) { + struct ipoib_peer *peer; + unsigned int i; -/** Maximum time we will wait for the broadcast join to succeed */ -#define IPOIB_JOIN_MAX_DELAY_MS 1000 + for ( i = 0 ; i < IPOIB_NUM_CACHED_PEERS ; i++ ) { + peer = &ipoib_peer_cache[i]; + if ( memcmp ( &peer->mac.gid, gid, + sizeof ( peer->mac.gid) ) == 0 ) { + return peer; + } + } + + return NULL; +} + +/** + * Store GID and QPN in peer cache + * + * @v gid Peer GID + * @v qpn Peer QPN + * @ret peer Peer cache entry + */ +static struct ipoib_peer * +ipoib_cache_peer ( const struct ib_gid *gid, unsigned long qpn ) { + struct ipoib_peer *peer; + unsigned int key; + + /* Look for existing cache entry */ + peer = ipoib_lookup_peer_by_gid ( gid ); + if ( peer ) { + assert ( peer->mac.qpn = ntohl ( qpn ) ); + return peer; + } + + /* No entry found: create a new one */ + key = ipoib_peer_cache_idx++; + peer = &ipoib_peer_cache[ key % IPOIB_NUM_CACHED_PEERS ]; + if ( peer->key ) + DBG ( "IPoIB peer %x evicted from cache\n", peer->key ); + + memset ( peer, 0, sizeof ( *peer ) ); + peer->key = key; + peer->mac.qpn = htonl ( qpn ); + memcpy ( &peer->mac.gid, gid, sizeof ( peer->mac.gid ) ); + DBG ( "IPoIB peer %x has GID %08lx:%08lx:%08lx:%08lx and QPN %lx\n", + peer->key, htonl ( gid->u.dwords[0] ), + htonl ( gid->u.dwords[1] ), htonl ( gid->u.dwords[2] ), + htonl ( gid->u.dwords[3] ), qpn ); + return peer; +} /**************************************************************************** * @@ -141,37 +233,32 @@ static const struct ib_gid ipv4_broadcast_gid = { **************************************************************************** */ -/** Broadcast QPN used in IPoIB MAC addresses - * - * This is a guaranteed invalid real QPN - */ -#define IPOIB_BROADCAST_QPN 0xffffffffUL - -/** Broadcast IPoIB address */ -static struct ipoib_mac ipoib_broadcast = { - .qpn = ntohl ( IPOIB_BROADCAST_QPN ), -}; - /** * Add IPoIB link-layer header * * @v iobuf I/O buffer - * @v netdev Network device - * @v net_protocol Network-layer protocol * @v ll_dest Link-layer destination address + * @v ll_source Source link-layer address + * @v net_proto Network-layer protocol, in network-byte order + * @ret rc Return status code */ -static int ipoib_push ( struct io_buffer *iobuf, - struct net_device *netdev __unused, - struct net_protocol *net_protocol, - const void *ll_dest ) { +static int ipoib_push ( struct io_buffer *iobuf, const void *ll_dest, + const void *ll_source __unused, uint16_t net_proto ) { struct ipoib_hdr *ipoib_hdr = iob_push ( iobuf, sizeof ( *ipoib_hdr ) ); + const struct ipoib_mac *dest_mac = ll_dest; + const struct ipoib_mac *src_mac = ll_source; + struct ipoib_peer *dest; + struct ipoib_peer *src; + + /* Add link-layer addresses to cache */ + dest = ipoib_cache_peer ( &dest_mac->gid, ntohl ( dest_mac->qpn ) ); + src = ipoib_cache_peer ( &src_mac->gid, ntohl ( src_mac->qpn ) ); /* Build IPoIB header */ - memcpy ( &ipoib_hdr->pseudo.peer, ll_dest, - sizeof ( ipoib_hdr->pseudo.peer ) ); - ipoib_hdr->real.proto = net_protocol->net_proto; - ipoib_hdr->real.reserved = 0; + ipoib_hdr->proto = net_proto; + ipoib_hdr->u.peer.dest = dest->key; + ipoib_hdr->u.peer.src = src->key; return 0; } @@ -180,15 +267,16 @@ static int ipoib_push ( struct io_buffer *iobuf, * Remove IPoIB link-layer header * * @v iobuf I/O buffer - * @v netdev Network device - * @v net_proto Network-layer protocol, in network-byte order - * @v ll_source Source link-layer address + * @ret ll_dest Link-layer destination address + * @ret ll_source Source link-layer address + * @ret net_proto Network-layer protocol, in network-byte order * @ret rc Return status code */ -static int ipoib_pull ( struct io_buffer *iobuf, - struct net_device *netdev __unused, - uint16_t *net_proto, const void **ll_source ) { +static int ipoib_pull ( struct io_buffer *iobuf, const void **ll_dest, + const void **ll_source, uint16_t *net_proto ) { struct ipoib_hdr *ipoib_hdr = iobuf->data; + struct ipoib_peer *dest; + struct ipoib_peer *source; /* Sanity check */ if ( iob_len ( iobuf ) < sizeof ( *ipoib_hdr ) ) { @@ -200,9 +288,17 @@ static int ipoib_pull ( struct io_buffer *iobuf, /* Strip off IPoIB header */ iob_pull ( iobuf, sizeof ( *ipoib_hdr ) ); + /* Identify source and destination addresses, and clear + * reserved word in IPoIB header + */ + dest = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.dest ); + source = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.src ); + ipoib_hdr->u.reserved = 0; + /* Fill in required fields */ - *net_proto = ipoib_hdr->real.proto; - *ll_source = &ipoib_hdr->pseudo.peer; + *ll_dest = ( dest ? &dest->mac : &ipoib_broadcast ); + *ll_source = ( source ? &source->mac : &ipoib_broadcast ); + *net_proto = ipoib_hdr->proto; return 0; } @@ -225,6 +321,21 @@ const char * ipoib_ntoa ( const void *ll_addr ) { return buf; } +/** + * Hash multicast address + * + * @v af Address family + * @v net_addr Network-layer address + * @v ll_addr Link-layer address to fill in + * @ret rc Return status code + */ +static int ipoib_mc_hash ( unsigned int af __unused, + const void *net_addr __unused, + void *ll_addr __unused ) { + + return -ENOTSUP; +} + /** IPoIB protocol */ struct ll_protocol ipoib_protocol __ll_protocol = { .name = "IPoIB", @@ -235,6 +346,7 @@ struct ll_protocol ipoib_protocol __ll_protocol = { .push = ipoib_push, .pull = ipoib_pull, .ntoa = ipoib_ntoa, + .mc_hash = ipoib_mc_hash, }; /**************************************************************************** @@ -266,11 +378,17 @@ static void ipoib_destroy_qset ( struct ipoib_device *ipoib, * * @v ipoib IPoIB device * @v qset Queue set + * @v num_cqes Number of completion queue entries + * @v cq_op Completion queue operations + * @v num_send_wqes Number of send work queue entries + * @v num_recv_wqes Number of receive work queue entries + * @v qkey Queue key * @ret rc Return status code */ static int ipoib_create_qset ( struct ipoib_device *ipoib, struct ipoib_queue_set *qset, unsigned int num_cqes, + struct ib_completion_queue_operations *cq_op, unsigned int num_send_wqes, unsigned int num_recv_wqes, unsigned long qkey ) { @@ -285,7 +403,7 @@ static int ipoib_create_qset ( struct ipoib_device *ipoib, qset->recv_max_fill = num_recv_wqes; /* Allocate completion queue */ - qset->cq = ib_create_cq ( ibdev, num_cqes ); + qset->cq = ib_create_cq ( ibdev, num_cqes, cq_op ); if ( ! qset->cq ) { DBGC ( ipoib, "IPoIB %p could not allocate completion queue\n", ipoib ); @@ -311,28 +429,6 @@ static int ipoib_create_qset ( struct ipoib_device *ipoib, return rc; } -/** - * Find path cache entry by GID - * - * @v gid GID - * @ret entry Path cache entry, or NULL - */ -static struct ipoib_cached_path * -ipoib_find_cached_path ( struct ib_gid *gid ) { - struct ipoib_cached_path *path; - unsigned int i; - - for ( i = 0 ; i < IPOIB_NUM_CACHED_PATHS ; i++ ) { - path = &ipoib_path_cache[i]; - if ( memcmp ( &path->gid, gid, sizeof ( *gid ) ) == 0 ) - return path; - } - DBG ( "IPoIB %08lx:%08lx:%08lx:%08lx cache miss\n", - htonl ( gid->u.dwords[0] ), htonl ( gid->u.dwords[1] ), - htonl ( gid->u.dwords[2] ), htonl ( gid->u.dwords[3] ) ); - return NULL; -} - /** * Transmit path record request * @@ -344,36 +440,38 @@ static int ipoib_get_path_record ( struct ipoib_device *ipoib, struct ib_gid *gid ) { struct ib_device *ibdev = ipoib->ibdev; struct io_buffer *iobuf; - struct ib_mad_path_record *path_record; + struct ib_mad_sa *sa; struct ib_address_vector av; int rc; /* Allocate I/O buffer */ - iobuf = alloc_iob ( sizeof ( *path_record ) ); + iobuf = alloc_iob ( sizeof ( *sa ) ); if ( ! iobuf ) return -ENOMEM; - iob_put ( iobuf, sizeof ( *path_record ) ); - path_record = iobuf->data; - memset ( path_record, 0, sizeof ( *path_record ) ); + iob_put ( iobuf, sizeof ( *sa ) ); + sa = iobuf->data; + memset ( sa, 0, sizeof ( *sa ) ); /* Construct path record request */ - path_record->mad_hdr.base_version = IB_MGMT_BASE_VERSION; - path_record->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM; - path_record->mad_hdr.class_version = 2; - path_record->mad_hdr.method = IB_MGMT_METHOD_GET; - path_record->mad_hdr.attr_id = htons ( IB_SA_ATTR_PATH_REC ); - path_record->mad_hdr.tid[0] = IPOIB_TID_GET_PATH_REC; - path_record->mad_hdr.tid[1] = ipoib_meta_tid++; - path_record->sa_hdr.comp_mask[1] = + sa->mad_hdr.base_version = IB_MGMT_BASE_VERSION; + sa->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM; + sa->mad_hdr.class_version = 2; + sa->mad_hdr.method = IB_MGMT_METHOD_GET; + sa->mad_hdr.attr_id = htons ( IB_SA_ATTR_PATH_REC ); + sa->mad_hdr.tid[0] = IPOIB_TID_GET_PATH_REC; + sa->mad_hdr.tid[1] = ipoib_meta_tid++; + sa->sa_hdr.comp_mask[1] = htonl ( IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID ); - memcpy ( &path_record->dgid, gid, sizeof ( path_record->dgid ) ); - memcpy ( &path_record->sgid, &ibdev->port_gid, - sizeof ( path_record->sgid ) ); + memcpy ( &sa->sa_data.path_record.dgid, gid, + sizeof ( sa->sa_data.path_record.dgid ) ); + memcpy ( &sa->sa_data.path_record.sgid, &ibdev->gid, + sizeof ( sa->sa_data.path_record.sgid ) ); /* Construct address vector */ memset ( &av, 0, sizeof ( av ) ); - av.dlid = ibdev->sm_lid; - av.dest_qp = IB_SA_QPN; + av.lid = ibdev->sm_lid; + av.sl = ibdev->sm_sl; + av.qpn = IB_SA_QPN; av.qkey = IB_GLOBAL_QKEY; /* Post send request */ @@ -400,40 +498,41 @@ static int ipoib_mc_member_record ( struct ipoib_device *ipoib, struct ib_gid *gid, int join ) { struct ib_device *ibdev = ipoib->ibdev; struct io_buffer *iobuf; - struct ib_mad_mc_member_record *mc_member_record; + struct ib_mad_sa *sa; struct ib_address_vector av; int rc; /* Allocate I/O buffer */ - iobuf = alloc_iob ( sizeof ( *mc_member_record ) ); + iobuf = alloc_iob ( sizeof ( *sa ) ); if ( ! iobuf ) return -ENOMEM; - iob_put ( iobuf, sizeof ( *mc_member_record ) ); - mc_member_record = iobuf->data; - memset ( mc_member_record, 0, sizeof ( *mc_member_record ) ); + iob_put ( iobuf, sizeof ( *sa ) ); + sa = iobuf->data; + memset ( sa, 0, sizeof ( *sa ) ); /* Construct path record request */ - mc_member_record->mad_hdr.base_version = IB_MGMT_BASE_VERSION; - mc_member_record->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM; - mc_member_record->mad_hdr.class_version = 2; - mc_member_record->mad_hdr.method = + sa->mad_hdr.base_version = IB_MGMT_BASE_VERSION; + sa->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM; + sa->mad_hdr.class_version = 2; + sa->mad_hdr.method = ( join ? IB_MGMT_METHOD_SET : IB_MGMT_METHOD_DELETE ); - mc_member_record->mad_hdr.attr_id = htons ( IB_SA_ATTR_MC_MEMBER_REC ); - mc_member_record->mad_hdr.tid[0] = IPOIB_TID_MC_MEMBER_REC; - mc_member_record->mad_hdr.tid[1] = ipoib_meta_tid++; - mc_member_record->sa_hdr.comp_mask[1] = + sa->mad_hdr.attr_id = htons ( IB_SA_ATTR_MC_MEMBER_REC ); + sa->mad_hdr.tid[0] = IPOIB_TID_MC_MEMBER_REC; + sa->mad_hdr.tid[1] = ipoib_meta_tid++; + sa->sa_hdr.comp_mask[1] = htonl ( IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID | IB_SA_MCMEMBER_REC_JOIN_STATE ); - mc_member_record->scope__join_state = 1; - memcpy ( &mc_member_record->mgid, gid, - sizeof ( mc_member_record->mgid ) ); - memcpy ( &mc_member_record->port_gid, &ibdev->port_gid, - sizeof ( mc_member_record->port_gid ) ); + sa->sa_data.mc_member_record.scope__join_state = 1; + memcpy ( &sa->sa_data.mc_member_record.mgid, gid, + sizeof ( sa->sa_data.mc_member_record.mgid ) ); + memcpy ( &sa->sa_data.mc_member_record.port_gid, &ibdev->gid, + sizeof ( sa->sa_data.mc_member_record.port_gid ) ); /* Construct address vector */ memset ( &av, 0, sizeof ( av ) ); - av.dlid = ibdev->sm_lid; - av.dest_qp = IB_SA_QPN; + av.lid = ibdev->sm_lid; + av.sl = ibdev->sm_sl; + av.qpn = IB_SA_QPN; av.qkey = IB_GLOBAL_QKEY; /* Post send request */ @@ -459,49 +558,51 @@ static int ipoib_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct ipoib_device *ipoib = netdev->priv; struct ib_device *ibdev = ipoib->ibdev; - struct ipoib_pseudo_hdr *ipoib_pshdr = iobuf->data; + struct ipoib_hdr *ipoib_hdr; + struct ipoib_peer *dest; struct ib_address_vector av; struct ib_gid *gid; - struct ipoib_cached_path *path; - int rc; /* Sanity check */ - if ( iob_len ( iobuf ) < sizeof ( *ipoib_pshdr ) ) { + if ( iob_len ( iobuf ) < sizeof ( *ipoib_hdr ) ) { DBGC ( ipoib, "IPoIB %p buffer too short\n", ipoib ); return -EINVAL; } - iob_pull ( iobuf, ( sizeof ( *ipoib_pshdr ) ) ); + ipoib_hdr = iobuf->data; /* Attempting transmission while link is down will put the * queue pair into an error state, so don't try it. */ - if ( ! ibdev->link_up ) + if ( ! ib_link_ok ( ibdev ) ) return -ENETUNREACH; + /* Identify destination address */ + dest = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.dest ); + if ( ! dest ) + return -ENXIO; + ipoib_hdr->u.reserved = 0; + /* Construct address vector */ memset ( &av, 0, sizeof ( av ) ); - av.qkey = IB_GLOBAL_QKEY; + av.qkey = ipoib->data_qkey; av.gid_present = 1; - if ( ipoib_pshdr->peer.qpn == htonl ( IPOIB_BROADCAST_QPN ) ) { - /* Broadcast address */ - av.dest_qp = IB_BROADCAST_QPN; - av.dlid = ipoib->broadcast_lid; + if ( dest->mac.qpn == htonl ( IPOIB_BROADCAST_QPN ) ) { + /* Broadcast */ + av.qpn = IB_BROADCAST_QPN; + av.lid = ipoib->broadcast_lid; gid = &ipoib->broadcast_gid; } else { - /* Unicast - look in path cache */ - path = ipoib_find_cached_path ( &ipoib_pshdr->peer.gid ); - if ( ! path ) { - /* No path entry - get path record */ - rc = ipoib_get_path_record ( ipoib, - &ipoib_pshdr->peer.gid ); - netdev_tx_complete ( netdev, iobuf ); - return rc; + /* Unicast */ + if ( ! dest->lid ) { + /* No LID yet - get path record to fetch LID */ + ipoib_get_path_record ( ipoib, &dest->mac.gid ); + return -ENOENT; } - av.dest_qp = ntohl ( ipoib_pshdr->peer.qpn ); - av.dlid = path->dlid; - av.rate = path->rate; - av.sl = path->sl; - gid = &ipoib_pshdr->peer.gid; + av.qpn = ntohl ( dest->mac.qpn ); + av.lid = dest->lid; + av.rate = dest->rate; + av.sl = dest->sl; + gid = &dest->mac.gid; } memcpy ( &av.gid, gid, sizeof ( av.gid ) ); @@ -513,17 +614,15 @@ static int ipoib_transmit ( struct net_device *netdev, * * @v ibdev Infiniband device * @v qp Queue pair - * @v completion Completion * @v iobuf I/O buffer + * @v rc Completion status code */ static void ipoib_data_complete_send ( struct ib_device *ibdev __unused, struct ib_queue_pair *qp, - struct ib_completion *completion, - struct io_buffer *iobuf ) { + struct io_buffer *iobuf, int rc ) { struct net_device *netdev = ib_qp_get_ownerdata ( qp ); - netdev_tx_complete_err ( netdev, iobuf, - ( completion->syndrome ? -EIO : 0 ) ); + netdev_tx_complete_err ( netdev, iobuf, rc ); } /** @@ -531,67 +630,67 @@ static void ipoib_data_complete_send ( struct ib_device *ibdev __unused, * * @v ibdev Infiniband device * @v qp Queue pair - * @v completion Completion + * @v av Address vector, or NULL * @v iobuf I/O buffer + * @v rc Completion status code */ static void ipoib_data_complete_recv ( struct ib_device *ibdev __unused, struct ib_queue_pair *qp, - struct ib_completion *completion, - struct io_buffer *iobuf ) { + struct ib_address_vector *av, + struct io_buffer *iobuf, int rc ) { struct net_device *netdev = ib_qp_get_ownerdata ( qp ); struct ipoib_device *ipoib = netdev->priv; - struct ipoib_pseudo_hdr *ipoib_pshdr; - - if ( completion->syndrome ) { - netdev_rx_err ( netdev, iobuf, -EIO ); - goto done; - } + struct ipoib_hdr *ipoib_hdr; + struct ipoib_peer *src; - iob_put ( iobuf, completion->len ); - if ( iob_len ( iobuf ) < sizeof ( struct ib_global_route_header ) ) { - DBGC ( ipoib, "IPoIB %p received data packet too short to " - "contain GRH\n", ipoib ); - DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) ); - netdev_rx_err ( netdev, iobuf, -EIO ); - goto done; + if ( rc != 0 ) { + netdev_rx_err ( netdev, iobuf, rc ); + return; } - iob_pull ( iobuf, sizeof ( struct ib_global_route_header ) ); - if ( iob_len ( iobuf ) < sizeof ( struct ipoib_real_hdr ) ) { + /* Sanity check */ + if ( iob_len ( iobuf ) < sizeof ( struct ipoib_hdr ) ) { DBGC ( ipoib, "IPoIB %p received data packet too short to " "contain IPoIB header\n", ipoib ); DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) ); netdev_rx_err ( netdev, iobuf, -EIO ); - goto done; + return; } + ipoib_hdr = iobuf->data; - ipoib_pshdr = iob_push ( iobuf, sizeof ( *ipoib_pshdr ) ); - /* FIXME: fill in a MAC address for the sake of AoE! */ + /* Parse source address */ + if ( av->gid_present ) { + src = ipoib_cache_peer ( &av->gid, av->qpn ); + ipoib_hdr->u.peer.src = src->key; + } + /* Hand off to network layer */ netdev_rx ( netdev, iobuf ); - - done: - ipoib->data.recv_fill--; } +/** IPoIB data completion operations */ +static struct ib_completion_queue_operations ipoib_data_cq_op = { + .complete_send = ipoib_data_complete_send, + .complete_recv = ipoib_data_complete_recv, +}; + /** * Handle IPoIB metadata send completion * * @v ibdev Infiniband device * @v qp Queue pair - * @v completion Completion * @v iobuf I/O buffer + * @v rc Completion status code */ static void ipoib_meta_complete_send ( struct ib_device *ibdev __unused, struct ib_queue_pair *qp, - struct ib_completion *completion, - struct io_buffer *iobuf ) { + struct io_buffer *iobuf, int rc ) { struct net_device *netdev = ib_qp_get_ownerdata ( qp ); struct ipoib_device *ipoib = netdev->priv; - if ( completion->syndrome ) { - DBGC ( ipoib, "IPoIB %p metadata TX completion error %x\n", - ipoib, completion->syndrome ); + if ( rc != 0 ) { + DBGC ( ipoib, "IPoIB %p metadata TX completion error: %s\n", + ipoib, strerror ( rc ) ); } free_iob ( iobuf ); } @@ -602,26 +701,25 @@ static void ipoib_meta_complete_send ( struct ib_device *ibdev __unused, * @v ipoib IPoIB device * @v path_record Path record */ -static void ipoib_recv_path_record ( struct ipoib_device *ipoib __unused, - struct ib_mad_path_record *path_record ) { - struct ipoib_cached_path *path; +static void ipoib_recv_path_record ( struct ipoib_device *ipoib, + struct ib_path_record *path_record ) { + struct ipoib_peer *peer; + + /* Locate peer cache entry */ + peer = ipoib_lookup_peer_by_gid ( &path_record->dgid ); + if ( ! peer ) { + DBGC ( ipoib, "IPoIB %p received unsolicited path record\n", + ipoib ); + return; + } /* Update path cache entry */ - path = &ipoib_path_cache[ipoib_path_cache_idx]; - memcpy ( &path->gid, &path_record->dgid, sizeof ( path->gid ) ); - path->dlid = ntohs ( path_record->dlid ); - path->sl = ( path_record->reserved__sl & 0x0f ); - path->rate = ( path_record->rate_selector__rate & 0x3f ); - - DBG ( "IPoIB %08lx:%08lx:%08lx:%08lx dlid %x sl %x rate %x\n", - htonl ( path->gid.u.dwords[0] ), htonl ( path->gid.u.dwords[1] ), - htonl ( path->gid.u.dwords[2] ), htonl ( path->gid.u.dwords[3] ), - path->dlid, path->sl, path->rate ); - - /* Update path cache index */ - ipoib_path_cache_idx++; - if ( ipoib_path_cache_idx == IPOIB_NUM_CACHED_PATHS ) - ipoib_path_cache_idx = 0; + peer->lid = ntohs ( path_record->dlid ); + peer->sl = ( path_record->reserved__sl & 0x0f ); + peer->rate = ( path_record->rate_selector__rate & 0x3f ); + + DBG ( "IPoIB peer %x has dlid %x sl %x rate %x\n", + peer->key, peer->lid, peer->sl, peer->rate ); } /** @@ -631,7 +729,7 @@ static void ipoib_recv_path_record ( struct ipoib_device *ipoib __unused, * @v mc_member_record Multicast membership record */ static void ipoib_recv_mc_member_record ( struct ipoib_device *ipoib, - struct ib_mad_mc_member_record *mc_member_record ) { + struct ib_mc_member_record *mc_member_record ) { int joined; int rc; @@ -657,64 +755,64 @@ static void ipoib_recv_mc_member_record ( struct ipoib_device *ipoib, * * @v ibdev Infiniband device * @v qp Queue pair - * @v completion Completion + * @v av Address vector, or NULL * @v iobuf I/O buffer + * @v rc Completion status code */ -static void ipoib_meta_complete_recv ( struct ib_device *ibdev __unused, - struct ib_queue_pair *qp, - struct ib_completion *completion, - struct io_buffer *iobuf ) { +static void +ipoib_meta_complete_recv ( struct ib_device *ibdev __unused, + struct ib_queue_pair *qp, + struct ib_address_vector *av __unused, + struct io_buffer *iobuf, int rc ) { struct net_device *netdev = ib_qp_get_ownerdata ( qp ); struct ipoib_device *ipoib = netdev->priv; - union ib_mad *mad; + struct ib_mad_sa *sa; - if ( completion->syndrome ) { - DBGC ( ipoib, "IPoIB %p metadata RX completion error %x\n", - ipoib, completion->syndrome ); + if ( rc != 0 ) { + DBGC ( ipoib, "IPoIB %p metadata RX completion error: %s\n", + ipoib, strerror ( rc ) ); goto done; } - iob_put ( iobuf, completion->len ); - if ( iob_len ( iobuf ) < sizeof ( struct ib_global_route_header ) ) { - DBGC ( ipoib, "IPoIB %p received metadata packet too short " - "to contain GRH\n", ipoib ); - DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) ); - goto done; - } - iob_pull ( iobuf, sizeof ( struct ib_global_route_header ) ); - if ( iob_len ( iobuf ) < sizeof ( *mad ) ) { + if ( iob_len ( iobuf ) < sizeof ( *sa ) ) { DBGC ( ipoib, "IPoIB %p received metadata packet too short " "to contain reply\n", ipoib ); DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) ); goto done; } - mad = iobuf->data; + sa = iobuf->data; - if ( mad->mad_hdr.status != 0 ) { + if ( sa->mad_hdr.status != 0 ) { DBGC ( ipoib, "IPoIB %p metadata RX err status %04x\n", - ipoib, ntohs ( mad->mad_hdr.status ) ); + ipoib, ntohs ( sa->mad_hdr.status ) ); goto done; } - switch ( mad->mad_hdr.tid[0] ) { + switch ( sa->mad_hdr.tid[0] ) { case IPOIB_TID_GET_PATH_REC: - ipoib_recv_path_record ( ipoib, &mad->path_record ); + ipoib_recv_path_record ( ipoib, &sa->sa_data.path_record ); break; case IPOIB_TID_MC_MEMBER_REC: - ipoib_recv_mc_member_record ( ipoib, &mad->mc_member_record ); + ipoib_recv_mc_member_record ( ipoib, + &sa->sa_data.mc_member_record ); break; default: DBGC ( ipoib, "IPoIB %p unwanted response:\n", ipoib ); - DBGC_HD ( ipoib, mad, sizeof ( *mad ) ); + DBGC_HD ( ipoib, sa, sizeof ( *sa ) ); break; } done: - ipoib->meta.recv_fill--; free_iob ( iobuf ); } +/** IPoIB metadata completion operations */ +static struct ib_completion_queue_operations ipoib_meta_cq_op = { + .complete_send = ipoib_meta_complete_send, + .complete_recv = ipoib_meta_complete_recv, +}; + /** * Refill IPoIB receive ring * @@ -726,15 +824,14 @@ static void ipoib_refill_recv ( struct ipoib_device *ipoib, struct io_buffer *iobuf; int rc; - while ( qset->recv_fill < qset->recv_max_fill ) { - iobuf = alloc_iob ( IPOIB_MTU ); + while ( qset->qp->recv.fill < qset->recv_max_fill ) { + iobuf = alloc_iob ( IPOIB_PKT_LEN ); if ( ! iobuf ) break; if ( ( rc = ib_post_recv ( ibdev, qset->qp, iobuf ) ) != 0 ) { free_iob ( iobuf ); break; } - qset->recv_fill++; } } @@ -747,10 +844,8 @@ static void ipoib_poll ( struct net_device *netdev ) { struct ipoib_device *ipoib = netdev->priv; struct ib_device *ibdev = ipoib->ibdev; - ib_poll_cq ( ibdev, ipoib->meta.cq, ipoib_meta_complete_send, - ipoib_meta_complete_recv ); - ib_poll_cq ( ibdev, ipoib->data.cq, ipoib_data_complete_send, - ipoib_data_complete_recv ); + ib_poll_cq ( ibdev, ipoib->meta.cq ); + ib_poll_cq ( ibdev, ipoib->data.cq ); ipoib_refill_recv ( ipoib, &ipoib->meta ); ipoib_refill_recv ( ipoib, &ipoib->data ); } @@ -834,6 +929,7 @@ static int ipoib_open ( struct net_device *netdev ) { /* Allocate metadata queue set */ if ( ( rc = ipoib_create_qset ( ipoib, &ipoib->meta, IPOIB_META_NUM_CQES, + &ipoib_meta_cq_op, IPOIB_META_NUM_SEND_WQES, IPOIB_META_NUM_RECV_WQES, IB_GLOBAL_QKEY ) ) != 0 ) { @@ -845,6 +941,7 @@ static int ipoib_open ( struct net_device *netdev ) { /* Allocate data queue set */ if ( ( rc = ipoib_create_qset ( ipoib, &ipoib->data, IPOIB_DATA_NUM_CQES, + &ipoib_data_cq_op, IPOIB_DATA_NUM_SEND_WQES, IPOIB_DATA_NUM_RECV_WQES, IB_GLOBAL_QKEY ) ) != 0 ) { @@ -923,15 +1020,15 @@ static void ipoib_set_ib_params ( struct ipoib_device *ipoib ) { /* Calculate GID portion of MAC address based on port GID */ mac = ( ( struct ipoib_mac * ) netdev->ll_addr ); - memcpy ( &mac->gid, &ibdev->port_gid, sizeof ( mac->gid ) ); + memcpy ( &mac->gid, &ibdev->gid, sizeof ( mac->gid ) ); /* Calculate broadcast GID based on partition key */ - memcpy ( &ipoib->broadcast_gid, &ipv4_broadcast_gid, + memcpy ( &ipoib->broadcast_gid, &ipoib_broadcast.gid, sizeof ( ipoib->broadcast_gid ) ); ipoib->broadcast_gid.u.words[2] = htons ( ibdev->pkey ); /* Set net device link state to reflect Infiniband link state */ - if ( ibdev->link_up ) { + if ( ib_link_ok ( ibdev ) ) { netdev_link_up ( netdev ); } else { netdev_link_down ( netdev ); diff --git a/gpxe/src/drivers/net/natsemi.c b/gpxe/src/drivers/net/natsemi.c index 028b905c..84bfd7ab 100644 --- a/gpxe/src/drivers/net/natsemi.c +++ b/gpxe/src/drivers/net/natsemi.c @@ -61,7 +61,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/gpxe/src/drivers/net/ne2k_isa.c b/gpxe/src/drivers/net/ne2k_isa.c new file mode 100644 index 00000000..f8a45cc8 --- /dev/null +++ b/gpxe/src/drivers/net/ne2k_isa.c @@ -0,0 +1,373 @@ +/************************************************************************** + ETHERBOOT - BOOTP/TFTP Bootstrap Program + + Author: Martin Renters + Date: May/94 + + This code is based heavily on David Greenman's if_ed.c driver + + Copyright (C) 1993-1994, David Greenman, Martin Renters. + This software may be used, modified, copied, distributed, and sold, in + both source and binary form provided that the above copyright and these + terms are retained. Under no circumstances are the authors responsible for + the proper functioning of this software, nor do the authors assume any + responsibility for damages incurred with its use. + + Multicast support added by Timothy Legge (timlegge@users.sourceforge.net) 09/28/2003 + Relocation support added by Ken Yap (ken_yap@users.sourceforge.net) 28/12/02 + Card Detect support adapted from the eCos driver (Christian Plessl ) + Extracted from ns8390.c and adapted by Pantelis Koukousoulas + **************************************************************************/ + +#include "ns8390.h" +#include "etherboot.h" +#include "nic.h" +#include +#include +#include + +#define ASIC_PIO NE_DATA + +static unsigned char eth_vendor, eth_flags; +static unsigned short eth_nic_base, eth_asic_base; +static unsigned char eth_memsize, eth_rx_start, eth_tx_start; +static Address eth_bmem, eth_rmem; +static unsigned char eth_drain_receiver; + +static struct nic_operations ne_operations; +static void ne_reset(struct nic *nic, struct isa_device *isa); + +static isa_probe_addr_t ne_probe_addrs[] = { 0x300, 0x280, 0x320, 0x340, 0x380, 0x220, }; + +/************************************************************************** + ETH_PIO_READ - Read a frame via Programmed I/O + **************************************************************************/ +static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt) { + outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND); + outb(cnt, eth_nic_base + D8390_P0_RBCR0); + outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1); + outb(src, eth_nic_base + D8390_P0_RSAR0); + outb(src >> 8, eth_nic_base + D8390_P0_RSAR1); + outb(D8390_COMMAND_RD0 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND); + if (eth_flags & FLAG_16BIT) + cnt = (cnt + 1) >> 1; + + while (cnt--) { + if (eth_flags & FLAG_16BIT) { + *((unsigned short *) dst) = inw(eth_asic_base + ASIC_PIO); + dst += 2; + } else + *(dst++) = inb(eth_asic_base + ASIC_PIO); + } +} + +/************************************************************************** + ETH_PIO_WRITE - Write a frame via Programmed I/O + **************************************************************************/ +static void eth_pio_write(const unsigned char *src, unsigned int dst, + unsigned int cnt) { + outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND); + outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR); + outb(cnt, eth_nic_base + D8390_P0_RBCR0); + outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1); + outb(dst, eth_nic_base + D8390_P0_RSAR0); + outb(dst >> 8, eth_nic_base + D8390_P0_RSAR1); + outb(D8390_COMMAND_RD1 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND); + if (eth_flags & FLAG_16BIT) + cnt = (cnt + 1) >> 1; + + while (cnt--) { + + if (eth_flags & FLAG_16BIT) { + outw(*((unsigned short *) src), eth_asic_base + ASIC_PIO); + src += 2; + } else + outb(*(src++), eth_asic_base + ASIC_PIO); + } +} + +/************************************************************************** + enable_multicast - Enable Multicast + **************************************************************************/ +static void enable_multicast(unsigned short eth_nic_base) { + unsigned char mcfilter[8]; + int i; + + memset(mcfilter, 0xFF, 8); + outb(4, eth_nic_base + D8390_P0_RCR); + outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1, eth_nic_base + D8390_P0_COMMAND); + for (i = 0; i < 8; i++) { + outb(mcfilter[i], eth_nic_base + 8 + i); + if (inb(eth_nic_base + 8 + i) != mcfilter[i]) + DBG("Error SMC 83C690 Multicast filter read/write mishap %d\n", + i); + } + outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0, eth_nic_base + D8390_P0_COMMAND); + outb(4 | 0x08, eth_nic_base + D8390_P0_RCR); +} + +/************************************************************************** + NE_PROBE1 - Look for an adapter on the ISA bus + **************************************************************************/ +static int ne_probe1(isa_probe_addr_t ioaddr) { + //From the eCos driver + unsigned int regd; + unsigned int state; + + state = inb(ioaddr); + outb(ioaddr, D8390_COMMAND_RD2 | D8390_COMMAND_PS1 | D8390_COMMAND_STP); + regd = inb(ioaddr + D8390_P0_TCR); + + if (inb(ioaddr + D8390_P0_TCR)) { + outb(ioaddr, state); + outb(ioaddr + 0x0d, regd); + return 0; + } + + return 1; +} + +/************************************************************************** + NE_PROBE - Initialize an adapter ??? + **************************************************************************/ +static int ne_probe(struct nic *nic, struct isa_device *isa) { + int i; + unsigned char c; + unsigned char romdata[16]; + unsigned char testbuf[32]; + + eth_vendor = VENDOR_NONE; + eth_drain_receiver = 0; + + nic->irqno = 0; + nic->ioaddr = isa->ioaddr; + eth_nic_base = isa->ioaddr; + + /****************************************************************** + Search for NE1000/2000 if no WD/SMC or 3com cards + ******************************************************************/ + if (eth_vendor == VENDOR_NONE) { + + static unsigned char test[] = "NE*000 memory"; + + eth_bmem = 0; /* No shared memory */ + + eth_flags = FLAG_PIO; + eth_asic_base = eth_nic_base + NE_ASIC_OFFSET; + eth_memsize = MEM_16384; + eth_tx_start = 32; + eth_rx_start = 32 + D8390_TXBUF_SIZE; + c = inb(eth_asic_base + NE_RESET); + outb(c, eth_asic_base + NE_RESET); + (void) inb(0x84); + outb(D8390_COMMAND_STP | D8390_COMMAND_RD2, eth_nic_base + + D8390_P0_COMMAND); + outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR); + outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR); + outb(MEM_8192, eth_nic_base + D8390_P0_PSTART); + outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP); + eth_pio_write((unsigned char *) test, 8192, sizeof(test)); + eth_pio_read(8192, testbuf, sizeof(test)); + if (!memcmp(test, testbuf, sizeof(test))) + goto out; + eth_flags |= FLAG_16BIT; + eth_memsize = MEM_32768; + eth_tx_start = 64; + eth_rx_start = 64 + D8390_TXBUF_SIZE; + outb(D8390_DCR_WTS | D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + + D8390_P0_DCR); + outb(MEM_16384, eth_nic_base + D8390_P0_PSTART); + outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP); + eth_pio_write((unsigned char *) test, 16384, sizeof(test)); + eth_pio_read(16384, testbuf, sizeof(test)); + if (!memcmp(testbuf, test, sizeof(test))) + goto out; + + +out: + if (eth_nic_base == 0) + return (0); + if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */ + eth_flags |= FLAG_16BIT; + eth_vendor = VENDOR_NOVELL; + eth_pio_read(0, romdata, sizeof(romdata)); + for (i = 0; i < ETH_ALEN; i++) { + nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)]; + } + nic->ioaddr = eth_nic_base; + DBG("\nNE%c000 base %4.4x, MAC Addr %s\n", + (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base, eth_ntoa( + nic->node_addr)); + } + + if (eth_vendor == VENDOR_NONE) + return (0); + + if (eth_vendor != VENDOR_3COM) + eth_rmem = eth_bmem; + + ne_reset(nic, isa); + nic->nic_op = &ne_operations; + return 1; +} + + +/************************************************************************** + NE_DISABLE - Turn off adapter + **************************************************************************/ +static void ne_disable(struct nic *nic, struct isa_device *isa) { + ne_reset(nic, isa); +} + + +/************************************************************************** + NE_RESET - Reset adapter + **************************************************************************/ +static void ne_reset(struct nic *nic, struct isa_device *isa __unused) +{ + int i; + + eth_drain_receiver = 0; + outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | + D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND); + if (eth_flags & FLAG_16BIT) + outb(0x49, eth_nic_base+D8390_P0_DCR); + else + outb(0x48, eth_nic_base+D8390_P0_DCR); + outb(0, eth_nic_base+D8390_P0_RBCR0); + outb(0, eth_nic_base+D8390_P0_RBCR1); + outb(0x20, eth_nic_base+D8390_P0_RCR); /* monitor mode */ + outb(2, eth_nic_base+D8390_P0_TCR); + outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR); + outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART); + + outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP); + outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND); + outb(0xFF, eth_nic_base+D8390_P0_ISR); + outb(0, eth_nic_base+D8390_P0_IMR); + outb(D8390_COMMAND_PS1 | + D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND); + + for (i=0; inode_addr[i], eth_nic_base+D8390_P1_PAR0+i); + for (i=0; i= eth_memsize) next = eth_rx_start; + outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND); + curr = inb(eth_nic_base+D8390_P1_CURR); + outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND); + if (curr >= eth_memsize) curr=eth_rx_start; + if (curr == next) return(0); + + if ( ! retrieve ) return 1; + + pktoff = next << 8; + if (eth_flags & FLAG_PIO) + eth_pio_read(pktoff, (unsigned char *)&pkthdr, 4); + else + memcpy(&pkthdr, bus_to_virt(eth_rmem + pktoff), 4); + pktoff += sizeof(pkthdr); + /* incoming length includes FCS so must sub 4 */ + len = pkthdr.len - 4; + if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN + || len> ETH_FRAME_LEN) { + DBG("Bogus packet, ignoring\n"); + return (0); + } + else { + p = nic->packet; + nic->packetlen = len; /* available to caller */ + frag = (eth_memsize << 8) - pktoff; + if (len> frag) { /* We have a wrap-around */ + /* read first part */ + if (eth_flags & FLAG_PIO) + eth_pio_read(pktoff, p, frag); + else + memcpy(p, bus_to_virt(eth_rmem + pktoff), frag); + pktoff = eth_rx_start << 8; + p += frag; + len -= frag; + } + /* read second part */ + if (eth_flags & FLAG_PIO) + eth_pio_read(pktoff, p, len); + else + memcpy(p, bus_to_virt(eth_rmem + pktoff), len); + ret = 1; + } + next = pkthdr.next; /* frame number of next packet */ + if (next == eth_rx_start) + next = eth_memsize; + outb(next-1, eth_nic_base+D8390_P0_BOUND); + return(ret); +} + + +/************************************************************************** + NE_TRANSMIT - Transmit a frame + **************************************************************************/ +static void ne_transmit(struct nic *nic, const char *d, /* Destination */ +unsigned int t, /* Type */ +unsigned int s, /* size */ +const char *p) { /* Packet */ + + /* Programmed I/O */ + unsigned short type; + type = (t >> 8) | (t << 8); + eth_pio_write((unsigned char *) d, eth_tx_start << 8, ETH_ALEN); + eth_pio_write(nic->node_addr, (eth_tx_start << 8) + ETH_ALEN, ETH_ALEN); + /* bcc generates worse code without (const+const) below */ + eth_pio_write((unsigned char *) &type, (eth_tx_start << 8) + (ETH_ALEN + + ETH_ALEN), 2); + eth_pio_write((unsigned char *) p, (eth_tx_start << 8) + ETH_HLEN, s); + s += ETH_HLEN; + if (s < ETH_ZLEN) + s = ETH_ZLEN; + + outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | D8390_COMMAND_STA, + eth_nic_base + D8390_P0_COMMAND); + outb(eth_tx_start, eth_nic_base + D8390_P0_TPSR); + outb(s, eth_nic_base + D8390_P0_TBCR0); + outb(s >> 8, eth_nic_base + D8390_P0_TBCR1); + + outb(D8390_COMMAND_PS0 | D8390_COMMAND_TXP | D8390_COMMAND_RD2 + | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND); +} + +static struct nic_operations ne_operations = { .connect = dummy_connect, + .poll = ne_poll, .transmit = ne_transmit, .irq = dummy_irq, +}; + +ISA_DRIVER ( ne_driver, ne_probe_addrs, ne_probe1, + GENERIC_ISAPNP_VENDOR, 0x0600 ); + +DRIVER ( "ne", nic_driver, isapnp_driver, ne_driver, + ne_probe, ne_disable ); + +ISA_ROM("ne","NE1000/2000 and clones"); diff --git a/gpxe/src/drivers/net/phantom/phantom.c b/gpxe/src/drivers/net/phantom/phantom.c index 6c7d1fc9..33c76f62 100644 --- a/gpxe/src/drivers/net/phantom/phantom.c +++ b/gpxe/src/drivers/net/phantom/phantom.c @@ -25,12 +25,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include "phantom.h" /** @@ -40,11 +42,8 @@ * */ -/** Maximum time to wait for SPI lock */ -#define PHN_SPI_LOCK_TIMEOUT_MS 100 - -/** Maximum time to wait for SPI command to be issued */ -#define PHN_SPI_CMD_TIMEOUT_MS 100 +/** Maximum number of ports */ +#define PHN_MAX_NUM_PORTS 4 /** Maximum time to wait for command PEG to initialise * @@ -71,6 +70,9 @@ /** Maximum time to wait for test memory */ #define PHN_TEST_MEM_TIMEOUT_MS 100 +/** Maximum time to wait for CLP command to be issued */ +#define PHN_CLP_CMD_TIMEOUT_MS 500 + /** Link state poll frequency * * The link state will be checked once in every N calls to poll(). @@ -105,10 +107,41 @@ struct phantom_descriptor_rings { volatile uint32_t cmd_cons; }; -/** A Phantom NIC port */ -struct phantom_nic_port { - /** Phantom NIC containing this port */ - struct phantom_nic *phantom; +/** RX context creation request and response buffers */ +struct phantom_create_rx_ctx_rqrsp { + struct { + struct nx_hostrq_rx_ctx_s rx_ctx; + struct nx_hostrq_rds_ring_s rds; + struct nx_hostrq_sds_ring_s sds; + } __unm_dma_aligned hostrq; + struct { + struct nx_cardrsp_rx_ctx_s rx_ctx; + struct nx_cardrsp_rds_ring_s rds; + struct nx_cardrsp_sds_ring_s sds; + } __unm_dma_aligned cardrsp; +}; + +/** TX context creation request and response buffers */ +struct phantom_create_tx_ctx_rqrsp { + struct { + struct nx_hostrq_tx_ctx_s tx_ctx; + } __unm_dma_aligned hostrq; + struct { + struct nx_cardrsp_tx_ctx_s tx_ctx; + } __unm_dma_aligned cardrsp; +}; + +/** A Phantom NIC */ +struct phantom_nic { + /** BAR 0 */ + void *bar0; + /** Current CRB window */ + unsigned long crb_window; + /** CRB window access method */ + unsigned long ( *crb_access ) ( struct phantom_nic *phantom, + unsigned long reg ); + + /** Port number */ unsigned int port; @@ -143,73 +176,18 @@ struct phantom_nic_port { struct io_buffer *cds_iobuf[PHN_NUM_CDS]; - /** Link state poll timer */ - unsigned long link_poll_timer; - - /** Descriptor rings */ struct phantom_descriptor_rings *desc; -}; - -/** RX context creation request and response buffers */ -struct phantom_create_rx_ctx_rqrsp { - struct { - struct nx_hostrq_rx_ctx_s rx_ctx; - struct nx_hostrq_rds_ring_s rds; - struct nx_hostrq_sds_ring_s sds; - } __unm_dma_aligned hostrq; - struct { - struct nx_cardrsp_rx_ctx_s rx_ctx; - struct nx_cardrsp_rds_ring_s rds; - struct nx_cardrsp_sds_ring_s sds; - } __unm_dma_aligned cardrsp; -}; - -/** TX context creation request and response buffers */ -struct phantom_create_tx_ctx_rqrsp { - struct { - struct nx_hostrq_tx_ctx_s tx_ctx; - } __unm_dma_aligned hostrq; - struct { - struct nx_cardrsp_tx_ctx_s tx_ctx; - } __unm_dma_aligned cardrsp; -}; - -/** A Phantom DMA buffer area */ -union phantom_dma_buffer { - /** Dummy area required for (read-only) self-tests */ - uint8_t dummy_dma[UNM_DUMMY_DMA_SIZE]; - /** RX context creation request and response buffers */ - struct phantom_create_rx_ctx_rqrsp create_rx_ctx; - /** TX context creation request and response buffers */ - struct phantom_create_tx_ctx_rqrsp create_tx_ctx; -}; - -/** A Phantom NIC */ -struct phantom_nic { - /** BAR 0 */ - void *bar0; - /** Current CRB window */ - unsigned long crb_window; - /** CRB window access method */ - unsigned long ( *crb_access ) ( struct phantom_nic *phantom, - unsigned long reg ); - - /** Number of ports */ - int num_ports; - /** Per-port network devices */ - struct net_device *netdev[UNM_FLASH_NUM_PORTS]; - /** DMA buffers */ - union phantom_dma_buffer *dma_buf; - - /** Flash memory SPI bus */ - struct spi_bus spi_bus; - /** Flash memory SPI device */ - struct spi_device flash; /** Last known link state */ uint32_t link_state; + /** Link state poll timer */ + unsigned long link_poll_timer; + + + /** Non-volatile settings */ + struct settings settings; }; /*************************************************************************** @@ -227,21 +205,8 @@ struct phantom_nic { */ static unsigned long phantom_crb_access_128m ( struct phantom_nic *phantom, unsigned long reg ) { - static const uint32_t reg_window[] = { - [UNM_CRB_BLK_PCIE] = 0x0000000, - [UNM_CRB_BLK_CAM] = 0x2000000, - [UNM_CRB_BLK_ROMUSB] = 0x2000000, - [UNM_CRB_BLK_TEST] = 0x0000000, - }; - static const uint32_t reg_bases[] = { - [UNM_CRB_BLK_PCIE] = 0x6100000, - [UNM_CRB_BLK_CAM] = 0x6200000, - [UNM_CRB_BLK_ROMUSB] = 0x7300000, - [UNM_CRB_BLK_TEST] = 0x6200000, - }; - unsigned int block = UNM_CRB_BLK ( reg ); - unsigned long offset = UNM_CRB_OFFSET ( reg ); - uint32_t window = reg_window[block]; + unsigned long offset = ( 0x6000000 + ( reg & 0x1ffffff ) ); + uint32_t window = ( reg & 0x2000000 ); uint32_t verify_window; if ( phantom->crb_window != window ) { @@ -257,7 +222,7 @@ static unsigned long phantom_crb_access_128m ( struct phantom_nic *phantom, phantom->crb_window = window; } - return ( reg_bases[block] + offset ); + return offset; } /** @@ -269,21 +234,8 @@ static unsigned long phantom_crb_access_128m ( struct phantom_nic *phantom, */ static unsigned long phantom_crb_access_32m ( struct phantom_nic *phantom, unsigned long reg ) { - static const uint32_t reg_window[] = { - [UNM_CRB_BLK_PCIE] = 0x0000000, - [UNM_CRB_BLK_CAM] = 0x2000000, - [UNM_CRB_BLK_ROMUSB] = 0x2000000, - [UNM_CRB_BLK_TEST] = 0x0000000, - }; - static const uint32_t reg_bases[] = { - [UNM_CRB_BLK_PCIE] = 0x0100000, - [UNM_CRB_BLK_CAM] = 0x0200000, - [UNM_CRB_BLK_ROMUSB] = 0x1300000, - [UNM_CRB_BLK_TEST] = 0x0200000, - }; - unsigned int block = UNM_CRB_BLK ( reg ); - unsigned long offset = UNM_CRB_OFFSET ( reg ); - uint32_t window = reg_window[block]; + unsigned long offset = ( reg & 0x1ffffff ); + uint32_t window = ( reg & 0x2000000 ); uint32_t verify_window; if ( phantom->crb_window != window ) { @@ -299,7 +251,7 @@ static unsigned long phantom_crb_access_32m ( struct phantom_nic *phantom, phantom->crb_window = window; } - return ( reg_bases[block] + offset ); + return offset; } /** @@ -311,31 +263,54 @@ static unsigned long phantom_crb_access_32m ( struct phantom_nic *phantom, */ static unsigned long phantom_crb_access_2m ( struct phantom_nic *phantom, unsigned long reg ) { - static const uint32_t reg_window_hi[] = { - [UNM_CRB_BLK_PCIE] = 0x77300000, - [UNM_CRB_BLK_CAM] = 0x41600000, - [UNM_CRB_BLK_ROMUSB] = 0x42100000, - [UNM_CRB_BLK_TEST] = 0x29500000, + static const struct { + uint8_t block; + uint16_t window_hi; + } reg_window_hi[] = { + { UNM_CRB_BLK_PCIE, 0x773 }, + { UNM_CRB_BLK_CAM, 0x416 }, + { UNM_CRB_BLK_ROMUSB, 0x421 }, + { UNM_CRB_BLK_TEST, 0x295 }, + { UNM_CRB_BLK_PEG_0, 0x340 }, + { UNM_CRB_BLK_PEG_1, 0x341 }, + { UNM_CRB_BLK_PEG_2, 0x342 }, + { UNM_CRB_BLK_PEG_3, 0x343 }, + { UNM_CRB_BLK_PEG_4, 0x34b }, }; unsigned int block = UNM_CRB_BLK ( reg ); unsigned long offset = UNM_CRB_OFFSET ( reg ); - uint32_t window = ( reg_window_hi[block] | ( offset & 0x000f0000 ) ); + uint32_t window; uint32_t verify_window; + unsigned int i; - if ( phantom->crb_window != window ) { + for ( i = 0 ; i < ( sizeof ( reg_window_hi ) / + sizeof ( reg_window_hi[0] ) ) ; i++ ) { - /* Write to the CRB window register */ - writel ( window, phantom->bar0 + UNM_2M_CRB_WINDOW ); + if ( reg_window_hi[i].block != block ) + continue; - /* Ensure that the write has reached the card */ - verify_window = readl ( phantom->bar0 + UNM_2M_CRB_WINDOW ); - assert ( verify_window == window ); + window = ( ( reg_window_hi[i].window_hi << 20 ) | + ( offset & 0x000f0000 ) ); - /* Record new window */ - phantom->crb_window = window; + if ( phantom->crb_window != window ) { + + /* Write to the CRB window register */ + writel ( window, phantom->bar0 + UNM_2M_CRB_WINDOW ); + + /* Ensure that the write has reached the card */ + verify_window = readl ( phantom->bar0 + + UNM_2M_CRB_WINDOW ); + assert ( verify_window == window ); + + /* Record new window */ + phantom->crb_window = window; + } + + return ( 0x1e0000 + ( offset & 0xffff ) ); } - return ( 0x1e0000 + ( offset & 0xffff ) ); + assert ( 0 ); + return 0; } /** @@ -401,8 +376,9 @@ static inline void phantom_write_hilo ( struct phantom_nic *phantom, * @v buf 8-byte buffer to fill * @ret rc Return status code */ -static int phantom_read_test_mem ( struct phantom_nic *phantom, - uint64_t offset, uint32_t buf[2] ) { +static int phantom_read_test_mem_block ( struct phantom_nic *phantom, + unsigned long offset, + uint32_t buf[2] ) { unsigned int retries; uint32_t test_control; @@ -428,29 +404,58 @@ static int phantom_read_test_mem ( struct phantom_nic *phantom, return -ETIMEDOUT; } +/** + * Read single byte from Phantom test memory + * + * @v phantom Phantom NIC + * @v offset Offset within test memory + * @ret byte Byte read, or negative error + */ +static int phantom_read_test_mem ( struct phantom_nic *phantom, + unsigned long offset ) { + static union { + uint8_t bytes[8]; + uint32_t dwords[2]; + } cache; + static unsigned long cache_offset = -1UL; + unsigned long sub_offset; + int rc; + + sub_offset = ( offset & ( sizeof ( cache ) - 1 ) ); + offset = ( offset & ~( sizeof ( cache ) - 1 ) ); + + if ( cache_offset != offset ) { + if ( ( rc = phantom_read_test_mem_block ( phantom, offset, + cache.dwords )) !=0 ) + return rc; + cache_offset = offset; + } + + return cache.bytes[sub_offset]; +} + /** * Dump Phantom firmware dmesg log * * @v phantom Phantom NIC * @v log Log number + * @v max_lines Maximum number of lines to show, or -1 to show all + * @ret rc Return status code */ -static void phantom_dmesg ( struct phantom_nic *phantom, unsigned int log ) { +static int phantom_dmesg ( struct phantom_nic *phantom, unsigned int log, + unsigned int max_lines ) { uint32_t head; uint32_t tail; uint32_t len; uint32_t sig; uint32_t offset; - union { - uint8_t bytes[8]; - uint32_t dwords[2]; - } buf; - unsigned int i; - int rc; + int byte; /* Optimise out for non-debug builds */ if ( ! DBG_LOG ) - return; + return 0; + /* Locate log */ head = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_HEAD ( log ) ); len = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_LEN ( log ) ); tail = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_TAIL ( log ) ); @@ -463,165 +468,37 @@ static void phantom_dmesg ( struct phantom_nic *phantom, unsigned int log ) { sig, UNM_CAM_RAM_DMESG_SIG_MAGIC ); } - for ( offset = head ; offset < tail ; offset += 8 ) { - if ( ( rc = phantom_read_test_mem ( phantom, offset, - buf.dwords ) ) != 0 ) { - DBGC ( phantom, "Phantom %p could not read from test " - "memory: %s\n", phantom, strerror ( rc ) ); + /* Locate start of last (max_lines) lines */ + for ( offset = tail ; offset > head ; offset-- ) { + if ( ( byte = phantom_read_test_mem ( phantom, + ( offset - 1 ) ) ) < 0 ) + return byte; + if ( ( byte == '\n' ) && ( max_lines-- == 0 ) ) break; - } - for ( i = 0 ; ( ( i < sizeof ( buf ) ) && - ( offset + i ) < tail ) ; i++ ) { - DBG ( "%c", buf.bytes[i] ); - } + } + + /* Print lines */ + for ( ; offset < tail ; offset++ ) { + if ( ( byte = phantom_read_test_mem ( phantom, offset ) ) < 0 ) + return byte; + DBG ( "%c", byte ); } DBG ( "\n" ); + return 0; } /** * Dump Phantom firmware dmesg logs * * @v phantom Phantom NIC + * @v max_lines Maximum number of lines to show, or -1 to show all */ static void __attribute__ (( unused )) -phantom_dmesg_all ( struct phantom_nic *phantom ) { +phantom_dmesg_all ( struct phantom_nic *phantom, unsigned int max_lines ) { unsigned int i; for ( i = 0 ; i < UNM_CAM_RAM_NUM_DMESG_BUFFERS ; i++ ) - phantom_dmesg ( phantom, i ); -} - -/*************************************************************************** - * - * SPI bus access (for flash memory) - * - */ - -/** - * Acquire Phantom SPI lock - * - * @v phantom Phantom NIC - * @ret rc Return status code - */ -static int phantom_spi_lock ( struct phantom_nic *phantom ) { - unsigned int retries; - uint32_t pcie_sem2_lock; - - for ( retries = 0 ; retries < PHN_SPI_LOCK_TIMEOUT_MS ; retries++ ) { - pcie_sem2_lock = phantom_readl ( phantom, UNM_PCIE_SEM2_LOCK ); - if ( pcie_sem2_lock != 0 ) - return 0; - mdelay ( 1 ); - } - - DBGC ( phantom, "Phantom %p timed out waiting for SPI lock\n", - phantom ); - return -ETIMEDOUT; -} - -/** - * Wait for Phantom SPI command to complete - * - * @v phantom Phantom NIC - * @ret rc Return status code - */ -static int phantom_spi_wait ( struct phantom_nic *phantom ) { - unsigned int retries; - uint32_t glb_status; - - for ( retries = 0 ; retries < PHN_SPI_CMD_TIMEOUT_MS ; retries++ ) { - glb_status = phantom_readl ( phantom, UNM_ROMUSB_GLB_STATUS ); - if ( glb_status & UNM_ROMUSB_GLB_STATUS_ROM_DONE ) - return 0; - mdelay ( 1 ); - } - - DBGC ( phantom, "Phantom %p timed out waiting for SPI command\n", - phantom ); - return -ETIMEDOUT; -} - -/** - * Release Phantom SPI lock - * - * @v phantom Phantom NIC - */ -static void phantom_spi_unlock ( struct phantom_nic *phantom ) { - phantom_readl ( phantom, UNM_PCIE_SEM2_UNLOCK ); -} - -/** - * Read/write data via Phantom SPI bus - * - * @v bus SPI bus - * @v device SPI device - * @v command Command - * @v address Address to read/write (<0 for no address) - * @v data_out TX data buffer (or NULL) - * @v data_in RX data buffer (or NULL) - * @v len Length of data buffer(s) - * @ret rc Return status code - */ -static int phantom_spi_rw ( struct spi_bus *bus, - struct spi_device *device, - unsigned int command, int address, - const void *data_out, void *data_in, - size_t len ) { - struct phantom_nic *phantom = - container_of ( bus, struct phantom_nic, spi_bus ); - uint32_t data; - int rc; - - DBGCP ( phantom, "Phantom %p SPI command %x at %x+%zx\n", - phantom, command, address, len ); - if ( data_out ) - DBGCP_HDA ( phantom, address, data_out, len ); - - /* We support only exactly 4-byte reads */ - if ( len != UNM_SPI_BLKSIZE ) { - DBGC ( phantom, "Phantom %p invalid SPI length %zx\n", - phantom, len ); - return -EINVAL; - } - - /* Acquire SPI lock */ - if ( ( rc = phantom_spi_lock ( phantom ) ) != 0 ) - goto err_lock; - - /* Issue SPI command as per the PRM */ - if ( data_out ) { - memcpy ( &data, data_out, sizeof ( data ) ); - phantom_writel ( phantom, data, UNM_ROMUSB_ROM_WDATA ); - } - phantom_writel ( phantom, address, UNM_ROMUSB_ROM_ADDRESS ); - phantom_writel ( phantom, ( device->address_len / 8 ), - UNM_ROMUSB_ROM_ABYTE_CNT ); - udelay ( 100 ); /* according to PRM */ - phantom_writel ( phantom, 0, UNM_ROMUSB_ROM_DUMMY_BYTE_CNT ); - phantom_writel ( phantom, command, UNM_ROMUSB_ROM_INSTR_OPCODE ); - - /* Wait for SPI command to complete */ - if ( ( rc = phantom_spi_wait ( phantom ) ) != 0 ) - goto err_wait; - - /* Reset address byte count and dummy byte count, because the - * PRM asks us to. - */ - phantom_writel ( phantom, 0, UNM_ROMUSB_ROM_ABYTE_CNT ); - udelay ( 100 ); /* according to PRM */ - phantom_writel ( phantom, 0, UNM_ROMUSB_ROM_DUMMY_BYTE_CNT ); - - /* Read data, if applicable */ - if ( data_in ) { - data = phantom_readl ( phantom, UNM_ROMUSB_ROM_RDATA ); - memcpy ( data_in, &data, sizeof ( data ) ); - DBGCP_HDA ( phantom, address, data_in, len ); - } - - err_wait: - phantom_spi_unlock ( phantom ); - err_lock: - return rc; + phantom_dmesg ( phantom, i, max_lines ); } /*************************************************************************** @@ -665,26 +542,24 @@ static int phantom_wait_for_cmd ( struct phantom_nic *phantom ) { /** * Issue command to firmware * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v command Firmware command * @v arg1 Argument 1 * @v arg2 Argument 2 * @v arg3 Argument 3 * @ret rc Return status code */ -static int phantom_issue_cmd ( struct phantom_nic_port *phantom_port, +static int phantom_issue_cmd ( struct phantom_nic *phantom, uint32_t command, uint32_t arg1, uint32_t arg2, uint32_t arg3 ) { - struct phantom_nic *phantom = phantom_port->phantom; uint32_t signature; int rc; /* Issue command */ - signature = NX_CDRP_SIGNATURE_MAKE ( phantom_port->port, + signature = NX_CDRP_SIGNATURE_MAKE ( phantom->port, NXHAL_VERSION ); - DBGC2 ( phantom, "Phantom %p port %d issuing command %08lx (%08lx, " - "%08lx, %08lx)\n", phantom, phantom_port->port, - command, arg1, arg2, arg3 ); + DBGC2 ( phantom, "Phantom %p issuing command %08lx (%08lx, %08lx, " + "%08lx)\n", phantom, command, arg1, arg2, arg3 ); phantom_writel ( phantom, signature, UNM_NIC_REG_NX_SIGN ); phantom_writel ( phantom, arg1, UNM_NIC_REG_NX_ARG1 ); phantom_writel ( phantom, arg2, UNM_NIC_REG_NX_ARG2 ); @@ -705,36 +580,41 @@ static int phantom_issue_cmd ( struct phantom_nic_port *phantom_port, /** * Issue buffer-format command to firmware * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v command Firmware command * @v buffer Buffer to pass to firmware * @v len Length of buffer * @ret rc Return status code */ -static int phantom_issue_buf_cmd ( struct phantom_nic_port *phantom_port, +static int phantom_issue_buf_cmd ( struct phantom_nic *phantom, uint32_t command, void *buffer, size_t len ) { uint64_t physaddr; physaddr = virt_to_bus ( buffer ); - return phantom_issue_cmd ( phantom_port, command, ( physaddr >> 32 ), + return phantom_issue_cmd ( phantom, command, ( physaddr >> 32 ), ( physaddr & 0xffffffffUL ), len ); } /** * Create Phantom RX context * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @ret rc Return status code */ -static int phantom_create_rx_ctx ( struct phantom_nic_port *phantom_port ) { - struct phantom_nic *phantom = phantom_port->phantom; +static int phantom_create_rx_ctx ( struct phantom_nic *phantom ) { struct phantom_create_rx_ctx_rqrsp *buf; int rc; + + /* Allocate context creation buffer */ + buf = malloc_dma ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN ); + if ( ! buf ) { + rc = -ENOMEM; + goto out; + } + memset ( buf, 0, sizeof ( *buf ) ); /* Prepare request */ - buf = &phantom->dma_buf->create_rx_ctx; - memset ( buf, 0, sizeof ( *buf ) ); buf->hostrq.rx_ctx.host_rsp_dma_addr = cpu_to_le64 ( virt_to_bus ( &buf->cardrsp ) ); buf->hostrq.rx_ctx.capabilities[0] = @@ -749,197 +629,194 @@ static int phantom_create_rx_ctx ( struct phantom_nic_port *phantom_port ) { buf->hostrq.rx_ctx.num_rds_rings = cpu_to_le16 ( 1 ); buf->hostrq.rx_ctx.num_sds_rings = cpu_to_le16 ( 1 ); buf->hostrq.rds.host_phys_addr = - cpu_to_le64 ( virt_to_bus ( phantom_port->desc->rds ) ); + cpu_to_le64 ( virt_to_bus ( phantom->desc->rds ) ); buf->hostrq.rds.buff_size = cpu_to_le64 ( PHN_RX_BUFSIZE ); buf->hostrq.rds.ring_size = cpu_to_le32 ( PHN_NUM_RDS ); buf->hostrq.rds.ring_kind = cpu_to_le32 ( NX_RDS_RING_TYPE_NORMAL ); buf->hostrq.sds.host_phys_addr = - cpu_to_le64 ( virt_to_bus ( phantom_port->desc->sds ) ); + cpu_to_le64 ( virt_to_bus ( phantom->desc->sds ) ); buf->hostrq.sds.ring_size = cpu_to_le32 ( PHN_NUM_SDS ); - DBGC ( phantom, "Phantom %p port %d creating RX context\n", - phantom, phantom_port->port ); + DBGC ( phantom, "Phantom %p creating RX context\n", phantom ); DBGC2_HDA ( phantom, virt_to_bus ( &buf->hostrq ), &buf->hostrq, sizeof ( buf->hostrq ) ); /* Issue request */ - if ( ( rc = phantom_issue_buf_cmd ( phantom_port, + if ( ( rc = phantom_issue_buf_cmd ( phantom, NX_CDRP_CMD_CREATE_RX_CTX, &buf->hostrq, sizeof ( buf->hostrq ) ) ) != 0 ) { - DBGC ( phantom, "Phantom %p port %d could not create RX " - "context: %s\n", - phantom, phantom_port->port, strerror ( rc ) ); + DBGC ( phantom, "Phantom %p could not create RX context: " + "%s\n", phantom, strerror ( rc ) ); DBGC ( phantom, "Request:\n" ); DBGC_HDA ( phantom, virt_to_bus ( &buf->hostrq ), &buf->hostrq, sizeof ( buf->hostrq ) ); DBGC ( phantom, "Response:\n" ); DBGC_HDA ( phantom, virt_to_bus ( &buf->cardrsp ), &buf->cardrsp, sizeof ( buf->cardrsp ) ); - return rc; + goto out; } /* Retrieve context parameters */ - phantom_port->rx_context_id = + phantom->rx_context_id = le16_to_cpu ( buf->cardrsp.rx_ctx.context_id ); - phantom_port->rds_producer_crb = + phantom->rds_producer_crb = ( UNM_CAM_RAM + le32_to_cpu ( buf->cardrsp.rds.host_producer_crb )); - phantom_port->sds_consumer_crb = + phantom->sds_consumer_crb = ( UNM_CAM_RAM + le32_to_cpu ( buf->cardrsp.sds.host_consumer_crb )); - DBGC ( phantom, "Phantom %p port %d created RX context (id %04x, " - "port phys %02x virt %02x)\n", phantom, phantom_port->port, - phantom_port->rx_context_id, buf->cardrsp.rx_ctx.phys_port, - buf->cardrsp.rx_ctx.virt_port ); + DBGC ( phantom, "Phantom %p created RX context (id %04x, port phys " + "%02x virt %02x)\n", phantom, phantom->rx_context_id, + buf->cardrsp.rx_ctx.phys_port, buf->cardrsp.rx_ctx.virt_port ); DBGC2_HDA ( phantom, virt_to_bus ( &buf->cardrsp ), &buf->cardrsp, sizeof ( buf->cardrsp ) ); - DBGC ( phantom, "Phantom %p port %d RDS producer CRB is %08lx\n", - phantom, phantom_port->port, phantom_port->rds_producer_crb ); - DBGC ( phantom, "Phantom %p port %d SDS consumer CRB is %08lx\n", - phantom, phantom_port->port, phantom_port->sds_consumer_crb ); + DBGC ( phantom, "Phantom %p RDS producer CRB is %08lx\n", + phantom, phantom->rds_producer_crb ); + DBGC ( phantom, "Phantom %p SDS consumer CRB is %08lx\n", + phantom, phantom->sds_consumer_crb ); - return 0; + out: + free_dma ( buf, sizeof ( *buf ) ); + return rc; } /** * Destroy Phantom RX context * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @ret rc Return status code */ -static void phantom_destroy_rx_ctx ( struct phantom_nic_port *phantom_port ) { - struct phantom_nic *phantom = phantom_port->phantom; +static void phantom_destroy_rx_ctx ( struct phantom_nic *phantom ) { int rc; - DBGC ( phantom, "Phantom %p port %d destroying RX context (id %04x)\n", - phantom, phantom_port->port, phantom_port->rx_context_id ); + DBGC ( phantom, "Phantom %p destroying RX context (id %04x)\n", + phantom, phantom->rx_context_id ); /* Issue request */ - if ( ( rc = phantom_issue_cmd ( phantom_port, + if ( ( rc = phantom_issue_cmd ( phantom, NX_CDRP_CMD_DESTROY_RX_CTX, - phantom_port->rx_context_id, + phantom->rx_context_id, NX_DESTROY_CTX_RESET, 0 ) ) != 0 ) { - DBGC ( phantom, "Phantom %p port %d could not destroy RX " - "context: %s\n", - phantom, phantom_port->port, strerror ( rc ) ); + DBGC ( phantom, "Phantom %p could not destroy RX context: " + "%s\n", phantom, strerror ( rc ) ); /* We're probably screwed */ return; } /* Clear context parameters */ - phantom_port->rx_context_id = 0; - phantom_port->rds_producer_crb = 0; - phantom_port->sds_consumer_crb = 0; + phantom->rx_context_id = 0; + phantom->rds_producer_crb = 0; + phantom->sds_consumer_crb = 0; /* Reset software counters */ - phantom_port->rds_producer_idx = 0; - phantom_port->rds_consumer_idx = 0; - phantom_port->sds_consumer_idx = 0; + phantom->rds_producer_idx = 0; + phantom->rds_consumer_idx = 0; + phantom->sds_consumer_idx = 0; } /** * Create Phantom TX context * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @ret rc Return status code */ -static int phantom_create_tx_ctx ( struct phantom_nic_port *phantom_port ) { - struct phantom_nic *phantom = phantom_port->phantom; +static int phantom_create_tx_ctx ( struct phantom_nic *phantom ) { struct phantom_create_tx_ctx_rqrsp *buf; int rc; - /* Prepare request */ - buf = &phantom->dma_buf->create_tx_ctx; + /* Allocate context creation buffer */ + buf = malloc_dma ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN ); + if ( ! buf ) { + rc = -ENOMEM; + goto out; + } memset ( buf, 0, sizeof ( *buf ) ); + + /* Prepare request */ buf->hostrq.tx_ctx.host_rsp_dma_addr = cpu_to_le64 ( virt_to_bus ( &buf->cardrsp ) ); buf->hostrq.tx_ctx.cmd_cons_dma_addr = - cpu_to_le64 ( virt_to_bus ( &phantom_port->desc->cmd_cons ) ); - buf->hostrq.tx_ctx.dummy_dma_addr = - cpu_to_le64 ( virt_to_bus ( phantom->dma_buf->dummy_dma ) ); + cpu_to_le64 ( virt_to_bus ( &phantom->desc->cmd_cons ) ); buf->hostrq.tx_ctx.capabilities[0] = cpu_to_le32 ( NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN ); buf->hostrq.tx_ctx.host_int_crb_mode = cpu_to_le32 ( NX_HOST_INT_CRB_MODE_SHARED ); buf->hostrq.tx_ctx.cds_ring.host_phys_addr = - cpu_to_le64 ( virt_to_bus ( phantom_port->desc->cds ) ); + cpu_to_le64 ( virt_to_bus ( phantom->desc->cds ) ); buf->hostrq.tx_ctx.cds_ring.ring_size = cpu_to_le32 ( PHN_NUM_CDS ); - DBGC ( phantom, "Phantom %p port %d creating TX context\n", - phantom, phantom_port->port ); + DBGC ( phantom, "Phantom %p creating TX context\n", phantom ); DBGC2_HDA ( phantom, virt_to_bus ( &buf->hostrq ), &buf->hostrq, sizeof ( buf->hostrq ) ); /* Issue request */ - if ( ( rc = phantom_issue_buf_cmd ( phantom_port, + if ( ( rc = phantom_issue_buf_cmd ( phantom, NX_CDRP_CMD_CREATE_TX_CTX, &buf->hostrq, sizeof ( buf->hostrq ) ) ) != 0 ) { - DBGC ( phantom, "Phantom %p port %d could not create TX " - "context: %s\n", - phantom, phantom_port->port, strerror ( rc ) ); + DBGC ( phantom, "Phantom %p could not create TX context: " + "%s\n", phantom, strerror ( rc ) ); DBGC ( phantom, "Request:\n" ); DBGC_HDA ( phantom, virt_to_bus ( &buf->hostrq ), &buf->hostrq, sizeof ( buf->hostrq ) ); DBGC ( phantom, "Response:\n" ); DBGC_HDA ( phantom, virt_to_bus ( &buf->cardrsp ), &buf->cardrsp, sizeof ( buf->cardrsp ) ); - return rc; + goto out; } /* Retrieve context parameters */ - phantom_port->tx_context_id = + phantom->tx_context_id = le16_to_cpu ( buf->cardrsp.tx_ctx.context_id ); - phantom_port->cds_producer_crb = + phantom->cds_producer_crb = ( UNM_CAM_RAM + le32_to_cpu(buf->cardrsp.tx_ctx.cds_ring.host_producer_crb)); - DBGC ( phantom, "Phantom %p port %d created TX context (id %04x, " - "port phys %02x virt %02x)\n", phantom, phantom_port->port, - phantom_port->tx_context_id, buf->cardrsp.tx_ctx.phys_port, - buf->cardrsp.tx_ctx.virt_port ); + DBGC ( phantom, "Phantom %p created TX context (id %04x, port phys " + "%02x virt %02x)\n", phantom, phantom->tx_context_id, + buf->cardrsp.tx_ctx.phys_port, buf->cardrsp.tx_ctx.virt_port ); DBGC2_HDA ( phantom, virt_to_bus ( &buf->cardrsp ), &buf->cardrsp, sizeof ( buf->cardrsp ) ); - DBGC ( phantom, "Phantom %p port %d CDS producer CRB is %08lx\n", - phantom, phantom_port->port, phantom_port->cds_producer_crb ); + DBGC ( phantom, "Phantom %p CDS producer CRB is %08lx\n", + phantom, phantom->cds_producer_crb ); - return 0; + out: + free_dma ( buf, sizeof ( *buf ) ); + return rc; } /** * Destroy Phantom TX context * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @ret rc Return status code */ -static void phantom_destroy_tx_ctx ( struct phantom_nic_port *phantom_port ) { - struct phantom_nic *phantom = phantom_port->phantom; +static void phantom_destroy_tx_ctx ( struct phantom_nic *phantom ) { int rc; - DBGC ( phantom, "Phantom %p port %d destroying TX context (id %04x)\n", - phantom, phantom_port->port, phantom_port->tx_context_id ); + DBGC ( phantom, "Phantom %p destroying TX context (id %04x)\n", + phantom, phantom->tx_context_id ); /* Issue request */ - if ( ( rc = phantom_issue_cmd ( phantom_port, + if ( ( rc = phantom_issue_cmd ( phantom, NX_CDRP_CMD_DESTROY_TX_CTX, - phantom_port->tx_context_id, + phantom->tx_context_id, NX_DESTROY_CTX_RESET, 0 ) ) != 0 ) { - DBGC ( phantom, "Phantom %p port %d could not destroy TX " - "context: %s\n", - phantom, phantom_port->port, strerror ( rc ) ); + DBGC ( phantom, "Phantom %p could not destroy TX context: " + "%s\n", phantom, strerror ( rc ) ); /* We're probably screwed */ return; } /* Clear context parameters */ - phantom_port->tx_context_id = 0; - phantom_port->cds_producer_crb = 0; + phantom->tx_context_id = 0; + phantom->cds_producer_crb = 0; /* Reset software counters */ - phantom_port->cds_producer_idx = 0; - phantom_port->cds_consumer_idx = 0; + phantom->cds_producer_idx = 0; + phantom->cds_consumer_idx = 0; } /*************************************************************************** @@ -951,11 +828,10 @@ static void phantom_destroy_tx_ctx ( struct phantom_nic_port *phantom_port ) { /** * Allocate Phantom RX descriptor * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @ret index RX descriptor index, or negative error */ -static int phantom_alloc_rds ( struct phantom_nic_port *phantom_port ) { - struct phantom_nic *phantom = phantom_port->phantom; +static int phantom_alloc_rds ( struct phantom_nic *phantom ) { unsigned int rds_producer_idx; unsigned int next_rds_producer_idx; @@ -965,12 +841,11 @@ static int phantom_alloc_rds ( struct phantom_nic_port *phantom_port ) { * guaranteed never to be an overestimate of the number of * descriptors read by the hardware. */ - rds_producer_idx = phantom_port->rds_producer_idx; + rds_producer_idx = phantom->rds_producer_idx; next_rds_producer_idx = ( ( rds_producer_idx + 1 ) % PHN_NUM_RDS ); - if ( next_rds_producer_idx == phantom_port->rds_consumer_idx ) { - DBGC ( phantom, "Phantom %p port %d RDS ring full (index %d " - "not consumed)\n", phantom, phantom_port->port, - next_rds_producer_idx ); + if ( next_rds_producer_idx == phantom->rds_consumer_idx ) { + DBGC ( phantom, "Phantom %p RDS ring full (index %d not " + "consumed)\n", phantom, next_rds_producer_idx ); return -ENOBUFS; } @@ -980,41 +855,38 @@ static int phantom_alloc_rds ( struct phantom_nic_port *phantom_port ) { /** * Post Phantom RX descriptor * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v rds RX descriptor */ -static void phantom_post_rds ( struct phantom_nic_port *phantom_port, +static void phantom_post_rds ( struct phantom_nic *phantom, struct phantom_rds *rds ) { - struct phantom_nic *phantom = phantom_port->phantom; unsigned int rds_producer_idx; unsigned int next_rds_producer_idx; struct phantom_rds *entry; /* Copy descriptor to ring */ - rds_producer_idx = phantom_port->rds_producer_idx; - entry = &phantom_port->desc->rds[rds_producer_idx]; + rds_producer_idx = phantom->rds_producer_idx; + entry = &phantom->desc->rds[rds_producer_idx]; memcpy ( entry, rds, sizeof ( *entry ) ); - DBGC2 ( phantom, "Phantom %p port %d posting RDS %ld (slot %d):\n", - phantom, phantom_port->port, NX_GET ( rds, handle ), - rds_producer_idx ); + DBGC2 ( phantom, "Phantom %p posting RDS %ld (slot %d):\n", + phantom, NX_GET ( rds, handle ), rds_producer_idx ); DBGC2_HDA ( phantom, virt_to_bus ( entry ), entry, sizeof ( *entry ) ); /* Update producer index */ next_rds_producer_idx = ( ( rds_producer_idx + 1 ) % PHN_NUM_RDS ); - phantom_port->rds_producer_idx = next_rds_producer_idx; + phantom->rds_producer_idx = next_rds_producer_idx; wmb(); - phantom_writel ( phantom, phantom_port->rds_producer_idx, - phantom_port->rds_producer_crb ); + phantom_writel ( phantom, phantom->rds_producer_idx, + phantom->rds_producer_crb ); } /** * Allocate Phantom TX descriptor * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @ret index TX descriptor index, or negative error */ -static int phantom_alloc_cds ( struct phantom_nic_port *phantom_port ) { - struct phantom_nic *phantom = phantom_port->phantom; +static int phantom_alloc_cds ( struct phantom_nic *phantom ) { unsigned int cds_producer_idx; unsigned int next_cds_producer_idx; @@ -1022,12 +894,11 @@ static int phantom_alloc_cds ( struct phantom_nic_port *phantom_port ) { * in strict order, so we just check for a collision against * the consumer index. */ - cds_producer_idx = phantom_port->cds_producer_idx; + cds_producer_idx = phantom->cds_producer_idx; next_cds_producer_idx = ( ( cds_producer_idx + 1 ) % PHN_NUM_CDS ); - if ( next_cds_producer_idx == phantom_port->cds_consumer_idx ) { - DBGC ( phantom, "Phantom %p port %d CDS ring full (index %d " - "not consumed)\n", phantom, phantom_port->port, - next_cds_producer_idx ); + if ( next_cds_producer_idx == phantom->cds_consumer_idx ) { + DBGC ( phantom, "Phantom %p CDS ring full (index %d not " + "consumed)\n", phantom, next_cds_producer_idx ); return -ENOBUFS; } @@ -1037,30 +908,29 @@ static int phantom_alloc_cds ( struct phantom_nic_port *phantom_port ) { /** * Post Phantom TX descriptor * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v cds TX descriptor */ -static void phantom_post_cds ( struct phantom_nic_port *phantom_port, +static void phantom_post_cds ( struct phantom_nic *phantom, union phantom_cds *cds ) { - struct phantom_nic *phantom = phantom_port->phantom; unsigned int cds_producer_idx; unsigned int next_cds_producer_idx; union phantom_cds *entry; /* Copy descriptor to ring */ - cds_producer_idx = phantom_port->cds_producer_idx; - entry = &phantom_port->desc->cds[cds_producer_idx]; + cds_producer_idx = phantom->cds_producer_idx; + entry = &phantom->desc->cds[cds_producer_idx]; memcpy ( entry, cds, sizeof ( *entry ) ); - DBGC2 ( phantom, "Phantom %p port %d posting CDS %d:\n", - phantom, phantom_port->port, cds_producer_idx ); + DBGC2 ( phantom, "Phantom %p posting CDS %d:\n", + phantom, cds_producer_idx ); DBGC2_HDA ( phantom, virt_to_bus ( entry ), entry, sizeof ( *entry ) ); /* Update producer index */ next_cds_producer_idx = ( ( cds_producer_idx + 1 ) % PHN_NUM_CDS ); - phantom_port->cds_producer_idx = next_cds_producer_idx; + phantom->cds_producer_idx = next_cds_producer_idx; wmb(); - phantom_writel ( phantom, phantom_port->cds_producer_idx, - phantom_port->cds_producer_crb ); + phantom_writel ( phantom, phantom->cds_producer_idx, + phantom->cds_producer_crb ); } /*************************************************************************** @@ -1072,19 +942,19 @@ static void phantom_post_cds ( struct phantom_nic_port *phantom_port, /** * Add/remove MAC address * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v ll_addr MAC address to add or remove * @v opcode MAC request opcode * @ret rc Return status code */ -static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port, +static int phantom_update_macaddr ( struct phantom_nic *phantom, const uint8_t *ll_addr, unsigned int opcode ) { union phantom_cds cds; int index; /* Get descriptor ring entry */ - index = phantom_alloc_cds ( phantom_port ); + index = phantom_alloc_cds ( phantom ); if ( index < 0 ) return index; @@ -1094,7 +964,7 @@ static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port, nic_request.common.opcode, UNM_NIC_REQUEST ); NX_FILL_2 ( &cds, 1, nic_request.header.opcode, UNM_MAC_EVENT, - nic_request.header.context_id, phantom_port->port ); + nic_request.header.context_id, phantom->port ); NX_FILL_7 ( &cds, 2, nic_request.body.mac_request.opcode, opcode, nic_request.body.mac_request.mac_addr_0, ll_addr[0], @@ -1105,7 +975,7 @@ static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port, nic_request.body.mac_request.mac_addr_5, ll_addr[5] ); /* Post descriptor */ - phantom_post_cds ( phantom_port, &cds ); + phantom_post_cds ( phantom, &cds ); return 0; } @@ -1113,35 +983,33 @@ static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port, /** * Add MAC address * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v ll_addr MAC address to add or remove * @ret rc Return status code */ -static inline int phantom_add_macaddr ( struct phantom_nic_port *phantom_port, +static inline int phantom_add_macaddr ( struct phantom_nic *phantom, const uint8_t *ll_addr ) { - struct phantom_nic *phantom = phantom_port->phantom; - DBGC ( phantom, "Phantom %p port %d adding MAC address %s\n", - phantom, phantom_port->port, eth_ntoa ( ll_addr ) ); + DBGC ( phantom, "Phantom %p adding MAC address %s\n", + phantom, eth_ntoa ( ll_addr ) ); - return phantom_update_macaddr ( phantom_port, ll_addr, UNM_MAC_ADD ); + return phantom_update_macaddr ( phantom, ll_addr, UNM_MAC_ADD ); } /** * Remove MAC address * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v ll_addr MAC address to add or remove * @ret rc Return status code */ -static inline int phantom_del_macaddr ( struct phantom_nic_port *phantom_port, +static inline int phantom_del_macaddr ( struct phantom_nic *phantom, const uint8_t *ll_addr ) { - struct phantom_nic *phantom = phantom_port->phantom; - DBGC ( phantom, "Phantom %p port %d removing MAC address %s\n", - phantom, phantom_port->port, eth_ntoa ( ll_addr ) ); + DBGC ( phantom, "Phantom %p removing MAC address %s\n", + phantom, eth_ntoa ( ll_addr ) ); - return phantom_update_macaddr ( phantom_port, ll_addr, UNM_MAC_DEL ); + return phantom_update_macaddr ( phantom, ll_addr, UNM_MAC_DEL ); } /*************************************************************************** @@ -1153,14 +1021,12 @@ static inline int phantom_del_macaddr ( struct phantom_nic_port *phantom_port, /** * Poll link state * - * @v phantom Phantom NIC + * @v netdev Network device */ -static void phantom_poll_link_state ( struct phantom_nic *phantom ) { - struct net_device *netdev; - struct phantom_nic_port *phantom_port; +static void phantom_poll_link_state ( struct net_device *netdev ) { + struct phantom_nic *phantom = netdev_priv ( netdev ); uint32_t xg_state_p3; unsigned int link; - int i; /* Read link state */ xg_state_p3 = phantom_readl ( phantom, UNM_NIC_REG_XG_STATE_P3 ); @@ -1174,28 +1040,22 @@ static void phantom_poll_link_state ( struct phantom_nic *phantom ) { phantom, xg_state_p3, phantom->link_state ); phantom->link_state = xg_state_p3; - /* Indicate per-port link state to gPXE */ - for ( i = 0 ; i < phantom->num_ports ; i++ ) { - netdev = phantom->netdev[i]; - phantom_port = netdev_priv ( netdev ); - link = UNM_NIC_REG_XG_STATE_P3_LINK ( phantom_port->port, - phantom->link_state ); - switch ( link ) { - case UNM_NIC_REG_XG_STATE_P3_LINK_UP: - DBGC ( phantom, "Phantom %p port %d link is up\n", - phantom, phantom_port->port ); - netdev_link_up ( netdev ); - break; - case UNM_NIC_REG_XG_STATE_P3_LINK_DOWN: - DBGC ( phantom, "Phantom %p port %d link is down\n", - phantom, phantom_port->port ); - netdev_link_down ( netdev ); - break; - default: - DBGC ( phantom, "Phantom %p port %d bad link state " - "%d\n", phantom, phantom_port->port, link ); - break; - } + /* Indicate link state to gPXE */ + link = UNM_NIC_REG_XG_STATE_P3_LINK ( phantom->port, + phantom->link_state ); + switch ( link ) { + case UNM_NIC_REG_XG_STATE_P3_LINK_UP: + DBGC ( phantom, "Phantom %p link is up\n", phantom ); + netdev_link_up ( netdev ); + break; + case UNM_NIC_REG_XG_STATE_P3_LINK_DOWN: + DBGC ( phantom, "Phantom %p link is down\n", phantom ); + netdev_link_down ( netdev ); + break; + default: + DBGC ( phantom, "Phantom %p bad link state %d\n", + phantom, link ); + break; } } @@ -1211,7 +1071,7 @@ static void phantom_poll_link_state ( struct phantom_nic *phantom ) { * @v netdev Net device */ static void phantom_refill_rx_ring ( struct net_device *netdev ) { - struct phantom_nic_port *phantom_port = netdev_priv ( netdev ); + struct phantom_nic *phantom = netdev_priv ( netdev ); struct io_buffer *iobuf; struct phantom_rds rds; unsigned int handle; @@ -1222,11 +1082,11 @@ static void phantom_refill_rx_ring ( struct net_device *netdev ) { /* Skip this index if the descriptor has not yet been * consumed. */ - if ( phantom_port->rds_iobuf[handle] != NULL ) + if ( phantom->rds_iobuf[handle] != NULL ) continue; /* Allocate descriptor ring entry */ - index = phantom_alloc_rds ( phantom_port ); + index = phantom_alloc_rds ( phantom ); assert ( PHN_RDS_MAX_FILL < PHN_NUM_RDS ); assert ( index >= 0 ); /* Guaranteed by MAX_FILL < NUM_RDS ) */ @@ -1247,11 +1107,11 @@ static void phantom_refill_rx_ring ( struct net_device *netdev ) { dma_addr, virt_to_bus ( iobuf->data ) ); /* Record I/O buffer */ - assert ( phantom_port->rds_iobuf[handle] == NULL ); - phantom_port->rds_iobuf[handle] = iobuf; + assert ( phantom->rds_iobuf[handle] == NULL ); + phantom->rds_iobuf[handle] = iobuf; /* Post descriptor */ - phantom_post_rds ( phantom_port, &rds ); + phantom_post_rds ( phantom, &rds ); } } @@ -1262,24 +1122,24 @@ static void phantom_refill_rx_ring ( struct net_device *netdev ) { * @ret rc Return status code */ static int phantom_open ( struct net_device *netdev ) { - struct phantom_nic_port *phantom_port = netdev_priv ( netdev ); + struct phantom_nic *phantom = netdev_priv ( netdev ); int rc; /* Allocate and zero descriptor rings */ - phantom_port->desc = malloc_dma ( sizeof ( *(phantom_port->desc) ), + phantom->desc = malloc_dma ( sizeof ( *(phantom->desc) ), UNM_DMA_BUFFER_ALIGN ); - if ( ! phantom_port->desc ) { + if ( ! phantom->desc ) { rc = -ENOMEM; goto err_alloc_desc; } - memset ( phantom_port->desc, 0, sizeof ( *(phantom_port->desc) ) ); + memset ( phantom->desc, 0, sizeof ( *(phantom->desc) ) ); /* Create RX context */ - if ( ( rc = phantom_create_rx_ctx ( phantom_port ) ) != 0 ) + if ( ( rc = phantom_create_rx_ctx ( phantom ) ) != 0 ) goto err_create_rx_ctx; /* Create TX context */ - if ( ( rc = phantom_create_tx_ctx ( phantom_port ) ) != 0 ) + if ( ( rc = phantom_create_tx_ctx ( phantom ) ) != 0 ) goto err_create_tx_ctx; /* Fill the RX descriptor ring */ @@ -1293,26 +1153,26 @@ static int phantom_open ( struct net_device *netdev ) { * packets (or, failing that, promiscuous mode), but the * firmware doesn't currently support this. */ - if ( ( rc = phantom_add_macaddr ( phantom_port, + if ( ( rc = phantom_add_macaddr ( phantom, netdev->ll_protocol->ll_broadcast ) ) != 0 ) goto err_add_macaddr_broadcast; - if ( ( rc = phantom_add_macaddr ( phantom_port, + if ( ( rc = phantom_add_macaddr ( phantom, netdev->ll_addr ) ) != 0 ) goto err_add_macaddr_unicast; return 0; - phantom_del_macaddr ( phantom_port, netdev->ll_addr ); + phantom_del_macaddr ( phantom, netdev->ll_addr ); err_add_macaddr_unicast: - phantom_del_macaddr ( phantom_port, + phantom_del_macaddr ( phantom, netdev->ll_protocol->ll_broadcast ); err_add_macaddr_broadcast: - phantom_destroy_tx_ctx ( phantom_port ); + phantom_destroy_tx_ctx ( phantom ); err_create_tx_ctx: - phantom_destroy_rx_ctx ( phantom_port ); + phantom_destroy_rx_ctx ( phantom ); err_create_rx_ctx: - free_dma ( phantom_port->desc, sizeof ( *(phantom_port->desc) ) ); - phantom_port->desc = NULL; + free_dma ( phantom->desc, sizeof ( *(phantom->desc) ) ); + phantom->desc = NULL; err_alloc_desc: return rc; } @@ -1323,32 +1183,32 @@ static int phantom_open ( struct net_device *netdev ) { * @v netdev Net device */ static void phantom_close ( struct net_device *netdev ) { - struct phantom_nic_port *phantom_port = netdev_priv ( netdev ); + struct phantom_nic *phantom = netdev_priv ( netdev ); struct io_buffer *iobuf; unsigned int i; /* Shut down the port */ - phantom_del_macaddr ( phantom_port, netdev->ll_addr ); - phantom_del_macaddr ( phantom_port, + phantom_del_macaddr ( phantom, netdev->ll_addr ); + phantom_del_macaddr ( phantom, netdev->ll_protocol->ll_broadcast ); - phantom_destroy_tx_ctx ( phantom_port ); - phantom_destroy_rx_ctx ( phantom_port ); - free_dma ( phantom_port->desc, sizeof ( *(phantom_port->desc) ) ); - phantom_port->desc = NULL; + phantom_destroy_tx_ctx ( phantom ); + phantom_destroy_rx_ctx ( phantom ); + free_dma ( phantom->desc, sizeof ( *(phantom->desc) ) ); + phantom->desc = NULL; /* Flush any uncompleted descriptors */ for ( i = 0 ; i < PHN_RDS_MAX_FILL ; i++ ) { - iobuf = phantom_port->rds_iobuf[i]; + iobuf = phantom->rds_iobuf[i]; if ( iobuf ) { free_iob ( iobuf ); - phantom_port->rds_iobuf[i] = NULL; + phantom->rds_iobuf[i] = NULL; } } for ( i = 0 ; i < PHN_NUM_CDS ; i++ ) { - iobuf = phantom_port->cds_iobuf[i]; + iobuf = phantom->cds_iobuf[i]; if ( iobuf ) { netdev_tx_complete_err ( netdev, iobuf, -ECANCELED ); - phantom_port->cds_iobuf[i] = NULL; + phantom->cds_iobuf[i] = NULL; } } } @@ -1362,12 +1222,12 @@ static void phantom_close ( struct net_device *netdev ) { */ static int phantom_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { - struct phantom_nic_port *phantom_port = netdev_priv ( netdev ); + struct phantom_nic *phantom = netdev_priv ( netdev ); union phantom_cds cds; int index; /* Get descriptor ring entry */ - index = phantom_alloc_cds ( phantom_port ); + index = phantom_alloc_cds ( phantom ); if ( index < 0 ) return index; @@ -1378,19 +1238,19 @@ static int phantom_transmit ( struct net_device *netdev, tx.num_buffers, 1, tx.length, iob_len ( iobuf ) ); NX_FILL_2 ( &cds, 2, - tx.port, phantom_port->port, - tx.context_id, phantom_port->port ); + tx.port, phantom->port, + tx.context_id, phantom->port ); NX_FILL_1 ( &cds, 4, tx.buffer1_dma_addr, virt_to_bus ( iobuf->data ) ); NX_FILL_1 ( &cds, 5, tx.buffer1_length, iob_len ( iobuf ) ); /* Record I/O buffer */ - assert ( phantom_port->cds_iobuf[index] == NULL ); - phantom_port->cds_iobuf[index] = iobuf; + assert ( phantom->cds_iobuf[index] == NULL ); + phantom->cds_iobuf[index] = iobuf; /* Post descriptor */ - phantom_post_cds ( phantom_port, &cds ); + phantom_post_cds ( phantom, &cds ); return 0; } @@ -1401,8 +1261,7 @@ static int phantom_transmit ( struct net_device *netdev, * @v netdev Network device */ static void phantom_poll ( struct net_device *netdev ) { - struct phantom_nic_port *phantom_port = netdev_priv ( netdev ); - struct phantom_nic *phantom = phantom_port->phantom; + struct phantom_nic *phantom = netdev_priv ( netdev ); struct io_buffer *iobuf; unsigned int cds_consumer_idx; unsigned int raw_new_cds_consumer_idx; @@ -1414,33 +1273,33 @@ static void phantom_poll ( struct net_device *netdev ) { unsigned int sds_opcode; /* Check for TX completions */ - cds_consumer_idx = phantom_port->cds_consumer_idx; - raw_new_cds_consumer_idx = phantom_port->desc->cmd_cons; + cds_consumer_idx = phantom->cds_consumer_idx; + raw_new_cds_consumer_idx = phantom->desc->cmd_cons; new_cds_consumer_idx = le32_to_cpu ( raw_new_cds_consumer_idx ); while ( cds_consumer_idx != new_cds_consumer_idx ) { - DBGC2 ( phantom, "Phantom %p port %d CDS %d complete\n", - phantom, phantom_port->port, cds_consumer_idx ); + DBGC2 ( phantom, "Phantom %p CDS %d complete\n", + phantom, cds_consumer_idx ); /* Completions may be for commands other than TX, so * there may not always be an associated I/O buffer. */ - if ( ( iobuf = phantom_port->cds_iobuf[cds_consumer_idx] ) ) { + if ( ( iobuf = phantom->cds_iobuf[cds_consumer_idx] ) ) { netdev_tx_complete ( netdev, iobuf ); - phantom_port->cds_iobuf[cds_consumer_idx] = NULL; + phantom->cds_iobuf[cds_consumer_idx] = NULL; } cds_consumer_idx = ( ( cds_consumer_idx + 1 ) % PHN_NUM_CDS ); - phantom_port->cds_consumer_idx = cds_consumer_idx; + phantom->cds_consumer_idx = cds_consumer_idx; } /* Check for received packets */ - rds_consumer_idx = phantom_port->rds_consumer_idx; - sds_consumer_idx = phantom_port->sds_consumer_idx; + rds_consumer_idx = phantom->rds_consumer_idx; + sds_consumer_idx = phantom->sds_consumer_idx; while ( 1 ) { - sds = &phantom_port->desc->sds[sds_consumer_idx]; + sds = &phantom->desc->sds[sds_consumer_idx]; if ( NX_GET ( sds, owner ) == 0 ) break; - DBGC2 ( phantom, "Phantom %p port %d SDS %d status:\n", - phantom, phantom_port->port, sds_consumer_idx ); + DBGC2 ( phantom, "Phantom %p SDS %d status:\n", + phantom, sds_consumer_idx ); DBGC2_HDA ( phantom, virt_to_bus ( sds ), sds, sizeof (*sds) ); /* Check received opcode */ @@ -1452,24 +1311,23 @@ static void phantom_poll ( struct net_device *netdev ) { * descriptor has been written. */ if ( NX_GET ( sds, total_length ) == 0 ) { - DBGC ( phantom, "Phantom %p port %d SDS %d " - "incomplete; deferring\n", phantom, - phantom_port->port, sds_consumer_idx ); + DBGC ( phantom, "Phantom %p SDS %d " + "incomplete; deferring\n", + phantom, sds_consumer_idx ); /* Leave for next poll() */ break; } /* Process received packet */ sds_handle = NX_GET ( sds, handle ); - iobuf = phantom_port->rds_iobuf[sds_handle]; + iobuf = phantom->rds_iobuf[sds_handle]; assert ( iobuf != NULL ); iob_put ( iobuf, NX_GET ( sds, total_length ) ); iob_pull ( iobuf, NX_GET ( sds, pkt_offset ) ); - DBGC2 ( phantom, "Phantom %p port %d RDS %d " - "complete\n", - phantom, phantom_port->port, sds_handle ); + DBGC2 ( phantom, "Phantom %p RDS %d complete\n", + phantom, sds_handle ); netdev_rx ( netdev, iobuf ); - phantom_port->rds_iobuf[sds_handle] = NULL; + phantom->rds_iobuf[sds_handle] = NULL; /* Update RDS consumer counter. This is a * lower bound for the number of descriptors @@ -1480,13 +1338,12 @@ static void phantom_poll ( struct net_device *netdev ) { */ rds_consumer_idx = ( ( rds_consumer_idx + 1 ) % PHN_NUM_RDS ); - phantom_port->rds_consumer_idx = rds_consumer_idx; + phantom->rds_consumer_idx = rds_consumer_idx; } else { - DBGC ( phantom, "Phantom %p port %d unexpected SDS " - "opcode %02x\n", - phantom, phantom_port->port, sds_opcode ); + DBGC ( phantom, "Phantom %p unexpected SDS opcode " + "%02x\n", phantom, sds_opcode ); DBGC_HDA ( phantom, virt_to_bus ( sds ), sds, sizeof ( *sds ) ); } @@ -1496,20 +1353,20 @@ static void phantom_poll ( struct net_device *netdev ) { /* Update SDS consumer index */ sds_consumer_idx = ( ( sds_consumer_idx + 1 ) % PHN_NUM_SDS ); - phantom_port->sds_consumer_idx = sds_consumer_idx; + phantom->sds_consumer_idx = sds_consumer_idx; wmb(); - phantom_writel ( phantom, phantom_port->sds_consumer_idx, - phantom_port->sds_consumer_crb ); + phantom_writel ( phantom, phantom->sds_consumer_idx, + phantom->sds_consumer_crb ); } /* Refill the RX descriptor ring */ phantom_refill_rx_ring ( netdev ); /* Occasionally poll the link state */ - if ( phantom_port->link_poll_timer-- == 0 ) { - phantom_poll_link_state ( phantom ); + if ( phantom->link_poll_timer-- == 0 ) { + phantom_poll_link_state ( netdev ); /* Reset the link poll timer */ - phantom_port->link_poll_timer = PHN_LINK_POLL_FREQUENCY; + phantom->link_poll_timer = PHN_LINK_POLL_FREQUENCY; } } @@ -1520,9 +1377,8 @@ static void phantom_poll ( struct net_device *netdev ) { * @v enable Interrupts should be enabled */ static void phantom_irq ( struct net_device *netdev, int enable ) { - struct phantom_nic_port *phantom_port = netdev_priv ( netdev ); - struct phantom_nic *phantom = phantom_port->phantom; - static const unsigned long sw_int_mask_reg[UNM_FLASH_NUM_PORTS] = { + struct phantom_nic *phantom = netdev_priv ( netdev ); + static const unsigned long sw_int_mask_reg[PHN_MAX_NUM_PORTS] = { UNM_NIC_REG_SW_INT_MASK_0, UNM_NIC_REG_SW_INT_MASK_1, UNM_NIC_REG_SW_INT_MASK_2, @@ -1531,7 +1387,7 @@ static void phantom_irq ( struct net_device *netdev, int enable ) { phantom_writel ( phantom, ( enable ? 1 : 0 ), - sw_int_mask_reg[phantom_port->port] ); + sw_int_mask_reg[phantom->port] ); } /** Phantom net device operations */ @@ -1543,6 +1399,336 @@ static struct net_device_operations phantom_operations = { .irq = phantom_irq, }; +/*************************************************************************** + * + * CLP settings + * + */ + +/** Phantom CLP settings tag magic */ +#define PHN_CLP_TAG_MAGIC 0xc19c1900UL + +/** Phantom CLP settings tag magic mask */ +#define PHN_CLP_TAG_MAGIC_MASK 0xffffff00UL + +/** Phantom CLP data + * + */ +union phantom_clp_data { + /** Data bytes + * + * This field is right-aligned; if only N bytes are present + * then bytes[0]..bytes[7-N] should be zero, and the data + * should be in bytes[7-N+1] to bytes[7]; + */ + uint8_t bytes[8]; + /** Dwords for the CLP interface */ + struct { + /** High dword, in network byte order */ + uint32_t hi; + /** Low dword, in network byte order */ + uint32_t lo; + } dwords; +}; +#define PHN_CLP_BLKSIZE ( sizeof ( union phantom_clp_data ) ) + +/** + * Wait for Phantom CLP command to complete + * + * @v phantom Phantom NIC + * @ret rc Return status code + */ +static int phantom_clp_wait ( struct phantom_nic *phantom ) { + unsigned int retries; + uint32_t status; + + for ( retries = 0 ; retries < PHN_CLP_CMD_TIMEOUT_MS ; retries++ ) { + status = phantom_readl ( phantom, UNM_CAM_RAM_CLP_STATUS ); + if ( status & UNM_CAM_RAM_CLP_STATUS_DONE ) + return 0; + mdelay ( 1 ); + } + + DBGC ( phantom, "Phantom %p timed out waiting for CLP command\n", + phantom ); + return -ETIMEDOUT; +} + +/** + * Issue Phantom CLP command + * + * @v phantom Phantom NIC + * @v port Virtual port number + * @v opcode Opcode + * @v data_in Data in, or NULL + * @v data_out Data out, or NULL + * @v offset Offset within data + * @v len Data buffer length + * @ret len Total transfer length (for reads), or negative error + */ +static int phantom_clp_cmd ( struct phantom_nic *phantom, unsigned int port, + unsigned int opcode, const void *data_in, + void *data_out, size_t offset, size_t len ) { + union phantom_clp_data data; + unsigned int index = ( offset / sizeof ( data ) ); + unsigned int last = 0; + size_t in_frag_len; + uint8_t *in_frag; + uint32_t command; + uint32_t status; + size_t read_len; + unsigned int error; + size_t out_frag_len; + uint8_t *out_frag; + int rc; + + /* Sanity checks */ + assert ( ( offset % sizeof ( data ) ) == 0 ); + if ( len > 255 ) { + DBGC ( phantom, "Phantom %p invalid CLP length %zd\n", + phantom, len ); + return -EINVAL; + } + + /* Check that CLP interface is ready */ + if ( ( rc = phantom_clp_wait ( phantom ) ) != 0 ) + return rc; + + /* Copy data in */ + memset ( &data, 0, sizeof ( data ) ); + if ( data_in ) { + assert ( offset < len ); + in_frag_len = ( len - offset ); + if ( in_frag_len > sizeof ( data ) ) { + in_frag_len = sizeof ( data ); + } else { + last = 1; + } + in_frag = &data.bytes[ sizeof ( data ) - in_frag_len ]; + memcpy ( in_frag, ( data_in + offset ), in_frag_len ); + phantom_writel ( phantom, be32_to_cpu ( data.dwords.lo ), + UNM_CAM_RAM_CLP_DATA_LO ); + phantom_writel ( phantom, be32_to_cpu ( data.dwords.hi ), + UNM_CAM_RAM_CLP_DATA_HI ); + } + + /* Issue CLP command */ + command = ( ( index << 24 ) | ( ( data_in ? len : 0 ) << 16 ) | + ( port << 8 ) | ( last << 7 ) | ( opcode << 0 ) ); + phantom_writel ( phantom, command, UNM_CAM_RAM_CLP_COMMAND ); + mb(); + phantom_writel ( phantom, UNM_CAM_RAM_CLP_STATUS_START, + UNM_CAM_RAM_CLP_STATUS ); + + /* Wait for command to complete */ + if ( ( rc = phantom_clp_wait ( phantom ) ) != 0 ) + return rc; + + /* Get command status */ + status = phantom_readl ( phantom, UNM_CAM_RAM_CLP_STATUS ); + read_len = ( ( status >> 16 ) & 0xff ); + error = ( ( status >> 8 ) & 0xff ); + if ( error ) { + DBGC ( phantom, "Phantom %p CLP command error %02x\n", + phantom, error ); + return -EIO; + } + + /* Copy data out */ + if ( data_out ) { + data.dwords.lo = cpu_to_be32 ( phantom_readl ( phantom, + UNM_CAM_RAM_CLP_DATA_LO ) ); + data.dwords.hi = cpu_to_be32 ( phantom_readl ( phantom, + UNM_CAM_RAM_CLP_DATA_HI ) ); + out_frag_len = ( read_len - offset ); + if ( out_frag_len > sizeof ( data ) ) + out_frag_len = sizeof ( data ); + out_frag = &data.bytes[ sizeof ( data ) - out_frag_len ]; + if ( out_frag_len > ( len - offset ) ) + out_frag_len = ( len - offset ); + memcpy ( ( data_out + offset ), out_frag, out_frag_len ); + } + + return read_len; +} + +/** + * Store Phantom CLP setting + * + * @v phantom Phantom NIC + * @v port Virtual port number + * @v setting Setting number + * @v data Data buffer + * @v len Length of data buffer + * @ret rc Return status code + */ +static int phantom_clp_store ( struct phantom_nic *phantom, unsigned int port, + unsigned int setting, const void *data, + size_t len ) { + unsigned int opcode = setting; + size_t offset; + int rc; + + for ( offset = 0 ; offset < len ; offset += PHN_CLP_BLKSIZE ) { + if ( ( rc = phantom_clp_cmd ( phantom, port, opcode, data, + NULL, offset, len ) ) < 0 ) + return rc; + } + return 0; +} + +/** + * Fetch Phantom CLP setting + * + * @v phantom Phantom NIC + * @v port Virtual port number + * @v setting Setting number + * @v data Data buffer + * @v len Length of data buffer + * @ret len Length of setting, or negative error + */ +static int phantom_clp_fetch ( struct phantom_nic *phantom, unsigned int port, + unsigned int setting, void *data, size_t len ) { + unsigned int opcode = ( setting + 1 ); + size_t offset = 0; + int read_len; + + while ( 1 ) { + read_len = phantom_clp_cmd ( phantom, port, opcode, NULL, + data, offset, len ); + if ( read_len < 0 ) + return read_len; + offset += PHN_CLP_BLKSIZE; + if ( offset >= ( unsigned ) read_len ) + break; + if ( offset >= len ) + break; + } + return read_len; +} + +/** A Phantom CLP setting */ +struct phantom_clp_setting { + /** gPXE setting */ + struct setting *setting; + /** Setting number */ + unsigned int clp_setting; +}; + +/** Phantom CLP settings */ +static struct phantom_clp_setting clp_settings[] = { + { &mac_setting, 0x01 }, +}; + +/** + * Find Phantom CLP setting + * + * @v setting gPXE setting + * @v clp_setting Setting number, or 0 if not found + */ +static unsigned int +phantom_clp_setting ( struct phantom_nic *phantom, struct setting *setting ) { + struct phantom_clp_setting *clp_setting; + unsigned int i; + + /* Search the list of explicitly-defined settings */ + for ( i = 0 ; i < ( sizeof ( clp_settings ) / + sizeof ( clp_settings[0] ) ) ; i++ ) { + clp_setting = &clp_settings[i]; + if ( setting_cmp ( setting, clp_setting->setting ) == 0 ) + return clp_setting->clp_setting; + } + + /* Allow for use of numbered settings */ + if ( ( setting->tag & PHN_CLP_TAG_MAGIC_MASK ) == PHN_CLP_TAG_MAGIC ) + return ( setting->tag & ~PHN_CLP_TAG_MAGIC_MASK ); + + DBGC2 ( phantom, "Phantom %p has no \"%s\" setting\n", + phantom, setting->name ); + + return 0; +} + +/** + * Store Phantom CLP setting + * + * @v settings Settings block + * @v setting Setting to store + * @v data Setting data, or NULL to clear setting + * @v len Length of setting data + * @ret rc Return status code + */ +static int phantom_store_setting ( struct settings *settings, + struct setting *setting, + const void *data, size_t len ) { + struct phantom_nic *phantom = + container_of ( settings, struct phantom_nic, settings ); + unsigned int clp_setting; + int rc; + + /* Find Phantom setting equivalent to gPXE setting */ + clp_setting = phantom_clp_setting ( phantom, setting ); + if ( ! clp_setting ) + return -ENOTSUP; + + /* Store setting */ + if ( ( rc = phantom_clp_store ( phantom, phantom->port, + clp_setting, data, len ) ) != 0 ) { + DBGC ( phantom, "Phantom %p could not store setting \"%s\": " + "%s\n", phantom, setting->name, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Fetch Phantom CLP setting + * + * @v settings Settings block + * @v setting Setting to fetch + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ +static int phantom_fetch_setting ( struct settings *settings, + struct setting *setting, + void *data, size_t len ) { + struct phantom_nic *phantom = + container_of ( settings, struct phantom_nic, settings ); + unsigned int clp_setting; + int read_len; + int rc; + + /* Find Phantom setting equivalent to gPXE setting */ + clp_setting = phantom_clp_setting ( phantom, setting ); + if ( ! clp_setting ) + return -ENOTSUP; + + /* Fetch setting */ + if ( ( read_len = phantom_clp_fetch ( phantom, phantom->port, + clp_setting, data, len ) ) < 0 ){ + rc = read_len; + DBGC ( phantom, "Phantom %p could not fetch setting \"%s\": " + "%s\n", phantom, setting->name, strerror ( rc ) ); + return rc; + } + + return read_len; +} + +/** Phantom CLP settings operations */ +static struct settings_operations phantom_settings_operations = { + .store = phantom_store_setting, + .fetch = phantom_fetch_setting, +}; + +/*************************************************************************** + * + * Initialisation + * + */ + /** * Map Phantom CRB window * @@ -1556,8 +1742,15 @@ static int phantom_map_crb ( struct phantom_nic *phantom, bar0_start = pci_bar_start ( pci, PCI_BASE_ADDRESS_0 ); bar0_size = pci_bar_size ( pci, PCI_BASE_ADDRESS_0 ); - DBGC ( phantom, "Phantom %p BAR0 is %08lx+%lx\n", - phantom, bar0_start, bar0_size ); + DBGC ( phantom, "Phantom %p is PCI %02x:%02x.%x with BAR0 at " + "%08lx+%lx\n", phantom, pci->bus, PCI_SLOT ( pci->devfn ), + PCI_FUNC ( pci->devfn ), bar0_start, bar0_size ); + + if ( ! bar0_start ) { + DBGC ( phantom, "Phantom %p BAR not assigned; ignoring\n", + phantom ); + return -EINVAL; + } switch ( bar0_size ) { case ( 128 * 1024 * 1024 ) : @@ -1592,71 +1785,23 @@ static int phantom_map_crb ( struct phantom_nic *phantom, } /** - * Read Phantom flash contents + * Unhalt all PEGs * * @v phantom Phantom NIC - * @ret rc Return status code */ -static int phantom_read_flash ( struct phantom_nic *phantom ) { - struct unm_board_info board_info; - int rc; - - /* Initialise flash access */ - phantom->spi_bus.rw = phantom_spi_rw; - phantom->flash.bus = &phantom->spi_bus; - init_m25p32 ( &phantom->flash ); - /* Phantom doesn't support greater than 4-byte block sizes */ - phantom->flash.nvs.block_size = UNM_SPI_BLKSIZE; - - /* Read and verify board information */ - if ( ( rc = nvs_read ( &phantom->flash.nvs, UNM_BRDCFG_START, - &board_info, sizeof ( board_info ) ) ) != 0 ) { - DBGC ( phantom, "Phantom %p could not read board info: %s\n", - phantom, strerror ( rc ) ); - return rc; - } - if ( board_info.magic != UNM_BDINFO_MAGIC ) { - DBGC ( phantom, "Phantom %p has bad board info magic %lx\n", - phantom, board_info.magic ); - DBGC_HD ( phantom, &board_info, sizeof ( board_info ) ); - return -EINVAL; - } - if ( board_info.header_version != UNM_BDINFO_VERSION ) { - DBGC ( phantom, "Phantom %p has bad board info version %lx\n", - phantom, board_info.header_version ); - DBGC_HD ( phantom, &board_info, sizeof ( board_info ) ); - return -EINVAL; - } - - /* Identify board type and number of ports */ - switch ( board_info.board_type ) { - case UNM_BRDTYPE_P3_4_GB: - case UNM_BRDTYPE_P3_4_GB_MM: - phantom->num_ports = 4; - break; - case UNM_BRDTYPE_P3_HMEZ: - case UNM_BRDTYPE_P3_IMEZ: - case UNM_BRDTYPE_P3_10G_CX4: - case UNM_BRDTYPE_P3_10G_CX4_LP: - case UNM_BRDTYPE_P3_10G_SFP_PLUS: - case UNM_BRDTYPE_P3_XG_LOM: - phantom->num_ports = 2; - break; - case UNM_BRDTYPE_P3_10000_BASE_T: - case UNM_BRDTYPE_P3_10G_XFP: - phantom->num_ports = 1; - break; - default: - DBGC ( phantom, "Phantom %p unrecognised board type %#lx; " - "assuming single-port\n", - phantom, board_info.board_type ); - phantom->num_ports = 1; - break; - } - DBGC ( phantom, "Phantom %p board type is %#lx (%d ports)\n", - phantom, board_info.board_type, phantom->num_ports ); - - return 0; +static void phantom_unhalt_pegs ( struct phantom_nic *phantom ) { + uint32_t halt_status; + + halt_status = phantom_readl ( phantom, UNM_PEG_0_HALT_STATUS ); + phantom_writel ( phantom, halt_status, UNM_PEG_0_HALT_STATUS ); + halt_status = phantom_readl ( phantom, UNM_PEG_1_HALT_STATUS ); + phantom_writel ( phantom, halt_status, UNM_PEG_1_HALT_STATUS ); + halt_status = phantom_readl ( phantom, UNM_PEG_2_HALT_STATUS ); + phantom_writel ( phantom, halt_status, UNM_PEG_2_HALT_STATUS ); + halt_status = phantom_readl ( phantom, UNM_PEG_3_HALT_STATUS ); + phantom_writel ( phantom, halt_status, UNM_PEG_3_HALT_STATUS ); + halt_status = phantom_readl ( phantom, UNM_PEG_4_HALT_STATUS ); + phantom_writel ( phantom, halt_status, UNM_PEG_4_HALT_STATUS ); } /** @@ -1668,7 +1813,6 @@ static int phantom_read_flash ( struct phantom_nic *phantom ) { static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) { uint32_t cold_boot; uint32_t sw_reset; - physaddr_t dummy_dma_phys; unsigned int retries; uint32_t cmdpeg_state; uint32_t last_cmdpeg_state = 0; @@ -1681,6 +1825,11 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) { if ( cmdpeg_state == UNM_NIC_REG_CMDPEG_STATE_INITIALIZE_ACK ) { DBGC ( phantom, "Phantom %p command PEG already initialized\n", phantom ); + /* Unhalt the PEGs. Previous firmware (e.g. BOFM) may + * have halted the PEGs to prevent internal bus + * collisions when the BIOS re-reads the expansion ROM. + */ + phantom_unhalt_pegs ( phantom ); return 0; } @@ -1707,10 +1856,7 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) { UNM_CAM_RAM_WOL_PORT_MODE ); /* Pass dummy DMA area to card */ - dummy_dma_phys = virt_to_bus ( phantom->dma_buf->dummy_dma ); - DBGC ( phantom, "Phantom %p dummy DMA at %08lx\n", - phantom, dummy_dma_phys ); - phantom_write_hilo ( phantom, dummy_dma_phys, + phantom_write_hilo ( phantom, 0, UNM_NIC_REG_DUMMY_BUF_ADDR_LO, UNM_NIC_REG_DUMMY_BUF_ADDR_HI ); phantom_writel ( phantom, UNM_NIC_REG_DUMMY_BUF_INIT, @@ -1750,12 +1896,11 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) { /** * Read Phantom MAC address * - * @v phanton_port Phantom NIC port + * @v phanton_port Phantom NIC * @v ll_addr Buffer to fill with MAC address */ -static void phantom_get_macaddr ( struct phantom_nic_port *phantom_port, +static void phantom_get_macaddr ( struct phantom_nic *phantom, uint8_t *ll_addr ) { - struct phantom_nic *phantom = phantom_port->phantom; union { uint8_t mac_addr[2][ETH_ALEN]; uint32_t dwords[3]; @@ -1765,7 +1910,7 @@ static void phantom_get_macaddr ( struct phantom_nic_port *phantom_port, /* Read the three dwords that include this MAC address and one other */ offset = ( UNM_CAM_RAM_MAC_ADDRS + - ( 12 * ( phantom_port->port / 2 ) ) ); + ( 12 * ( phantom->port / 2 ) ) ); for ( i = 0 ; i < 3 ; i++, offset += 4 ) { u.dwords[i] = phantom_readl ( phantom, offset ); } @@ -1773,10 +1918,36 @@ static void phantom_get_macaddr ( struct phantom_nic_port *phantom_port, /* Copy out the relevant MAC address */ for ( i = 0 ; i < ETH_ALEN ; i++ ) { ll_addr[ ETH_ALEN - i - 1 ] = - u.mac_addr[ phantom_port->port & 1 ][i]; + u.mac_addr[ phantom->port & 1 ][i]; } - DBGC ( phantom, "Phantom %p port %d MAC address is %s\n", - phantom, phantom_port->port, eth_ntoa ( ll_addr ) ); + DBGC ( phantom, "Phantom %p MAC address is %s\n", + phantom, eth_ntoa ( ll_addr ) ); +} + +/** + * Check Phantom is enabled for boot + * + * @v phanton_port Phantom NIC + * @ret rc Return status code + * + * This is something of an ugly hack to accommodate an OEM + * requirement. The NIC has only one expansion ROM BAR, rather than + * one per port. To allow individual ports to be selectively + * enabled/disabled for PXE boot (as required), we must therefore + * leave the expansion ROM always enabled, and place the per-port + * enable/disable logic within the gPXE driver. + */ +static int phantom_check_boot_enable ( struct phantom_nic *phantom ) { + unsigned long boot_enable; + + boot_enable = phantom_readl ( phantom, UNM_CAM_RAM_BOOT_ENABLE ); + if ( ! ( boot_enable & ( 1 << phantom->port ) ) ) { + DBGC ( phantom, "Phantom %p PXE boot is disabled\n", + phantom ); + return -ENOTSUP; + } + + return 0; } /** @@ -1820,25 +1991,27 @@ static int phantom_init_rcvpeg ( struct phantom_nic *phantom ) { */ static int phantom_probe ( struct pci_device *pci, const struct pci_device_id *id __unused ) { - struct phantom_nic *phantom; struct net_device *netdev; - struct phantom_nic_port *phantom_port; - int i; + struct phantom_nic *phantom; + struct settings *parent_settings; int rc; - /* Phantom NICs expose multiple PCI functions, used for - * virtualisation. Ignore everything except function 0. - */ - if ( PCI_FUNC ( pci->devfn ) != 0 ) - return -ENODEV; - /* Allocate Phantom device */ - phantom = zalloc ( sizeof ( *phantom ) ); - if ( ! phantom ) { + netdev = alloc_etherdev ( sizeof ( *phantom ) ); + if ( ! netdev ) { rc = -ENOMEM; - goto err_alloc_phantom; + goto err_alloc_etherdev; } - pci_set_drvdata ( pci, phantom ); + netdev_init ( netdev, &phantom_operations ); + phantom = netdev_priv ( netdev ); + pci_set_drvdata ( pci, netdev ); + netdev->dev = &pci->dev; + memset ( phantom, 0, sizeof ( *phantom ) ); + phantom->port = PCI_FUNC ( pci->devfn ); + assert ( phantom->port < PHN_MAX_NUM_PORTS ); + settings_init ( &phantom->settings, + &phantom_settings_operations, + &netdev->refcnt, "clp", PHN_CLP_TAG_MAGIC ); /* Fix up PCI device */ adjust_pci_device ( pci ); @@ -1847,87 +2020,66 @@ static int phantom_probe ( struct pci_device *pci, if ( ( rc = phantom_map_crb ( phantom, pci ) ) != 0 ) goto err_map_crb; - /* Read flash information */ - if ( ( rc = phantom_read_flash ( phantom ) ) != 0 ) - goto err_read_flash; - - /* Allocate net devices for each port */ - for ( i = 0 ; i < phantom->num_ports ; i++ ) { - netdev = alloc_etherdev ( sizeof ( *phantom_port ) ); - if ( ! netdev ) { - rc = -ENOMEM; - goto err_alloc_etherdev; - } - phantom->netdev[i] = netdev; - netdev_init ( netdev, &phantom_operations ); - phantom_port = netdev_priv ( netdev ); - netdev->dev = &pci->dev; - phantom_port->phantom = phantom; - phantom_port->port = i; - } - /* BUG5945 - need to hack PCI config space on P3 B1 silicon. * B2 will have this fixed; remove this hack when B1 is no * longer in use. */ - for ( i = 0 ; i < 8 ; i++ ) { - uint32_t temp; - pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), i ); - pci_read_config_dword ( pci, 0xc8, &temp ); - pci_read_config_dword ( pci, 0xc8, &temp ); - pci_write_config_dword ( pci, 0xc8, 0xf1000 ); + if ( PCI_FUNC ( pci->devfn ) == 0 ) { + unsigned int i; + for ( i = 0 ; i < 8 ; i++ ) { + uint32_t temp; + pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), i ); + pci_read_config_dword ( pci, 0xc8, &temp ); + pci_read_config_dword ( pci, 0xc8, &temp ); + pci_write_config_dword ( pci, 0xc8, 0xf1000 ); + } + pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), 0 ); } - pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), 0 ); - /* Allocate dummy DMA buffer and perform initial hardware handshake */ - phantom->dma_buf = malloc_dma ( sizeof ( *(phantom->dma_buf) ), - UNM_DMA_BUFFER_ALIGN ); - if ( ! phantom->dma_buf ) - goto err_dma_buf; + /* Initialise the command PEG */ if ( ( rc = phantom_init_cmdpeg ( phantom ) ) != 0 ) goto err_init_cmdpeg; - /* Initialise the receive firmware */ + /* Initialise the receive PEG */ if ( ( rc = phantom_init_rcvpeg ( phantom ) ) != 0 ) goto err_init_rcvpeg; /* Read MAC addresses */ - for ( i = 0 ; i < phantom->num_ports ; i++ ) { - phantom_port = netdev_priv ( phantom->netdev[i] ); - phantom_get_macaddr ( phantom_port, - phantom->netdev[i]->ll_addr ); - } + phantom_get_macaddr ( phantom, netdev->ll_addr ); + + /* Skip if boot disabled on NIC */ + if ( ( rc = phantom_check_boot_enable ( phantom ) ) != 0 ) + goto err_check_boot_enable; /* Register network devices */ - for ( i = 0 ; i < phantom->num_ports ; i++ ) { - if ( ( rc = register_netdev ( phantom->netdev[i] ) ) != 0 ) { - DBGC ( phantom, "Phantom %p could not register port " - "%d: %s\n", phantom, i, strerror ( rc ) ); - goto err_register_netdev; - } + if ( ( rc = register_netdev ( netdev ) ) != 0 ) { + DBGC ( phantom, "Phantom %p could not register net device: " + "%s\n", phantom, strerror ( rc ) ); + goto err_register_netdev; + } + + /* Register settings blocks */ + parent_settings = netdev_settings ( netdev ); + if ( ( rc = register_settings ( &phantom->settings, + parent_settings ) ) != 0 ) { + DBGC ( phantom, "Phantom %p could not register settings: " + "%s\n", phantom, strerror ( rc ) ); + goto err_register_settings; } return 0; - i = ( phantom->num_ports - 1 ); + unregister_settings ( &phantom->settings ); + err_register_settings: + unregister_netdev ( netdev ); err_register_netdev: - for ( ; i >= 0 ; i-- ) - unregister_netdev ( phantom->netdev[i] ); + err_check_boot_enable: err_init_rcvpeg: err_init_cmdpeg: - free_dma ( phantom->dma_buf, sizeof ( *(phantom->dma_buf) ) ); - phantom->dma_buf = NULL; - err_dma_buf: - i = ( phantom->num_ports - 1 ); - err_alloc_etherdev: - for ( ; i >= 0 ; i-- ) { - netdev_nullify ( phantom->netdev[i] ); - netdev_put ( phantom->netdev[i] ); - } - err_read_flash: err_map_crb: - free ( phantom ); - err_alloc_phantom: + netdev_nullify ( netdev ); + netdev_put ( netdev ); + err_alloc_etherdev: return rc; } @@ -1937,18 +2089,13 @@ static int phantom_probe ( struct pci_device *pci, * @v pci PCI device */ static void phantom_remove ( struct pci_device *pci ) { - struct phantom_nic *phantom = pci_get_drvdata ( pci ); - int i; + struct net_device *netdev = pci_get_drvdata ( pci ); + struct phantom_nic *phantom = netdev_priv ( netdev ); - for ( i = ( phantom->num_ports - 1 ) ; i >= 0 ; i-- ) - unregister_netdev ( phantom->netdev[i] ); - free_dma ( phantom->dma_buf, sizeof ( *(phantom->dma_buf) ) ); - phantom->dma_buf = NULL; - for ( i = ( phantom->num_ports - 1 ) ; i >= 0 ; i-- ) { - netdev_nullify ( phantom->netdev[i] ); - netdev_put ( phantom->netdev[i] ); - } - free ( phantom ); + unregister_settings ( &phantom->settings ); + unregister_netdev ( netdev ); + netdev_nullify ( netdev ); + netdev_put ( netdev ); } /** Phantom PCI IDs */ diff --git a/gpxe/src/drivers/net/phantom/phantom.h b/gpxe/src/drivers/net/phantom/phantom.h index 110c1226..974eecae 100644 --- a/gpxe/src/drivers/net/phantom/phantom.h +++ b/gpxe/src/drivers/net/phantom/phantom.h @@ -45,18 +45,12 @@ typedef uint32_t nx_rcode_t; #define NXHAL_VERSION 1 #include "nxhal_nic_interface.h" -/** SPI controller maximum block size */ -#define UNM_SPI_BLKSIZE 4 - /** DMA buffer alignment */ #define UNM_DMA_BUFFER_ALIGN 16 /** Mark structure as DMA-aligned */ #define __unm_dma_aligned __attribute__ (( aligned ( UNM_DMA_BUFFER_ALIGN ) )) -/** Dummy DMA buffer size */ -#define UNM_DUMMY_DMA_SIZE 1024 - /****************************************************************************** * * Register definitions @@ -76,14 +70,19 @@ typedef uint32_t nx_rcode_t; * address by the phantom_crb_access_xxx() methods. */ enum unm_reg_blocks { - UNM_CRB_BLK_PCIE, - UNM_CRB_BLK_CAM, - UNM_CRB_BLK_ROMUSB, - UNM_CRB_BLK_TEST, + UNM_CRB_BLK_PCIE = 0x01, + UNM_CRB_BLK_CAM = 0x22, + UNM_CRB_BLK_ROMUSB = 0x33, + UNM_CRB_BLK_TEST = 0x02, + UNM_CRB_BLK_PEG_0 = 0x11, + UNM_CRB_BLK_PEG_1 = 0x12, + UNM_CRB_BLK_PEG_2 = 0x13, + UNM_CRB_BLK_PEG_3 = 0x14, + UNM_CRB_BLK_PEG_4 = 0x0f, }; -#define UNM_CRB_BASE(blk) ( (blk) << 24 ) -#define UNM_CRB_BLK(reg) ( (reg) >> 24 ) -#define UNM_CRB_OFFSET(reg) ( (reg) & 0x00ffffff ) +#define UNM_CRB_BASE(blk) ( (blk) << 20 ) +#define UNM_CRB_BLK(reg) ( (reg) >> 20 ) +#define UNM_CRB_OFFSET(reg) ( (reg) & 0x000fffff ) #define UNM_CRB_PCIE UNM_CRB_BASE ( UNM_CRB_BLK_PCIE ) #define UNM_PCIE_SEM2_LOCK ( UNM_CRB_PCIE + 0x1c010 ) @@ -101,6 +100,16 @@ enum unm_reg_blocks { #define UNM_CAM_RAM_DMESG_SIG(n) ( UNM_CAM_RAM + 0x0003c + (n) * 0x10 ) #define UNM_CAM_RAM_DMESG_SIG_MAGIC 0xcafebabeUL #define UNM_CAM_RAM_NUM_DMESG_BUFFERS 5 +#define UNM_CAM_RAM_CLP_COMMAND ( UNM_CAM_RAM + 0x000c0 ) +#define UNM_CAM_RAM_CLP_COMMAND_LAST 0x00000080UL +#define UNM_CAM_RAM_CLP_DATA_LO ( UNM_CAM_RAM + 0x000c4 ) +#define UNM_CAM_RAM_CLP_DATA_HI ( UNM_CAM_RAM + 0x000c8 ) +#define UNM_CAM_RAM_CLP_STATUS ( UNM_CAM_RAM + 0x000cc ) +#define UNM_CAM_RAM_CLP_STATUS_START 0x00000001UL +#define UNM_CAM_RAM_CLP_STATUS_DONE 0x00000002UL +#define UNM_CAM_RAM_CLP_STATUS_ERROR 0x0000ff00UL +#define UNM_CAM_RAM_CLP_STATUS_UNINITIALISED 0xffffffffUL +#define UNM_CAM_RAM_BOOT_ENABLE ( UNM_CAM_RAM + 0x000fc ) #define UNM_CAM_RAM_WOL_PORT_MODE ( UNM_CAM_RAM + 0x00198 ) #define UNM_CAM_RAM_MAC_ADDRS ( UNM_CAM_RAM + 0x001c0 ) #define UNM_CAM_RAM_COLD_BOOT ( UNM_CAM_RAM + 0x001fc ) @@ -160,114 +169,24 @@ enum unm_reg_blocks { #define UNM_TEST_RDDATA_LO ( UNM_CRB_TEST + 0x000a8 ) #define UNM_TEST_RDDATA_HI ( UNM_CRB_TEST + 0x000ac ) -/****************************************************************************** - * - * Flash layout - * - */ - -/* Board configuration */ - -#define UNM_BRDCFG_START 0x4000 - -struct unm_board_info { - uint32_t header_version; - uint32_t board_mfg; - uint32_t board_type; - uint32_t board_num; - uint32_t chip_id; - uint32_t chip_minor; - uint32_t chip_major; - uint32_t chip_pkg; - uint32_t chip_lot; - uint32_t port_mask; - uint32_t peg_mask; - uint32_t icache_ok; - uint32_t dcache_ok; - uint32_t casper_ok; - uint32_t mac_addr_lo_0; - uint32_t mac_addr_lo_1; - uint32_t mac_addr_lo_2; - uint32_t mac_addr_lo_3; - uint32_t mn_sync_mode; - uint32_t mn_sync_shift_cclk; - uint32_t mn_sync_shift_mclk; - uint32_t mn_wb_en; - uint32_t mn_crystal_freq; - uint32_t mn_speed; - uint32_t mn_org; - uint32_t mn_depth; - uint32_t mn_ranks_0; - uint32_t mn_ranks_1; - uint32_t mn_rd_latency_0; - uint32_t mn_rd_latency_1; - uint32_t mn_rd_latency_2; - uint32_t mn_rd_latency_3; - uint32_t mn_rd_latency_4; - uint32_t mn_rd_latency_5; - uint32_t mn_rd_latency_6; - uint32_t mn_rd_latency_7; - uint32_t mn_rd_latency_8; - uint32_t mn_dll_val[18]; - uint32_t mn_mode_reg; - uint32_t mn_ext_mode_reg; - uint32_t mn_timing_0; - uint32_t mn_timing_1; - uint32_t mn_timing_2; - uint32_t sn_sync_mode; - uint32_t sn_pt_mode; - uint32_t sn_ecc_en; - uint32_t sn_wb_en; - uint32_t sn_crystal_freq; - uint32_t sn_speed; - uint32_t sn_org; - uint32_t sn_depth; - uint32_t sn_dll_tap; - uint32_t sn_rd_latency; - uint32_t mac_addr_hi_0; - uint32_t mac_addr_hi_1; - uint32_t mac_addr_hi_2; - uint32_t mac_addr_hi_3; - uint32_t magic; - uint32_t mn_rdimm; - uint32_t mn_dll_override; -}; - -#define UNM_BDINFO_VERSION 1 -#define UNM_BRDTYPE_P3_HMEZ 0x0022 -#define UNM_BRDTYPE_P3_10G_CX4_LP 0x0023 -#define UNM_BRDTYPE_P3_4_GB 0x0024 -#define UNM_BRDTYPE_P3_IMEZ 0x0025 -#define UNM_BRDTYPE_P3_10G_SFP_PLUS 0x0026 -#define UNM_BRDTYPE_P3_10000_BASE_T 0x0027 -#define UNM_BRDTYPE_P3_XG_LOM 0x0028 -#define UNM_BRDTYPE_P3_4_GB_MM 0x0029 -#define UNM_BRDTYPE_P3_10G_CX4 0x0031 -#define UNM_BRDTYPE_P3_10G_XFP 0x0032 -#define UNM_BDINFO_MAGIC 0x12345678 +#define UNM_CRB_PEG_0 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_0 ) +#define UNM_PEG_0_HALT_STATUS ( UNM_CRB_PEG_0 + 0x00030 ) +#define UNM_PEG_0_HALT ( UNM_CRB_PEG_0 + 0x0003c ) -/* User defined region */ +#define UNM_CRB_PEG_1 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_1 ) +#define UNM_PEG_1_HALT_STATUS ( UNM_CRB_PEG_1 + 0x00030 ) +#define UNM_PEG_1_HALT ( UNM_CRB_PEG_1 + 0x0003c ) -#define UNM_USER_START 0x3e8000 +#define UNM_CRB_PEG_2 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_2 ) +#define UNM_PEG_2_HALT_STATUS ( UNM_CRB_PEG_2 + 0x00030 ) +#define UNM_PEG_2_HALT ( UNM_CRB_PEG_2 + 0x0003c ) -#define UNM_FLASH_NUM_PORTS 4 -#define UNM_FLASH_NUM_MAC_PER_PORT 32 +#define UNM_CRB_PEG_3 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_3 ) +#define UNM_PEG_3_HALT_STATUS ( UNM_CRB_PEG_3 + 0x00030 ) +#define UNM_PEG_3_HALT ( UNM_CRB_PEG_3 + 0x0003c ) -struct unm_user_info { - uint8_t flash_md5[16 * 64]; - uint32_t bootld_version; - uint32_t bootld_size; - uint32_t image_version; - uint32_t image_size; - uint32_t primary_status; - uint32_t secondary_present; - /* MAC address , 4 ports, 32 address per port */ - uint64_t mac_addr[UNM_FLASH_NUM_PORTS * UNM_FLASH_NUM_MAC_PER_PORT]; - uint32_t sub_sys_id; - uint8_t serial_num[32]; - uint32_t bios_version; - uint32_t pxe_enable; - uint32_t vlan_tag[UNM_FLASH_NUM_PORTS]; -}; +#define UNM_CRB_PEG_4 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_4 ) +#define UNM_PEG_4_HALT_STATUS ( UNM_CRB_PEG_4 + 0x00030 ) +#define UNM_PEG_4_HALT ( UNM_CRB_PEG_4 + 0x0003c ) #endif /* _PHANTOM_H */ diff --git a/gpxe/src/drivers/net/pnic.c b/gpxe/src/drivers/net/pnic.c index c7f08670..3a4af967 100644 --- a/gpxe/src/drivers/net/pnic.c +++ b/gpxe/src/drivers/net/pnic.c @@ -14,7 +14,7 @@ Bochs Pseudo NIC driver for Etherboot #include #include -#include +#include #include #include #include diff --git a/gpxe/src/drivers/net/r8169.c b/gpxe/src/drivers/net/r8169.c index 885f054a..0554058e 100644 --- a/gpxe/src/drivers/net/r8169.c +++ b/gpxe/src/drivers/net/r8169.c @@ -1,1159 +1,434 @@ -/************************************************************************** -* r8169.c: Etherboot device driver for the RealTek RTL-8169 Gigabit -* Written 2003 by Timothy Legge -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -* -* Portions of this code based on: -* r8169.c: A RealTek RTL-8169 Gigabit Ethernet driver -* for Linux kernel 2.4.x. -* -* Written 2002 ShuChen -* See Linux Driver for full information -* -* Linux Driver Versions: -* 1.27a, 10.02.2002 -* RTL8169_VERSION "2.2" <2004/08/09> -* -* Thanks to: -* Jean Chen of RealTek Semiconductor Corp. for -* providing the evaluation NIC used to develop -* this driver. RealTek's support for Etherboot -* is appreciated. -* -* REVISION HISTORY: -* ================ -* -* v1.0 11-26-2003 timlegge Initial port of Linux driver -* v1.5 01-17-2004 timlegge Initial driver output cleanup -* v1.6 03-27-2004 timlegge Additional Cleanup -* v1.7 11-22-2005 timlegge Update to RealTek Driver Version 2.2 -* -* 03-19-2008 Hilko Bengen Cleanups and fixes for newer cards -* (successfully tested with 8110SC-d onboard NIC) -* -* Indent Options: indent -kr -i8 -***************************************************************************/ - -#include "etherboot.h" -#include "nic.h" -#include +/* + * Copyright (c) 2008 Marty Connor + * 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 + * Copyright (c) 2003 - 2007 Francois Romieu + * Copyright (c) a lot of people too. Please respect their work. + */ + +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include #include +#include +#include +#include -#define drv_version "v1.7+" -#define drv_date "03-19-2008" - -#define HZ 1000 - -static u32 ioaddr; - -/* Condensed operations for readability. */ -#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) -#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - -#undef RTL8169_DEBUG -#undef RTL8169_JUMBO_FRAME_SUPPORT -#undef RTL8169_HW_FLOW_CONTROL_SUPPORT - - -#undef RTL8169_IOCTL_SUPPORT -#undef RTL8169_DYNAMIC_CONTROL -#define RTL8169_USE_IO - -#if 0 -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 20; -#endif - -#if 0 -/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). - The RTL chips use a 64 element hash table based on the Ethernet CRC. */ -static int multicast_filter_limit = 32; -#endif - -/* MAC address length*/ -#define MAC_ADDR_LEN 6 - -/* max supported gigabit ethernet frame size -- must be at least (dev->mtu+14+4).*/ -#define MAX_ETH_FRAME_SIZE 1536 - -#define TX_FIFO_THRESH 256 /* In bytes */ - -#define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */ -#define RX_DMA_BURST 7 /* Maximum PCI burst, '6' is 1024 */ -#define TX_DMA_BURST 7 /* Maximum PCI burst, '6' is 1024 */ -#define ETTh 0x3F /* 0x3F means NO threshold */ - -#define EarlyTxThld 0x3F /* 0x3F means NO early transmit */ -#define RxPacketMaxSize 0x0800 /* Maximum size supported is 16K-1 */ -#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ - -#define NUM_TX_DESC 1 /* Number of Tx descriptor registers */ -#define NUM_RX_DESC 4 /* Number of Rx descriptor registers */ -#define RX_BUF_SIZE 1536 /* Rx Buffer size */ - -#define RTL_MIN_IO_SIZE 0x80 -#define TX_TIMEOUT (6*HZ) - -#define RTL8169_TIMER_EXPIRE_TIME 100 //100 - -#define ETH_HDR_LEN 14 -#define DEFAULT_MTU 1500 -#define DEFAULT_RX_BUF_LEN 1536 - - -#ifdef RTL8169_JUMBO_FRAME_SUPPORT -#define MAX_JUMBO_FRAME_MTU ( 10000 ) -#define MAX_RX_SKBDATA_SIZE ( MAX_JUMBO_FRAME_MTU + ETH_HDR_LEN ) -#else -#define MAX_RX_SKBDATA_SIZE 1600 -#endif //end #ifdef RTL8169_JUMBO_FRAME_SUPPORT - -#ifdef RTL8169_USE_IO -#define RTL_W8(reg, val8) outb ((val8), ioaddr + (reg)) -#define RTL_W16(reg, val16) outw ((val16), ioaddr + (reg)) -#define RTL_W32(reg, val32) outl ((val32), ioaddr + (reg)) -#define RTL_R8(reg) inb (ioaddr + (reg)) -#define RTL_R16(reg) inw (ioaddr + (reg)) -#define RTL_R32(reg) ((unsigned long) inl (ioaddr + (reg))) -#else -/* write/read MMIO register */ -#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg)) -#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg)) -#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg)) -#define RTL_R8(reg) readb (ioaddr + (reg)) -#define RTL_R16(reg) readw (ioaddr + (reg)) -#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg))) -#endif - -enum mac_version { - RTL_GIGA_MAC_VER_01 = 0x01, // 8169 - RTL_GIGA_MAC_VER_02 = 0x02, // 8169S - RTL_GIGA_MAC_VER_03 = 0x03, // 8110S - RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB - RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd - RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe - RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb - RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be - RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb - RTL_GIGA_MAC_VER_14 = 0x0e, // 8101 ? - RTL_GIGA_MAC_VER_15 = 0x0f, // 8101 ? - RTL_GIGA_MAC_VER_16 = 0x11, // 8101Ec - RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf - RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP - RTL_GIGA_MAC_VER_19 = 0x13, // 8168C - RTL_GIGA_MAC_VER_20 = 0x14 // 8168C -}; - -enum cfg_version { - RTL_CFG_0 = 0x00, - RTL_CFG_1, - RTL_CFG_2 -}; - -static struct { - const char *name; - u8 mac_version; /* depend on RTL8169 docs */ - u32 RxConfigMask; /* should clear the bits supported by this chip */ -} rtl_chip_info[] = { - {"RTL8169", RTL_GIGA_MAC_VER_01, 0xff7e1880}, // 8169 - {"RTL8169s", RTL_GIGA_MAC_VER_02, 0xff7e1880}, // 8169S - {"RTL8110s", RTL_GIGA_MAC_VER_03, 0xff7e1880}, // 8110S - {"RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880}, // 8169SB - {"RTL8169sc/8110sc-d",RTL_GIGA_MAC_VER_05, 0xff7e1880}, // 8110SCd - {"RTL8169sc/8110sc-e",RTL_GIGA_MAC_VER_06, 0xff7e1880}, // 8110SCe - {"RTL8168b/8111b", RTL_GIGA_MAC_VER_11, 0xff7e1880}, // PCI-E - {"RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880}, // PCI-E - {"RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880}, // PCI-E 8139 - {"RTL8100e", RTL_GIGA_MAC_VER_14, 0xff7e1880}, // PCI-E 8139 - {"RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880}, // PCI-E 8139 - {"RTL8168b/8111b", RTL_GIGA_MAC_VER_17, 0xff7e1880}, // PCI-E - {"RTL8101e", RTL_GIGA_MAC_VER_16, 0xff7e1880}, // PCI-E - {"RTL8168cp/8111cp", RTL_GIGA_MAC_VER_18, 0xff7e1880}, // PCI-E - {"RTL8168c/8111c", RTL_GIGA_MAC_VER_19, 0xff7e1880}, // PCI-E - {"RTL8168c/8111c", RTL_GIGA_MAC_VER_20, 0xff7e1880}, // PCI-E -}; - -enum RTL8169_registers { - MAC0 = 0x0, /* Ethernet hardware address. */ - MAR0 = 0x8, /* Multicast filter. */ - TxDescAddrLow = 0x20, - TxDescAddrHigh = 0x24, - TxHDescStartAddr = 0x28, - FLASH = 0x30, - ERSR = 0x36, - ChipCmd = 0x37, - TxPoll = 0x38, - IntrMask = 0x3C, - IntrStatus = 0x3E, - TxConfig = 0x40, - RxConfig = 0x44, - RxMissed = 0x4C, - Cfg9346 = 0x50, - Config0 = 0x51, - Config1 = 0x52, - Config2 = 0x53, - Config3 = 0x54, - Config4 = 0x55, - Config5 = 0x56, - MultiIntr = 0x5C, - PHYAR = 0x60, - TBICSR = 0x64, - TBI_ANAR = 0x68, - TBI_LPAR = 0x6A, - PHYstatus = 0x6C, - RxMaxSize = 0xda, - CPlusCmd = 0xe0, - IntrMitigate = 0xe2, - RxDescAddrLow = 0xe4, - RxDescAddrHigh = 0xe8, - ETThReg = 0xEC, - FuncEvent = 0xF0, - FuncEventMask = 0xF4, - FuncPresetState = 0xF8, - FuncForceEvent = 0xFC, -}; - -enum RTL8169_register_content { - /*InterruptStatusBits */ - SYSErr = 0x8000, - PCSTimeout = 0x4000, - SWInt = 0x0100, - TxDescUnavail = 0x80, - RxFIFOOver = 0x40, - LinkChg = 0x20, - RxOverflow = 0x10, - TxErr = 0x08, - TxOK = 0x04, - RxErr = 0x02, - RxOK = 0x01, - - /*RxStatusDesc */ - RxRES = 0x00200000, - RxCRC = 0x00080000, - RxRUNT = 0x00100000, - RxRWT = 0x00400000, - - /*ChipCmdBits */ - CmdReset = 0x10, - CmdRxEnb = 0x08, - CmdTxEnb = 0x04, - RxBufEmpty = 0x01, - - /*Cfg9346Bits */ - Cfg9346_Lock = 0x00, - Cfg9346_Unlock = 0xC0, - - /*rx_mode_bits */ - AcceptErr = 0x20, - AcceptRunt = 0x10, - AcceptBroadcast = 0x08, - AcceptMulticast = 0x04, - AcceptMyPhys = 0x02, - AcceptAllPhys = 0x01, - - /*RxConfigBits */ - RxCfgFIFOShift = 13, - RxCfgDMAShift = 8, - - /*TxConfigBits */ - TxInterFrameGapShift = 24, - TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ - - /*rtl8169_PHYstatus */ - TBI_Enable = 0x80, - TxFlowCtrl = 0x40, - RxFlowCtrl = 0x20, - _1000bpsF = 0x10, - _100bps = 0x08, - _10bps = 0x04, - LinkStatus = 0x02, - FullDup = 0x01, - - /*GIGABIT_PHY_registers */ - PHY_CTRL_REG = 0, - PHY_STAT_REG = 1, - PHY_AUTO_NEGO_REG = 4, - PHY_1000_CTRL_REG = 9, - - /*GIGABIT_PHY_REG_BIT */ - PHY_Restart_Auto_Nego = 0x0200, - PHY_Enable_Auto_Nego = 0x1000, - - /* PHY_STAT_REG = 1; */ - PHY_Auto_Neco_Comp = 0x0020, - - /* PHY_AUTO_NEGO_REG = 4; */ - PHY_Cap_10_Half = 0x0020, - PHY_Cap_10_Full = 0x0040, - PHY_Cap_100_Half = 0x0080, - PHY_Cap_100_Full = 0x0100, - - /* PHY_1000_CTRL_REG = 9; */ - PHY_Cap_1000_Full = 0x0200, - PHY_Cap_1000_Half = 0x0100, - - PHY_Cap_PAUSE = 0x0400, - PHY_Cap_ASYM_PAUSE = 0x0800, - - PHY_Cap_Null = 0x0, - - /*_MediaType*/ - _10_Half = 0x01, - _10_Full = 0x02, - _100_Half = 0x04, - _100_Full = 0x08, - _1000_Full = 0x10, - - /*_TBICSRBit*/ - TBILinkOK = 0x02000000, -}; - -enum _DescStatusBit { - OWNbit = 0x80000000, - EORbit = 0x40000000, - FSbit = 0x20000000, - LSbit = 0x10000000, -}; - -struct TxDesc { - u32 status; - u32 vlan_tag; - u32 buf_addr; - u32 buf_Haddr; -}; - -struct RxDesc { - u32 status; - u32 vlan_tag; - u32 buf_addr; - u32 buf_Haddr; -}; +#include "r8169.h" -/* The descriptors for this card are required to be aligned on 256 - * byte boundaries. As the align attribute does not do more than 16 - * bytes of alignment it requires some extra steps. Add 256 to the - * size of the array and the init_ring adjusts the alignment. - * - * UPDATE: This is no longer true; we can request arbitrary alignment. - */ +/*** Low level hardware routines ***/ -/* Define the TX and RX Descriptors and Buffers */ -#define __align_256 __attribute__ (( aligned ( 256 ) )) -struct { - struct TxDesc tx_ring[NUM_TX_DESC] __align_256; - unsigned char txb[NUM_TX_DESC * RX_BUF_SIZE]; - struct RxDesc rx_ring[NUM_RX_DESC] __align_256; - unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE]; -} *r8169_bufs; -#define tx_ring r8169_bufs->tx_ring -#define rx_ring r8169_bufs->rx_ring -#define txb r8169_bufs->txb -#define rxb r8169_bufs->rxb - -static struct rtl8169_private { - void *mmio_addr; /* memory map physical address */ - int chipset; - int pcfg; - int mac_version; - unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ - unsigned long cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ - struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */ - struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */ - unsigned char *RxBufferRing[NUM_RX_DESC]; /* Index of Rx Buffer array */ - unsigned char *Tx_skbuff[NUM_TX_DESC]; -} tpx; - -static const u16 rtl8169_intr_mask = - LinkChg | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK; -static const unsigned int rtl8169_rx_config = - (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift) | - 0x0000000E; - -static void rtl8169_hw_phy_config(struct nic *nic __unused); -//static void rtl8169_hw_phy_reset(struct net_device *dev); - -#define RTL8169_WRITE_GMII_REG_BIT( ioaddr, reg, bitnum, bitval )\ -{ \ - int val; \ - if( bitval == 1 ){ val = ( RTL8169_READ_GMII_REG( ioaddr, reg ) | (bitval< 0; i--) { - // Check if the RTL8169 has completed writing to the specified MII register - if (!(RTL_R32(PHYAR) & 0x80000000)) { + for (i = 20; i > 0; i--) { + /* + * Check if the RTL8169 has completed writing to the specified + * MII register. + */ + if (!(RTL_R32(PHYAR) & 0x80000000)) break; - } else { - udelay(100); - } // end of if( ! (RTL_R32(PHYAR)&0x80000000) ) - } // end of for() loop + udelay(25); + } } -//================================================================= -static int RTL8169_READ_GMII_REG(unsigned long ioaddr, int RegAddr) +static int mdio_read(void *ioaddr, int reg_addr) { int i, value = -1; - RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16); - udelay(1000); + DBGP ( "mdio_read\n" ); + + RTL_W32(PHYAR, 0x0 | (reg_addr & 0x1f) << 16); - for (i = 2000; i > 0; i--) { - // Check if the RTL8169 has completed retrieving data from the specified MII register + for (i = 20; i > 0; i--) { + /* + * Check if the RTL8169 has completed retrieving data from + * the specified MII register. + */ if (RTL_R32(PHYAR) & 0x80000000) { - value = (int) (RTL_R32(PHYAR) & 0xFFFF); + value = RTL_R32(PHYAR) & 0xffff; break; - } else { - udelay(100); - } // end of if( RTL_R32(PHYAR) & 0x80000000 ) - } // end of for() loop + } + udelay(25); + } return value; } +static void mdio_patch(void *ioaddr, int reg_addr, int value) +{ + DBGP ( "mdio_patch\n" ); + + mdio_write(ioaddr, reg_addr, mdio_read(ioaddr, reg_addr) | value); +} -#if 0 -static void mdio_write(int RegAddr, int value) +static void rtl_ephy_write(void *ioaddr, int reg_addr, int value) { - int i; + unsigned int i; + + DBGP ( "rtl_ephy_write\n" ); - RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value); - udelay(1000); + RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) | + (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT); - for (i = 2000; i > 0; i--) { - /* Check if the RTL8169 has completed writing to the specified MII register */ - if (!(RTL_R32(PHYAR) & 0x80000000)) { + for (i = 0; i < 100; i++) { + if (!(RTL_R32(EPHYAR) & EPHYAR_FLAG)) break; - } else { - udelay(100); - } + udelay(10); } } -static int mdio_read(int RegAddr) +static u16 rtl_ephy_read(void *ioaddr, int reg_addr) { - int i, value = -1; + u16 value = 0xffff; + unsigned int i; - RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16); - udelay(1000); + DBGP ( "rtl_ephy_read\n" ); - for (i = 2000; i > 0; i--) { - /* Check if the RTL8169 has completed retrieving data from the specified MII register */ - if (RTL_R32(PHYAR) & 0x80000000) { - value = (int) (RTL_R32(PHYAR) & 0xFFFF); + RTL_W32(EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT); + + for (i = 0; i < 100; i++) { + if (RTL_R32(EPHYAR) & EPHYAR_FLAG) { + value = RTL_R32(EPHYAR) & EPHYAR_DATA_MASK; break; - } else { - udelay(100); } + udelay(10); } + return value; } -#endif -static void rtl8169_get_mac_version( struct rtl8169_private *tp, - u32 ioaddr ) +static void rtl_csi_write(void *ioaddr, int addr, int value) { - /* - * The driver currently handles the 8168Bf and the 8168Be identically - * but they can be identified more specifically through the test below - * if needed: - * - * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be - * - * Same thing for the 8101Eb and the 8101Ec: - * - * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec - */ - const struct { - u32 mask; - u32 val; - int mac_version; - } mac_info[] = { - /* 8168B family. */ - { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_18 }, - { 0x7cf00000, 0x3c000000, RTL_GIGA_MAC_VER_19 }, - { 0x7cf00000, 0x3c200000, RTL_GIGA_MAC_VER_20 }, - { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_20 }, - /* 8168B family. */ - { 0x7cf00000, 0x38000000, RTL_GIGA_MAC_VER_12 }, - { 0x7cf00000, 0x38500000, RTL_GIGA_MAC_VER_17 }, - { 0x7c800000, 0x38000000, RTL_GIGA_MAC_VER_17 }, - { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 }, - /* 8101 family. */ - { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 }, - { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 }, - { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 }, - /* FIXME: where did these entries come from ? -- FR */ - { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 }, - { 0xfc800000, 0x30800000, RTL_GIGA_MAC_VER_14 }, - /* 8110 family. */ - { 0xfc800000, 0x98000000, RTL_GIGA_MAC_VER_06 }, - { 0xfc800000, 0x18000000, RTL_GIGA_MAC_VER_05 }, - { 0xfc800000, 0x10000000, RTL_GIGA_MAC_VER_04 }, - { 0xfc800000, 0x04000000, RTL_GIGA_MAC_VER_03 }, - { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 }, - { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 }, - { 0x00000000, 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */ - }, *p = mac_info; - - unsigned long rv; + unsigned int i; - rv = (RTL_R32(TxConfig)); + DBGP ( "rtl_csi_write\n" ); - while ((rv & p->mask) != p->val) - p++; - tp->mac_version = p->mac_version; + RTL_W32(CSIDR, value); + RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) | + CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT); - if (p->mask == 0x00000000) { - DBG("unknown MAC (%08lx)\n", rv); + for (i = 0; i < 100; i++) { + if (!(RTL_R32(CSIAR) & CSIAR_FLAG)) + break; + udelay(10); } } -#define IORESOURCE_MEM 0x00000200 - -static int rtl8169_init_board(struct pci_device *pdev) +static u32 rtl_csi_read(void *ioaddr, int addr) { - int i; -// unsigned long mmio_end, mmio_flags - unsigned long mmio_start, mmio_len; - struct rtl8169_private *tp = &tpx; - - adjust_pci_device(pdev); - - mmio_start = pci_bar_start(pdev, PCI_BASE_ADDRESS_1); -// mmio_end = pci_resource_end (pdev, 1); -// mmio_flags = pci_resource_flags (pdev, PCI_BASE_ADDRESS_1); - mmio_len = pci_bar_size(pdev, PCI_BASE_ADDRESS_1); - - // make sure PCI base addr 1 is MMIO -// if (!(mmio_flags & IORESOURCE_MEM)) { -// printf ("region #1 not an MMIO resource, aborting\n"); -// return 0; -// } - - // check for weird/broken PCI region reporting - if (mmio_len < RTL_MIN_IO_SIZE) { - printf("Invalid PCI region size(s), aborting\n"); - return 0; - } -#ifdef RTL8169_USE_IO - ioaddr = pci_bar_start(pdev, PCI_BASE_ADDRESS_0); -#else - // ioremap MMIO region - ioaddr = (unsigned long) ioremap(mmio_start, mmio_len); - if (ioaddr == 0) { - printk("cannot remap MMIO, aborting\n"); - return 0; - } -#endif + u32 value = ~0x00; + unsigned int i; - tp->mmio_addr = (void*)ioaddr; - /* Soft reset the chip. */ - RTL_W8(ChipCmd, CmdReset); + DBGP ( "rtl_csi_read\n" ); - /* Check that the chip has finished the reset. */ - for (i = 1000; i > 0; i--) - if ((RTL_R8(ChipCmd) & CmdReset) == 0) - break; - else - udelay(10); + RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) | + CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT); - /* Identify chip attached to board */ - rtl8169_get_mac_version( tp, ioaddr ); - - // rtl8169_print_mac_version(tp); - - { - unsigned char val8 = - (unsigned char) (RTL8169_READ_GMII_REG(ioaddr, 3) & - 0x000f); - if (val8 == 0x00) { - tp->pcfg = RTL_CFG_0; - } else if (val8 == 0x01) { - tp->pcfg = RTL_CFG_1; - } else if (val8 == 0x02) { - tp->pcfg = RTL_CFG_2; - } else { - tp->pcfg = RTL_CFG_2; + for (i = 0; i < 100; i++) { + if (RTL_R32(CSIAR) & CSIAR_FLAG) { + value = RTL_R32(CSIDR); + break; } + udelay(10); } - /* identify chip attached to board */ - - for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--) - if (tp->mac_version == rtl_chip_info[i].mac_version) { - tp->chipset = i; - goto match; - } - /* if unknown chip, assume array element #0, original RTL-8169 in this case */ - DBG ( "PCI device: unknown chip version, assuming RTL-8169\n" ); - DBG ( "PCI device: TxConfig = %#lX\n", ( unsigned long ) RTL_R32 ( TxConfig ) ); + return value; +} - tp->chipset = 0; - return 1; +static void rtl8169_irq_mask_and_ack(void *ioaddr) +{ + DBGP ( "rtl8169_irq_mask_and_ack\n" ); - match: - return 0; + RTL_W16(IntrMask, 0x0000); + RTL_W16(IntrStatus, 0xffff); } -/************************************************************************** -IRQ - Wait for a frame -***************************************************************************/ -static void r8169_irq(struct nic *nic __unused, irq_action_t action) +static unsigned int rtl8169_tbi_reset_pending(void *ioaddr) { - int intr_status = 0; - int interested = RxOverflow | RxFIFOOver | RxErr | RxOK; + DBGP ( "rtl8169_tbi_reset_pending\n" ); - switch (action) { - case DISABLE: - case ENABLE: - intr_status = RTL_R16(IntrStatus); - /* h/w no longer present (hotplug?) or major error, - bail */ - if (intr_status == 0xFFFF) - break; - - intr_status = intr_status & ~interested; - if (action == ENABLE) - intr_status = intr_status | interested; - RTL_W16(IntrMask, intr_status); - break; - case FORCE: - RTL_W8(TxPoll, (RTL_R8(TxPoll) | 0x01)); - break; - } + return RTL_R32(TBICSR) & TBIReset; } -/************************************************************************** -POLL - Wait for a frame -***************************************************************************/ -static int r8169_poll(struct nic *nic, int retrieve) -{ - /* return true if there's an ethernet packet ready to read */ - /* nic->packet should contain data on return */ - /* nic->packetlen should contain length of data */ - int cur_rx; - unsigned int intr_status = 0; - struct rtl8169_private *tp = &tpx; - - cur_rx = tp->cur_rx; - if ((tp->RxDescArray[cur_rx].status & OWNbit) == 0) { - /* There is a packet ready */ - DBG("r8169_poll(): packet ready\n"); - if (!retrieve) - return 1; - intr_status = RTL_R16(IntrStatus); - /* h/w no longer present (hotplug?) or major error, - bail */ - if (intr_status == 0xFFFF) { - DBG("r8169_poll(): unknown error\n"); - return 0; - } - RTL_W16(IntrStatus, intr_status & - ~(RxFIFOOver | RxOverflow | RxOK)); - - if (!(tp->RxDescArray[cur_rx].status & RxRES)) { - nic->packetlen = (int) (tp->RxDescArray[cur_rx]. - status & 0x00001FFF) - 4; - memcpy(nic->packet, tp->RxBufferRing[cur_rx], - nic->packetlen); - if (cur_rx == NUM_RX_DESC - 1) - tp->RxDescArray[cur_rx].status = - (OWNbit | EORbit) + RX_BUF_SIZE; - else - tp->RxDescArray[cur_rx].status = - OWNbit + RX_BUF_SIZE; - tp->RxDescArray[cur_rx].buf_addr = - virt_to_bus(tp->RxBufferRing[cur_rx]); - tp->RxDescArray[cur_rx].buf_Haddr = 0; - } else - printf("Error Rx"); - /* FIXME: shouldn't I reset the status on an error */ - cur_rx = (cur_rx + 1) % NUM_RX_DESC; - tp->cur_rx = cur_rx; - RTL_W16(IntrStatus, intr_status & - (RxFIFOOver | RxOverflow | RxOK)); - - return 1; +static unsigned int rtl8169_xmii_reset_pending(void *ioaddr) +{ + DBGP ( "rtl8169_xmii_reset_pending\n" ); - } - tp->cur_rx = cur_rx; - /* FIXME: There is no reason to do this as cur_rx did not change */ - - return (0); /* initially as this is called to flush the input */ - -} - -/************************************************************************** -TRANSMIT - Transmit a frame -***************************************************************************/ -static void r8169_transmit(struct nic *nic, const char *d, /* Destination */ - unsigned int t, /* Type */ - unsigned int s, /* size */ - const char *p) -{ /* Packet */ - /* send the packet to destination */ - - u16 nstype; - u32 to; - u8 *ptxb; - struct rtl8169_private *tp = &tpx; - int entry = tp->cur_tx % NUM_TX_DESC; - - /* point to the current txb incase multiple tx_rings are used */ - ptxb = tp->Tx_skbuff[entry * MAX_ETH_FRAME_SIZE]; - memcpy(ptxb, d, ETH_ALEN); - memcpy(ptxb + ETH_ALEN, nic->node_addr, ETH_ALEN); - nstype = htons((u16) t); - memcpy(ptxb + 2 * ETH_ALEN, (u8 *) & nstype, 2); - memcpy(ptxb + ETH_HLEN, p, s); - s += ETH_HLEN; - s &= 0x0FFF; - while (s < ETH_ZLEN) - ptxb[s++] = '\0'; - - tp->TxDescArray[entry].buf_addr = virt_to_bus(ptxb); - tp->TxDescArray[entry].buf_Haddr = 0; - if (entry != (NUM_TX_DESC - 1)) - tp->TxDescArray[entry].status = - (OWNbit | FSbit | LSbit) | ((s > ETH_ZLEN) ? s : - ETH_ZLEN); - else - tp->TxDescArray[entry].status = - (OWNbit | EORbit | FSbit | LSbit) | ((s > ETH_ZLEN) ? s - : ETH_ZLEN); - RTL_W8(TxPoll, 0x40); /* set polling bit */ - - tp->cur_tx++; - to = currticks() + TX_TIMEOUT; - while ((tp->TxDescArray[entry].status & OWNbit) && (currticks() < to)); /* wait */ - - if (currticks() >= to) { - printf("TX Time Out"); - } + return mdio_read(ioaddr, MII_BMCR) & BMCR_RESET; } -static void rtl8169_set_rx_mode(struct nic *nic __unused) +static unsigned int rtl8169_tbi_link_ok(void *ioaddr) { - u32 mc_filter[2]; /* Multicast hash filter */ - int rx_mode; - u32 tmp = 0; - struct rtl8169_private *tp = &tpx; + DBGP ( "rtl8169_tbi_link_ok\n" ); - /* IFF_ALLMULTI */ - /* Too many to filter perfectly -- accept all multicasts. */ - rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; - mc_filter[1] = mc_filter[0] = 0xffffffff; + return RTL_R32(TBICSR) & TBILinkOk; +} - tmp = - rtl8169_rx_config | rx_mode | (RTL_R32(RxConfig) & - rtl_chip_info[tp->chipset]. - RxConfigMask); +static unsigned int rtl8169_xmii_link_ok(void *ioaddr) +{ + DBGP ( "rtl8169_xmii_link_ok\n" ); - RTL_W32(RxConfig, tmp); - RTL_W32(MAR0 + 0, mc_filter[0]); - RTL_W32(MAR0 + 4, mc_filter[1]); + return RTL_R8(PHYstatus) & LinkStatus; } -static void rtl8169_hw_start(struct nic *nic) + +static void rtl8169_tbi_reset_enable(void *ioaddr) { - u32 i; - struct rtl8169_private *tp = &tpx; + DBGP ( "rtl8169_tbi_reset_enable\n" ); - /* Soft reset the chip. */ - RTL_W8(ChipCmd, CmdReset); + RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset); +} - /* Check that the chip has finished the reset. */ - for (i = 1000; i > 0; i--) { - if ((RTL_R8(ChipCmd) & CmdReset) == 0) - break; - else - udelay(10); - } +static void rtl8169_xmii_reset_enable(void *ioaddr) +{ + unsigned int val; - RTL_W8(Cfg9346, Cfg9346_Unlock); - RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); - RTL_W8(ETThReg, ETTh); + DBGP ( "rtl8169_xmii_reset_enable\n" ); - /* For gigabit rtl8169 */ - RTL_W16(RxMaxSize, RxPacketMaxSize); + val = mdio_read(ioaddr, MII_BMCR) | BMCR_RESET; + mdio_write(ioaddr, MII_BMCR, val & 0xffff); +} - /* Set Rx Config register */ - i = rtl8169_rx_config | (RTL_R32(RxConfig) & - rtl_chip_info[tp->chipset].RxConfigMask); - RTL_W32(RxConfig, i); +static int rtl8169_set_speed_tbi(struct net_device *dev, + u8 autoneg, u16 speed, u8 duplex) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + int ret = 0; + u32 reg; + + DBGP ( "rtl8169_set_speed_tbi\n" ); + + reg = RTL_R32(TBICSR); + if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) && + (duplex == DUPLEX_FULL)) { + RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart)); + } else if (autoneg == AUTONEG_ENABLE) + RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart); + else { + DBG ( "incorrect speed setting refused in TBI mode\n" ); + ret = -EOPNOTSUPP; + } + return ret; +} - /* Set DMA burst size and Interframe Gap Time */ - RTL_W32(TxConfig, - (TX_DMA_BURST << TxDMAShift) | (InterFrameGap << - TxInterFrameGapShift)); +static int rtl8169_set_speed_xmii(struct net_device *dev, + u8 autoneg, u16 speed, u8 duplex) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + int auto_nego, giga_ctrl; + DBGP ( "rtl8169_set_speed_xmii\n" ); - RTL_W16(CPlusCmd, RTL_R16(CPlusCmd)); + auto_nego = mdio_read(ioaddr, MII_ADVERTISE); + auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL | + ADVERTISE_100HALF | ADVERTISE_100FULL); + giga_ctrl = mdio_read(ioaddr, MII_CTRL1000); + giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); - if (tp->mac_version == RTL_GIGA_MAC_VER_02 || tp->mac_version == RTL_GIGA_MAC_VER_03) { - RTL_W16(CPlusCmd, - (RTL_R16(CPlusCmd) | (1 << 14) | (1 << 3))); - DBG - ("Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14\n"); + if (autoneg == AUTONEG_ENABLE) { + auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL | + ADVERTISE_100HALF | ADVERTISE_100FULL); + giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; } else { - RTL_W16(CPlusCmd, (RTL_R16(CPlusCmd) | (1 << 3))); - DBG("Set MAC Reg C+CR Offset 0xE0: bit-3.\n"); + if (speed == SPEED_10) + auto_nego |= ADVERTISE_10HALF | ADVERTISE_10FULL; + else if (speed == SPEED_100) + auto_nego |= ADVERTISE_100HALF | ADVERTISE_100FULL; + else if (speed == SPEED_1000) + giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; + + if (duplex == DUPLEX_HALF) + auto_nego &= ~(ADVERTISE_10FULL | ADVERTISE_100FULL); + + if (duplex == DUPLEX_FULL) + auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_100HALF); + + /* This tweak comes straight from Realtek's driver. */ + if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) && + ((tp->mac_version == RTL_GIGA_MAC_VER_13) || + (tp->mac_version == RTL_GIGA_MAC_VER_16))) { + auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA; + } } - { - //RTL_W16(IntrMitigate, 0x1517); - //RTL_W16(IntrMitigate, 0x152a); - //RTL_W16(IntrMitigate, 0x282a); - RTL_W16(IntrMitigate, 0x0000); + /* The 8100e/8101e/8102e do Fast Ethernet only. */ + if ((tp->mac_version == RTL_GIGA_MAC_VER_07) || + (tp->mac_version == RTL_GIGA_MAC_VER_08) || + (tp->mac_version == RTL_GIGA_MAC_VER_09) || + (tp->mac_version == RTL_GIGA_MAC_VER_10) || + (tp->mac_version == RTL_GIGA_MAC_VER_13) || + (tp->mac_version == RTL_GIGA_MAC_VER_14) || + (tp->mac_version == RTL_GIGA_MAC_VER_15) || + (tp->mac_version == RTL_GIGA_MAC_VER_16)) { + if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF))) { + DBG ( "PHY does not support 1000Mbps.\n" ); + } + giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); } - tp->cur_rx = 0; - - RTL_W32(TxDescAddrLow, virt_to_le32desc(tp->TxDescArray)); - RTL_W32(TxDescAddrHigh, virt_to_le32desc(NULL)); - RTL_W32(RxDescAddrLow, virt_to_le32desc(tp->RxDescArray)); - RTL_W32(RxDescAddrHigh, virt_to_le32desc(NULL)); - RTL_W8(Cfg9346, Cfg9346_Lock); - udelay(10); - - RTL_W32(RxMissed, 0); - - rtl8169_set_rx_mode(nic); - - /* no early-rx interrupts */ - RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000); + auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; + + if ((tp->mac_version == RTL_GIGA_MAC_VER_11) || + (tp->mac_version == RTL_GIGA_MAC_VER_12) || + (tp->mac_version >= RTL_GIGA_MAC_VER_17)) { + /* + * Wake up the PHY. + * Vendor specific (0x1f) and reserved (0x0e) MII registers. + */ + mdio_write(ioaddr, 0x1f, 0x0000); + mdio_write(ioaddr, 0x0e, 0x0000); + } - RTL_W16(IntrMask, rtl8169_intr_mask); + tp->phy_auto_nego_reg = auto_nego; + tp->phy_1000_ctrl_reg = giga_ctrl; + mdio_write(ioaddr, MII_ADVERTISE, auto_nego); + mdio_write(ioaddr, MII_CTRL1000, giga_ctrl); + mdio_write(ioaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); + return 0; } -static void rtl8169_init_ring(struct nic *nic __unused) +static int rtl8169_set_speed(struct net_device *dev, + u8 autoneg, u16 speed, u8 duplex) { - int i; - struct rtl8169_private *tp = &tpx; + struct rtl8169_private *tp = netdev_priv(dev); + int ret; - tp->cur_rx = 0; - tp->cur_tx = 0; - memset(tp->TxDescArray, 0x0, NUM_TX_DESC * sizeof(struct TxDesc)); - memset(tp->RxDescArray, 0x0, NUM_RX_DESC * sizeof(struct RxDesc)); + DBGP ( "rtl8169_set_speed\n" ); - for (i = 0; i < NUM_TX_DESC; i++) { - tp->Tx_skbuff[i] = &txb[i]; - } + ret = tp->set_speed(dev, autoneg, speed, duplex); - for (i = 0; i < NUM_RX_DESC; i++) { - if (i == (NUM_RX_DESC - 1)) - tp->RxDescArray[i].status = - (OWNbit | EORbit) | RX_BUF_SIZE; - else - tp->RxDescArray[i].status = OWNbit | RX_BUF_SIZE; - - tp->RxBufferRing[i] = &rxb[i * RX_BUF_SIZE]; - tp->RxDescArray[i].buf_addr = - virt_to_bus(tp->RxBufferRing[i]); - tp->RxDescArray[i].buf_Haddr = 0; - } + return ret; } -/************************************************************************** -RESET - Finish setting up the ethernet interface -***************************************************************************/ -static void r8169_reset(struct nic *nic) +static void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg, + int bitnum, int bitval) { - int i; - struct rtl8169_private *tp = &tpx; - - tp->TxDescArray = tx_ring; - tp->RxDescArray = rx_ring; - - rtl8169_init_ring(nic); - rtl8169_hw_start(nic); - /* Construct a perfect filter frame with the mac address as first match - * and broadcast for all others */ - for (i = 0; i < 192; i++) - txb[i] = 0xFF; - - txb[0] = nic->node_addr[0]; - txb[1] = nic->node_addr[1]; - txb[2] = nic->node_addr[2]; - txb[3] = nic->node_addr[3]; - txb[4] = nic->node_addr[4]; - txb[5] = nic->node_addr[5]; -} - -/************************************************************************** -DISABLE - Turn off ethernet interface -***************************************************************************/ -static void r8169_disable ( struct nic *nic __unused ) { - int i; - struct rtl8169_private *tp = &tpx; - - /* Stop the chip's Tx and Rx DMA processes. */ - RTL_W8(ChipCmd, 0x00); + int val; - /* Disable interrupts by clearing the interrupt mask. */ - RTL_W16(IntrMask, 0x0000); - - RTL_W32(RxMissed, 0); + DBGP ( "rtl8169_write_gmii_reg_bit\n" ); - tp->TxDescArray = NULL; - tp->RxDescArray = NULL; - for (i = 0; i < NUM_RX_DESC; i++) { - tp->RxBufferRing[i] = NULL; - } + val = mdio_read(ioaddr, reg); + val = (bitval == 1) ? + val | (bitval << bitnum) : val & ~(0x0001 << bitnum); + mdio_write(ioaddr, reg, val & 0xffff); } -static struct nic_operations r8169_operations = { - .connect = dummy_connect, - .poll = r8169_poll, - .transmit = r8169_transmit, - .irq = r8169_irq, - -}; - -static struct pci_device_id r8169_nics[] = { - PCI_ROM(0x10ec, 0x8169, "r8169", "RealTek RTL8169 Gigabit Ethernet"), - PCI_ROM(0x16ec, 0x0116, "usr-r8169", "US Robotics RTL8169 Gigabit Ethernet"), - PCI_ROM(0x1186, 0x4300, "dlink-r8169", "D-Link RTL8169 Gigabit Ethernet"), - PCI_ROM(0x1737, 0x1032, "linksys-r8169", "Linksys RTL8169 Gigabit Ethernet"), - PCI_ROM(0x10ec, 0x8129, "r8169-8129", "RealTek RT8129 Fast Ethernet Adapter"), - PCI_ROM(0x10ec, 0x8136, "r8169-8101e", "RealTek RTL8101E PCI Express Fast Ethernet controller"), - PCI_ROM(0x10ec, 0x8167, "r8169-8110sc/8169sc", "RealTek RTL-8110SC/8169SC Gigabit Ethernet"), - PCI_ROM(0x10ec, 0x8168, "r8169-8168b", "RealTek RTL8111/8168B PCI Express Gigabit Ethernet controller"), -}; - -PCI_DRIVER ( r8169_driver, r8169_nics, PCI_NO_CLASS ); - -/************************************************************************** -PROBE - Look for an adapter, this routine's visible to the outside -***************************************************************************/ - -#define board_found 1 -#define valid_link 0 -static int r8169_probe ( struct nic *nic, struct pci_device *pci ) { - - static int board_idx = -1; - static int printed_version = 0; - struct rtl8169_private *tp = &tpx; - int i, rc; - int option = -1, Cap10_100 = 0, Cap1000 = 0; - - printf ( "r8169.c: Found %s, Vendor=%hX Device=%hX\n", - pci->driver_name, pci->vendor, pci->device ); - - board_idx++; - - printed_version = 1; - - /* Quick and very dirty hack to get r8169 driver working - * again, pre-rewrite +static void rtl8169_get_mac_version(struct rtl8169_private *tp, + void *ioaddr) +{ + /* + * The driver currently handles the 8168Bf and the 8168Be identically + * but they can be identified more specifically through the test below + * if needed: + * + * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be + * + * Same thing for the 8101Eb and the 8101Ec: + * + * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec */ - if ( ! r8169_bufs ) - r8169_bufs = malloc_dma ( sizeof ( *r8169_bufs ), 256 ); - if ( ! r8169_bufs ) - return 0; - memset ( r8169_bufs, 0, sizeof ( *r8169_bufs ) ); - - rc = rtl8169_init_board(pci); /* Return code is meaningless */ - - /* Get MAC address. FIXME: read EEPROM */ - for (i = 0; i < MAC_ADDR_LEN; i++) - nic->node_addr[i] = RTL_R8(MAC0 + i); - - DBG ( "%s: Identified chip type is '%s'.\n", pci->driver_name, - rtl_chip_info[tp->chipset].name ); - - /* Print out some hardware info */ - DBG ( "%s: %s at ioaddr %#hx, ", pci->driver_name, eth_ntoa ( nic->node_addr ), - (unsigned int) ioaddr ); + const struct { + u32 mask; + u32 val; + int mac_version; + } mac_info[] = { + /* 8168D family. */ + { 0x7c800000, 0x28000000, RTL_GIGA_MAC_VER_25 }, + + /* 8168C family. */ + { 0x7cf00000, 0x3ca00000, RTL_GIGA_MAC_VER_24 }, + { 0x7cf00000, 0x3c900000, RTL_GIGA_MAC_VER_23 }, + { 0x7cf00000, 0x3c800000, RTL_GIGA_MAC_VER_18 }, + { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_24 }, + { 0x7cf00000, 0x3c000000, RTL_GIGA_MAC_VER_19 }, + { 0x7cf00000, 0x3c200000, RTL_GIGA_MAC_VER_20 }, + { 0x7cf00000, 0x3c300000, RTL_GIGA_MAC_VER_21 }, + { 0x7cf00000, 0x3c400000, RTL_GIGA_MAC_VER_22 }, + { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_22 }, - /* Config PHY */ - rtl8169_hw_phy_config(nic); - - DBG("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); - RTL_W8(0x82, 0x01); + /* 8168B family. */ + { 0x7cf00000, 0x38000000, RTL_GIGA_MAC_VER_12 }, + { 0x7cf00000, 0x38500000, RTL_GIGA_MAC_VER_17 }, + { 0x7c800000, 0x38000000, RTL_GIGA_MAC_VER_17 }, + { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 }, - pci_write_config_byte(pci, PCI_LATENCY_TIMER, 0x40); + /* 8101 family. */ + { 0x7cf00000, 0x34a00000, RTL_GIGA_MAC_VER_09 }, + { 0x7cf00000, 0x24a00000, RTL_GIGA_MAC_VER_09 }, + { 0x7cf00000, 0x34900000, RTL_GIGA_MAC_VER_08 }, + { 0x7cf00000, 0x24900000, RTL_GIGA_MAC_VER_08 }, + { 0x7cf00000, 0x34800000, RTL_GIGA_MAC_VER_07 }, + { 0x7cf00000, 0x24800000, RTL_GIGA_MAC_VER_07 }, + { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 }, + { 0x7cf00000, 0x34300000, RTL_GIGA_MAC_VER_10 }, + { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 }, + { 0x7c800000, 0x34800000, RTL_GIGA_MAC_VER_09 }, + { 0x7c800000, 0x24800000, RTL_GIGA_MAC_VER_09 }, + { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 }, + /* FIXME: where did these entries come from ? -- FR */ + { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 }, + { 0xfc800000, 0x30800000, RTL_GIGA_MAC_VER_14 }, - if (tp->mac_version <= RTL_GIGA_MAC_VER_06) - pci_write_config_byte(pci, PCI_CACHE_LINE_SIZE, 0x08); + /* 8110 family. */ + { 0xfc800000, 0x98000000, RTL_GIGA_MAC_VER_06 }, + { 0xfc800000, 0x18000000, RTL_GIGA_MAC_VER_05 }, + { 0xfc800000, 0x10000000, RTL_GIGA_MAC_VER_04 }, + { 0xfc800000, 0x04000000, RTL_GIGA_MAC_VER_03 }, + { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 }, + { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 }, - if (tp->mac_version == RTL_GIGA_MAC_VER_02) { - DBG("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); - RTL_W8(0x82, 0x01); - DBG("Set PHY Reg 0x0bh = 0x00h\n"); - RTL8169_WRITE_GMII_REG(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0 - } + { 0x00000000, 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */ + }, *p = mac_info; + u32 reg; - r8169_reset(nic); - - /* if TBI is not endbled */ - if (!(RTL_R8(PHYstatus) & TBI_Enable)) { - int val = RTL8169_READ_GMII_REG(ioaddr, PHY_AUTO_NEGO_REG); - -#ifdef RTL8169_HW_FLOW_CONTROL_SUPPORT - val |= PHY_Cap_PAUSE | PHY_Cap_ASYM_PAUSE; -#endif //end #define RTL8169_HW_FLOW_CONTROL_SUPPORT - - /* Force RTL8169 in 10/100/1000 Full/Half mode. */ - if (option > 0) { - printf(" Force-mode Enabled.\n"); - Cap10_100 = 0, Cap1000 = 0; - switch (option) { - case _10_Half: - Cap10_100 = PHY_Cap_10_Half; - Cap1000 = PHY_Cap_Null; - break; - case _10_Full: - Cap10_100 = PHY_Cap_10_Full; - Cap1000 = PHY_Cap_Null; - break; - case _100_Half: - Cap10_100 = PHY_Cap_100_Half; - Cap1000 = PHY_Cap_Null; - break; - case _100_Full: - Cap10_100 = PHY_Cap_100_Full; - Cap1000 = PHY_Cap_Null; - break; - case _1000_Full: - Cap10_100 = PHY_Cap_Null; - Cap1000 = PHY_Cap_1000_Full; - break; - default: - break; - } - RTL8169_WRITE_GMII_REG(ioaddr, PHY_AUTO_NEGO_REG, Cap10_100 | (val & 0xC1F)); //leave PHY_AUTO_NEGO_REG bit4:0 unchanged - RTL8169_WRITE_GMII_REG(ioaddr, PHY_1000_CTRL_REG, - Cap1000); - } else { - DBG ( "%s: Auto-negotiation Enabled.\n", pci->driver_name ); - - // enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged - RTL8169_WRITE_GMII_REG(ioaddr, PHY_AUTO_NEGO_REG, - PHY_Cap_10_Half | - PHY_Cap_10_Full | - PHY_Cap_100_Half | - PHY_Cap_100_Full | (val & - 0xC1F)); - - // enable 1000 Full Mode -// RTL8169_WRITE_GMII_REG( ioaddr, PHY_1000_CTRL_REG, PHY_Cap_1000_Full ); - RTL8169_WRITE_GMII_REG(ioaddr, PHY_1000_CTRL_REG, PHY_Cap_1000_Full | PHY_Cap_1000_Half); //rtl8168 - - } // end of if( option > 0 ) - - // Enable auto-negotiation and restart auto-nigotiation - RTL8169_WRITE_GMII_REG(ioaddr, PHY_CTRL_REG, - PHY_Enable_Auto_Nego | - PHY_Restart_Auto_Nego); - udelay(100); - - // wait for auto-negotiation process - for (i = 10000; i > 0; i--) { - //check if auto-negotiation complete - if (RTL8169_READ_GMII_REG(ioaddr, PHY_STAT_REG) & - PHY_Auto_Neco_Comp) { - udelay(100); - option = RTL_R8(PHYstatus); - if (option & _1000bpsF) { - printf - ("1000Mbps Full-duplex operation.\n"); - } else { - printf - ("%sMbps %s-duplex operation.\n", - (option & _100bps) ? "100" : - "10", - (option & FullDup) ? "Full" : - "Half"); - } - break; - } else { - udelay(100); - } // end of if( RTL8169_READ_GMII_REG(ioaddr, 1) & 0x20 ) - } // end for-loop to wait for auto-negotiation process + DBGP ( "rtl8169_get_mac_version\n" ); + reg = RTL_R32(TxConfig); + while ((reg & p->mask) != p->val) + p++; + tp->mac_version = p->mac_version; - } else { - udelay(100); - printf - ("%s: 1000Mbps Full-duplex operation, TBI Link %s!\n", - pci->driver_name, - (RTL_R32(TBICSR) & TBILinkOK) ? "OK" : "Failed"); + DBG ( "tp->mac_version = %d\n", tp->mac_version ); + if (p->mask == 0x00000000) { + DBG ( "unknown MAC (%08lx)\n", reg ); } - - r8169_reset(nic); - - /* point to NIC specific routines */ - nic->nic_op = &r8169_operations; - - nic->irqno = pci->irq; - nic->ioaddr = ioaddr; - - return 1; -} - -//====================================================================================================== -/* -static void rtl8169_hw_PHY_reset(struct nic *nic __unused) -{ - int val, phy_reset_expiretime = 50; - struct rtl8169_private *priv = dev->priv; - unsigned long ioaddr = priv->ioaddr; - - DBG("%s: Reset RTL8169s PHY\n", dev->name); - - val = ( RTL8169_READ_GMII_REG( ioaddr, 0 ) | 0x8000 ) & 0xffff; - RTL8169_WRITE_GMII_REG( ioaddr, 0, val ); - - do //waiting for phy reset - { - if( RTL8169_READ_GMII_REG( ioaddr, 0 ) & 0x8000 ){ - phy_reset_expiretime --; - udelay(100); - } - else{ - break; - } - }while( phy_reset_expiretime >= 0 ); - - assert( phy_reset_expiretime > 0 ); } -*/ - struct phy_reg { u16 reg; u16 val; @@ -1161,8 +436,10 @@ struct phy_reg { static void rtl_phy_write(void *ioaddr, struct phy_reg *regs, int len) { + DBGP ( "rtl_phy_write\n" ); + while (len-- > 0) { - RTL8169_WRITE_GMII_REG((u32)ioaddr, regs->reg, regs->val); + mdio_write(ioaddr, regs->reg, regs->val); regs++; } } @@ -1201,22 +478,24 @@ static void rtl8169s_hw_phy_config(void *ioaddr) }, *p = phy_magic; unsigned int i; - RTL8169_WRITE_GMII_REG((u32)ioaddr, 0x1f, 0x0001); //w 31 2 0 1 - RTL8169_WRITE_GMII_REG((u32)ioaddr, 0x15, 0x1000); //w 21 15 0 1000 - RTL8169_WRITE_GMII_REG((u32)ioaddr, 0x18, 0x65c7); //w 24 15 0 65c7 - RTL8169_WRITE_GMII_REG_BIT((u32)ioaddr, 4, 11, 0); //w 4 11 11 0 + DBGP ( "rtl8169s_hw_phy_config\n" ); + + mdio_write(ioaddr, 0x1f, 0x0001); //w 31 2 0 1 + mdio_write(ioaddr, 0x15, 0x1000); //w 21 15 0 1000 + mdio_write(ioaddr, 0x18, 0x65c7); //w 24 15 0 65c7 + rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0 for (i = 0; i < ARRAY_SIZE(phy_magic); i++, p++) { int val, pos = 4; - val = (RTL8169_READ_GMII_REG((u32)ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff); - RTL8169_WRITE_GMII_REG((u32)ioaddr, pos, val); + val = (mdio_read(ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff); + mdio_write(ioaddr, pos, val); while (--pos >= 0) - RTL8169_WRITE_GMII_REG((u32)ioaddr, pos, p->regs[4 - pos] & 0xffff); - RTL8169_WRITE_GMII_REG_BIT((u32)ioaddr, 4, 11, 1); //w 4 11 11 1 - RTL8169_WRITE_GMII_REG_BIT((u32)ioaddr, 4, 11, 0); //w 4 11 11 0 + mdio_write(ioaddr, pos, p->regs[4 - pos] & 0xffff); + rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1 + rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0 } - RTL8169_WRITE_GMII_REG((u32)ioaddr, 0x1f, 0x0000); //w 31 2 0 0 + mdio_write(ioaddr, 0x1f, 0x0000); //w 31 2 0 0 } static void rtl8169sb_hw_phy_config(void *ioaddr) @@ -1227,65 +506,261 @@ static void rtl8169sb_hw_phy_config(void *ioaddr) { 0x1f, 0x0000 } }; + DBGP ( "rtl8169sb_hw_phy_config\n" ); + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } -static void rtl8168cp_hw_phy_config(void *ioaddr) +static void rtl8168bb_hw_phy_config(void *ioaddr) { struct phy_reg phy_reg_init[] = { - { 0x1f, 0x0000 }, - { 0x1d, 0x0f00 }, - { 0x1f, 0x0002 }, - { 0x0c, 0x1ec8 }, + { 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 rtl8168c_hw_phy_config(void *ioaddr) +static void rtl8168bef_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 }, + { 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 rtl8168cx_hw_phy_config(void *ioaddr) +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 }, + { 0x1f, 0x0000 } + }; + + DBGP ( "rtl8168c_2_hw_phy_config\n" ); + + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); + + mdio_patch(ioaddr, 0x16, 1 << 0); + mdio_patch(ioaddr, 0x14, 1 << 5); + mdio_patch(ioaddr, 0x0d, 1 << 5); + mdio_write(ioaddr, 0x1f, 0x0000); +} + +static void rtl8168c_3_hw_phy_config(void *ioaddr) +{ + struct phy_reg phy_reg_init[] = { + { 0x1f, 0x0001 }, + { 0x12, 0x2300 }, + { 0x1d, 0x3d98 }, { 0x1f, 0x0002 }, { 0x0c, 0x7eb8 }, + { 0x06, 0x5461 }, + { 0x1f, 0x0003 }, + { 0x16, 0x0f0a }, + { 0x1f, 0x0000 } + }; + + DBGP ( "rtl8168c_3_hw_phy_config\n" ); + + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); + + mdio_patch(ioaddr, 0x16, 1 << 0); + mdio_patch(ioaddr, 0x14, 1 << 5); + mdio_patch(ioaddr, 0x0d, 1 << 5); + mdio_write(ioaddr, 0x1f, 0x0000); +} + +static void rtl8168c_4_hw_phy_config(void *ioaddr) +{ + DBGP ( "rtl8168c_4_hw_phy_config\n" ); + + rtl8168c_3_hw_phy_config(ioaddr); +} + +static void rtl8168d_hw_phy_config(void *ioaddr) +{ + struct phy_reg phy_reg_init_0[] = { + { 0x1f, 0x0001 }, + { 0x09, 0x2770 }, + { 0x08, 0x04d0 }, + { 0x0b, 0xad15 }, + { 0x0c, 0x5bf0 }, + { 0x1c, 0xf101 }, + { 0x1f, 0x0003 }, + { 0x14, 0x94d7 }, + { 0x12, 0xf4d6 }, + { 0x09, 0xca0f }, + { 0x1f, 0x0002 }, + { 0x0b, 0x0b10 }, + { 0x0c, 0xd1f7 }, + { 0x1f, 0x0002 }, + { 0x06, 0x5461 }, + { 0x1f, 0x0002 }, + { 0x05, 0x6662 }, + { 0x1f, 0x0000 }, + { 0x14, 0x0060 }, + { 0x1f, 0x0000 }, + { 0x0d, 0xf8a0 }, + { 0x1f, 0x0005 }, + { 0x05, 0xffc2 } + }; + + DBGP ( "rtl8168d_hw_phy_config\n" ); + + rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0)); + + if (mdio_read(ioaddr, 0x06) == 0xc400) { + struct phy_reg phy_reg_init_1[] = { + { 0x1f, 0x0005 }, + { 0x01, 0x0300 }, + { 0x1f, 0x0000 }, + { 0x11, 0x401c }, + { 0x16, 0x4100 }, + { 0x1f, 0x0005 }, + { 0x07, 0x0010 }, + { 0x05, 0x83dc }, + { 0x06, 0x087d }, + { 0x05, 0x8300 }, + { 0x06, 0x0101 }, + { 0x06, 0x05f8 }, + { 0x06, 0xf9fa }, + { 0x06, 0xfbef }, + { 0x06, 0x79e2 }, + { 0x06, 0x835f }, + { 0x06, 0xe0f8 }, + { 0x06, 0x9ae1 }, + { 0x06, 0xf89b }, + { 0x06, 0xef31 }, + { 0x06, 0x3b65 }, + { 0x06, 0xaa07 }, + { 0x06, 0x81e4 }, + { 0x06, 0xf89a }, + { 0x06, 0xe5f8 }, + { 0x06, 0x9baf }, + { 0x06, 0x06ae }, + { 0x05, 0x83dc }, + { 0x06, 0x8300 }, + }; + + rtl_phy_write(ioaddr, phy_reg_init_1, + ARRAY_SIZE(phy_reg_init_1)); + } + + mdio_write(ioaddr, 0x1f, 0x0000); +} + +static void rtl8102e_hw_phy_config(void *ioaddr) +{ + struct phy_reg phy_reg_init[] = { + { 0x1f, 0x0003 }, + { 0x08, 0x441d }, + { 0x01, 0x9100 }, { 0x1f, 0x0000 } }; + DBGP ( "rtl8102e_hw_phy_config\n" ); + + mdio_write(ioaddr, 0x1f, 0x0000); + mdio_patch(ioaddr, 0x11, 1 << 12); + mdio_patch(ioaddr, 0x19, 1 << 13); + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } -static void rtl8169_hw_phy_config(struct nic *nic __unused) +static void rtl_hw_phy_config(struct net_device *dev) { - struct rtl8169_private *tp = &tpx; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; - DBG("rtl8169_hw_phy_config(): card at addr=0x%lx: priv->mac_version=%d, priv->pcfg=%d\n", (unsigned long) ioaddr, tp->mac_version, tp->pcfg); + + DBGP ( "rtl_hw_phy_config\n" ); + + DBG ( "mac_version = 0x%02x\n", tp->mac_version ); switch (tp->mac_version) { case RTL_GIGA_MAC_VER_01: @@ -1297,22 +772,1506 @@ static void rtl8169_hw_phy_config(struct nic *nic __unused) case RTL_GIGA_MAC_VER_04: rtl8169sb_hw_phy_config(ioaddr); break; + case RTL_GIGA_MAC_VER_07: + case RTL_GIGA_MAC_VER_08: + case RTL_GIGA_MAC_VER_09: + rtl8102e_hw_phy_config(ioaddr); + break; + case RTL_GIGA_MAC_VER_11: + rtl8168bb_hw_phy_config(ioaddr); + break; + case RTL_GIGA_MAC_VER_12: + rtl8168bef_hw_phy_config(ioaddr); + break; + case RTL_GIGA_MAC_VER_17: + rtl8168bef_hw_phy_config(ioaddr); + break; case RTL_GIGA_MAC_VER_18: - rtl8168cp_hw_phy_config(ioaddr); + rtl8168cp_1_hw_phy_config(ioaddr); break; case RTL_GIGA_MAC_VER_19: - rtl8168c_hw_phy_config(ioaddr); + rtl8168c_1_hw_phy_config(ioaddr); break; case RTL_GIGA_MAC_VER_20: - rtl8168cx_hw_phy_config(ioaddr); + rtl8168c_2_hw_phy_config(ioaddr); + break; + case RTL_GIGA_MAC_VER_21: + rtl8168c_3_hw_phy_config(ioaddr); + break; + case RTL_GIGA_MAC_VER_22: + rtl8168c_4_hw_phy_config(ioaddr); + break; + case RTL_GIGA_MAC_VER_23: + case RTL_GIGA_MAC_VER_24: + rtl8168cp_2_hw_phy_config(ioaddr); break; + case RTL_GIGA_MAC_VER_25: + rtl8168d_hw_phy_config(ioaddr); + break; + default: break; } } -DRIVER ( "r8169/PCI", nic_driver, pci_driver, r8169_driver, - r8169_probe, r8169_disable ); +static void rtl8169_phy_reset(struct net_device *dev __unused, + struct rtl8169_private *tp) +{ + void *ioaddr = tp->mmio_addr; + unsigned int i; + + DBGP ( "rtl8169_phy_reset\n" ); + + tp->phy_reset_enable(ioaddr); + for (i = 0; i < 100; i++) { + if (!tp->phy_reset_pending(ioaddr)) + return; + mdelay ( 1 ); + } + DBG ( "PHY reset failed.\n" ); +} + +static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp) +{ + void *ioaddr = tp->mmio_addr; + + DBGP ( "rtl8169_init_phy\n" ); + + rtl_hw_phy_config(dev); + + if (tp->mac_version <= RTL_GIGA_MAC_VER_06) { + DBG ( "Set MAC Reg C+CR Offset 0x82h = 0x01h\n" ); + RTL_W8(0x82, 0x01); + } + + pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40); + + if (tp->mac_version <= RTL_GIGA_MAC_VER_06) + pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08); + + if (tp->mac_version == RTL_GIGA_MAC_VER_02) { + DBG ( "Set MAC Reg C+CR Offset 0x82h = 0x01h\n" ); + RTL_W8(0x82, 0x01); + DBG ( "Set PHY Reg 0x0bh = 0x00h\n" ); + mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0 + } + + rtl8169_phy_reset(dev, tp); + + /* + * rtl8169_set_speed_xmii takes good care of the Fast Ethernet + * only 8101. Don't panic. + */ + rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL); + + if ((RTL_R8(PHYstatus) & TBI_Enable)) + DBG ( "TBI auto-negotiating\n" ); +} + +static const struct rtl_cfg_info { + void (*hw_start)(struct net_device *); + unsigned int region; + unsigned int align; + u16 intr_event; + u16 napi_event; + unsigned features; +} rtl_cfg_infos [] = { + [RTL_CFG_0] = { + .hw_start = rtl_hw_start_8169, + .region = 1, + .align = 0, + .intr_event = SYSErr | LinkChg | RxOverflow | + RxFIFOOver | TxErr | TxOK | RxOK | RxErr, + .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, + .features = RTL_FEATURE_GMII + }, + [RTL_CFG_1] = { + .hw_start = rtl_hw_start_8168, + .region = 2, + .align = 8, + .intr_event = SYSErr | LinkChg | RxOverflow | + TxErr | TxOK | RxOK | RxErr, + .napi_event = TxErr | TxOK | RxOK | RxOverflow, + .features = RTL_FEATURE_GMII + }, + [RTL_CFG_2] = { + .hw_start = rtl_hw_start_8101, + .region = 2, + .align = 8, + .intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout | + RxFIFOOver | TxErr | TxOK | RxOK | RxErr, + .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, + } +}; + +static void rtl8169_hw_reset(void *ioaddr) +{ + DBGP ( "rtl8169_hw_reset\n" ); + + /* Disable interrupts */ + rtl8169_irq_mask_and_ack(ioaddr); + + /* Reset the chipset */ + RTL_W8(ChipCmd, CmdReset); + + /* PCI commit */ + RTL_R8(ChipCmd); +} + +static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp) +{ + void *ioaddr = tp->mmio_addr; + u32 cfg = rtl8169_rx_config; + + DBGP ( "rtl_set_rx_tx_config_registers\n" ); + + cfg |= (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); + RTL_W32(RxConfig, cfg); + + /* Set DMA burst size and Interframe Gap Time */ + RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) | + (InterFrameGap << TxInterFrameGapShift)); +} + +static void rtl_soft_reset ( struct net_device *dev ) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + unsigned int i; + + DBGP ( "rtl_hw_soft_reset\n" ); + + /* Soft reset the chip. */ + RTL_W8(ChipCmd, CmdReset); + + /* Check that the chip has finished the reset. */ + for (i = 0; i < 100; i++) { + if ((RTL_R8(ChipCmd) & CmdReset) == 0) + break; + mdelay ( 1 ); + } + + if ( i == 100 ) { + DBG ( "Reset Failed! (> 100 iterations)\n" ); + } +} + +static void rtl_hw_start ( struct net_device *dev ) +{ + struct rtl8169_private *tp = netdev_priv ( dev ); + + DBGP ( "rtl_hw_start\n" ); + + /* Soft reset NIC */ + rtl_soft_reset ( dev ); + + tp->hw_start ( dev ); +} + +static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp, + void *ioaddr) +{ + DBGP ( "rtl_set_rx_tx_desc_registers\n" ); + + /* + * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh + * register to be written before TxDescAddrLow to work. + * Switching from MMIO to I/O access fixes the issue as well. + */ + RTL_W32 ( TxDescStartAddrHigh, 0 ); + RTL_W32 ( TxDescStartAddrLow, virt_to_bus ( tp->tx_base ) ); + RTL_W32 ( RxDescAddrHigh, 0 ); + RTL_W32 ( RxDescAddrLow, virt_to_bus ( tp->rx_base ) ); +} + +static u16 rtl_rw_cpluscmd(void *ioaddr) +{ + u16 cmd; + + DBGP ( "rtl_rw_cpluscmd\n" ); + + cmd = RTL_R16(CPlusCmd); + RTL_W16(CPlusCmd, cmd); + return cmd; +} + +static void rtl_set_rx_max_size(void *ioaddr) +{ + DBGP ( "rtl_set_rx_max_size\n" ); + + RTL_W16 ( RxMaxSize, RX_BUF_SIZE ); +} + +static void rtl8169_set_magic_reg(void *ioaddr, unsigned mac_version) +{ + struct { + u32 mac_version; + u32 clk; + u32 val; + } cfg2_info [] = { + { RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd + { RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff }, + { RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe + { RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff } + }, *p = cfg2_info; + unsigned int i; + u32 clk; + + DBGP ( "rtl8169_set_magic_reg\n" ); + + clk = RTL_R8(Config2) & PCI_Clock_66MHz; + for (i = 0; i < ARRAY_SIZE(cfg2_info); i++, p++) { + if ((p->mac_version == mac_version) && (p->clk == clk)) { + RTL_W32(0x7c, p->val); + break; + } + } +} + +static void rtl_set_rx_mode ( struct net_device *netdev ) +{ + struct rtl8169_private *tp = netdev_priv ( netdev ); + void *ioaddr = tp->mmio_addr; + u32 tmp; + + DBGP ( "rtl_set_rx_mode\n" ); + + /* Accept all Multicast Packets */ + + RTL_W32 ( MAR0 + 0, 0xffffffff ); + RTL_W32 ( MAR0 + 4, 0xffffffff ); + + tmp = rtl8169_rx_config | AcceptBroadcast | AcceptMulticast | AcceptMyPhys | + ( RTL_R32 ( RxConfig ) & rtl_chip_info[tp->chipset].RxConfigMask ); + + RTL_W32 ( RxConfig, tmp ); +} + +static void rtl_hw_start_8169(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + struct pci_device *pdev = tp->pci_dev; + + DBGP ( "rtl_hw_start_8169\n" ); + + if (tp->mac_version == RTL_GIGA_MAC_VER_05) { + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW); + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08); + } + + RTL_W8(Cfg9346, Cfg9346_Unlock); + + if ((tp->mac_version == RTL_GIGA_MAC_VER_01) || + (tp->mac_version == RTL_GIGA_MAC_VER_02) || + (tp->mac_version == RTL_GIGA_MAC_VER_03) || + (tp->mac_version == RTL_GIGA_MAC_VER_04)) + RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); + + RTL_W8(EarlyTxThres, EarlyTxThld); + + rtl_set_rx_max_size(ioaddr); + + if ((tp->mac_version == RTL_GIGA_MAC_VER_01) || + (tp->mac_version == RTL_GIGA_MAC_VER_02) || + (tp->mac_version == RTL_GIGA_MAC_VER_03) || + (tp->mac_version == RTL_GIGA_MAC_VER_04)) + rtl_set_rx_tx_config_registers(tp); + + tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW; + + if ((tp->mac_version == RTL_GIGA_MAC_VER_02) || + (tp->mac_version == RTL_GIGA_MAC_VER_03)) { + DBG ( "Set MAC Reg C+CR Offset 0xE0. " + "Bit-3 and bit-14 MUST be 1\n" ); + tp->cp_cmd |= (1 << 14); + } + + RTL_W16(CPlusCmd, tp->cp_cmd); + + rtl8169_set_magic_reg(ioaddr, tp->mac_version); + + /* + * Undocumented corner. Supposedly: + * (TxTimer << 12) | (TxPackets << 8) | (RxTimer << 4) | RxPackets + */ + RTL_W16(IntrMitigate, 0x0000); + + rtl_set_rx_tx_desc_registers(tp, ioaddr); + + if ((tp->mac_version != RTL_GIGA_MAC_VER_01) && + (tp->mac_version != RTL_GIGA_MAC_VER_02) && + (tp->mac_version != RTL_GIGA_MAC_VER_03) && + (tp->mac_version != RTL_GIGA_MAC_VER_04)) { + RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); + rtl_set_rx_tx_config_registers(tp); + } + + RTL_W8(Cfg9346, Cfg9346_Lock); + + /* Initially a 10 us delay. Turned it into a PCI commit. - FR */ + RTL_R8(IntrMask); + + RTL_W32(RxMissed, 0); + + rtl_set_rx_mode(dev); + + /* no early-rx interrupts */ + RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000); + + // RTL_W16(IntrMask, tp->intr_event); +} + +static void rtl_tx_performance_tweak(struct pci_device *pdev, u16 force) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct rtl8169_private *tp = netdev_priv(dev); + int cap = tp->pcie_cap; + + DBGP ( "rtl_tx_performance_tweak\n" ); + + if (cap) { + u16 ctl; + + pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl); + ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | force; + pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl); + } +} + +static void rtl_csi_access_enable(void *ioaddr) +{ + u32 csi; + + DBGP ( "rtl_csi_access_enable\n" ); + + csi = rtl_csi_read(ioaddr, 0x070c) & 0x00ffffff; + rtl_csi_write(ioaddr, 0x070c, csi | 0x27000000); +} + +struct ephy_info { + unsigned int offset; + u16 mask; + u16 bits; +}; + +static void rtl_ephy_init(void *ioaddr, struct ephy_info *e, int len) +{ + u16 w; + + DBGP ( "rtl_ephy_init\n" ); + + while (len-- > 0) { + w = (rtl_ephy_read(ioaddr, e->offset) & ~e->mask) | e->bits; + rtl_ephy_write(ioaddr, e->offset, w); + e++; + } +} + +static void rtl_disable_clock_request(struct pci_device *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct rtl8169_private *tp = netdev_priv(dev); + int cap = tp->pcie_cap; + + DBGP ( "rtl_disable_clock_request\n" ); + + if (cap) { + u16 ctl; + + pci_read_config_word(pdev, cap + PCI_EXP_LNKCTL, &ctl); + ctl &= ~PCI_EXP_LNKCTL_CLKREQ_EN; + pci_write_config_word(pdev, cap + PCI_EXP_LNKCTL, ctl); + } +} + +#define R8168_CPCMD_QUIRK_MASK (\ + EnableBist | \ + Mac_dbgo_oe | \ + Force_half_dup | \ + Force_rxflow_en | \ + Force_txflow_en | \ + Cxpl_dbg_sel | \ + ASF | \ + PktCntrDisable | \ + Mac_dbgo_sel) + +static void rtl_hw_start_8168bb(void *ioaddr, struct pci_device *pdev) +{ + DBGP ( "rtl_hw_start_8168bb\n" ); + + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); + + rtl_tx_performance_tweak(pdev, + (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN); +} + +static void rtl_hw_start_8168bef(void *ioaddr, struct pci_device *pdev) +{ + DBGP ( "rtl_hw_start_8168bef\n" ); + + rtl_hw_start_8168bb(ioaddr, pdev); + + RTL_W8(EarlyTxThres, EarlyTxThld); + + RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0)); +} + +static void __rtl_hw_start_8168cp(void *ioaddr, struct pci_device *pdev) +{ + DBGP ( "__rtl_hw_start_8168cp\n" ); + + RTL_W8(Config1, RTL_R8(Config1) | Speed_down); + + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + rtl_disable_clock_request(pdev); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); +} + +static void rtl_hw_start_8168cp_1(void *ioaddr, struct pci_device *pdev) +{ + static struct ephy_info e_info_8168cp[] = { + { 0x01, 0, 0x0001 }, + { 0x02, 0x0800, 0x1000 }, + { 0x03, 0, 0x0042 }, + { 0x06, 0x0080, 0x0000 }, + { 0x07, 0, 0x2000 } + }; + + DBGP ( "rtl_hw_start_8168cp_1\n" ); + + rtl_csi_access_enable(ioaddr); + + rtl_ephy_init(ioaddr, e_info_8168cp, ARRAY_SIZE(e_info_8168cp)); + + __rtl_hw_start_8168cp(ioaddr, pdev); +} + +static void rtl_hw_start_8168cp_2(void *ioaddr, struct pci_device *pdev) +{ + DBGP ( "rtl_hw_start_8168cp_2\n" ); + + rtl_csi_access_enable(ioaddr); + + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); +} + +static void rtl_hw_start_8168cp_3(void *ioaddr, struct pci_device *pdev) +{ + DBGP ( "rtl_hw_start_8168cp_3\n" ); + + rtl_csi_access_enable(ioaddr); + + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); + + /* Magic. */ + RTL_W8(DBG_REG, 0x20); + + RTL_W8(EarlyTxThres, EarlyTxThld); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); +} + +static void rtl_hw_start_8168c_1(void *ioaddr, struct pci_device *pdev) +{ + static struct ephy_info e_info_8168c_1[] = { + { 0x02, 0x0800, 0x1000 }, + { 0x03, 0, 0x0002 }, + { 0x06, 0x0080, 0x0000 } + }; + + DBGP ( "rtl_hw_start_8168c_1\n" ); + + rtl_csi_access_enable(ioaddr); + + RTL_W8(DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2); + + rtl_ephy_init(ioaddr, e_info_8168c_1, ARRAY_SIZE(e_info_8168c_1)); + + __rtl_hw_start_8168cp(ioaddr, pdev); +} + +static void rtl_hw_start_8168c_2(void *ioaddr, struct pci_device *pdev) +{ + static struct ephy_info e_info_8168c_2[] = { + { 0x01, 0, 0x0001 }, + { 0x03, 0x0400, 0x0220 } + }; + + DBGP ( "rtl_hw_start_8168c_2\n" ); + + rtl_csi_access_enable(ioaddr); + + rtl_ephy_init(ioaddr, e_info_8168c_2, ARRAY_SIZE(e_info_8168c_2)); + + __rtl_hw_start_8168cp(ioaddr, pdev); +} + +static void rtl_hw_start_8168c_3(void *ioaddr, struct pci_device *pdev) +{ + DBGP ( "rtl_hw_start_8168c_3\n" ); + + rtl_hw_start_8168c_2(ioaddr, pdev); +} + +static void rtl_hw_start_8168c_4(void *ioaddr, struct pci_device *pdev) +{ + DBGP ( "rtl_hw_start_8168c_4\n" ); + + rtl_csi_access_enable(ioaddr); + + __rtl_hw_start_8168cp(ioaddr, pdev); +} + +static void rtl_hw_start_8168d(void *ioaddr, struct pci_device *pdev) +{ + DBGP ( "rtl_hw_start_8168d\n" ); + + rtl_csi_access_enable(ioaddr); + + rtl_disable_clock_request(pdev); + + RTL_W8(EarlyTxThres, EarlyTxThld); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); +} + +static void rtl_hw_start_8168(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + struct pci_device *pdev = tp->pci_dev; + + DBGP ( "rtl_hw_start_8168\n" ); + + RTL_W8(Cfg9346, Cfg9346_Unlock); + + RTL_W8(EarlyTxThres, EarlyTxThld); + + rtl_set_rx_max_size(ioaddr); + + tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1; + + RTL_W16(CPlusCmd, tp->cp_cmd); + + RTL_W16(IntrMitigate, 0x5151); + + /* Work around for RxFIFO overflow. */ + if (tp->mac_version == RTL_GIGA_MAC_VER_11) { + tp->intr_event |= RxFIFOOver | PCSTimeout; + tp->intr_event &= ~RxOverflow; + } + + rtl_set_rx_tx_desc_registers(tp, ioaddr); + + rtl_set_rx_mode(dev); + + RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) | + (InterFrameGap << TxInterFrameGapShift)); + + RTL_R8(IntrMask); + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_11: + rtl_hw_start_8168bb(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_12: + case RTL_GIGA_MAC_VER_17: + rtl_hw_start_8168bef(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_18: + rtl_hw_start_8168cp_1(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_19: + rtl_hw_start_8168c_1(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_20: + rtl_hw_start_8168c_2(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_21: + rtl_hw_start_8168c_3(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_22: + rtl_hw_start_8168c_4(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_23: + rtl_hw_start_8168cp_2(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_24: + rtl_hw_start_8168cp_3(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_25: + rtl_hw_start_8168d(ioaddr, pdev); + break; + + default: + DBG ( "Unknown chipset (mac_version = %d).\n", + tp->mac_version ); + break; + } + + RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); + + RTL_W8(Cfg9346, Cfg9346_Lock); + + RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000); + + // RTL_W16(IntrMask, tp->intr_event); +} + +#define R810X_CPCMD_QUIRK_MASK (\ + EnableBist | \ + Mac_dbgo_oe | \ + Force_half_dup | \ + Force_half_dup | \ + Force_txflow_en | \ + Cxpl_dbg_sel | \ + ASF | \ + PktCntrDisable | \ + PCIDAC | \ + PCIMulRW) + +static void rtl_hw_start_8102e_1(void *ioaddr, struct pci_device *pdev) +{ + static struct ephy_info e_info_8102e_1[] = { + { 0x01, 0, 0x6e65 }, + { 0x02, 0, 0x091f }, + { 0x03, 0, 0xc2f9 }, + { 0x06, 0, 0xafb5 }, + { 0x07, 0, 0x0e00 }, + { 0x19, 0, 0xec80 }, + { 0x01, 0, 0x2e65 }, + { 0x01, 0, 0x6e65 } + }; + u8 cfg1; + + DBGP ( "rtl_hw_start_8102e_1\n" ); + + rtl_csi_access_enable(ioaddr); + + RTL_W8(DBG_REG, FIX_NAK_1); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W8(Config1, + LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable); + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); + + cfg1 = RTL_R8(Config1); + if ((cfg1 & LEDS0) && (cfg1 & LEDS1)) + RTL_W8(Config1, cfg1 & ~LEDS0); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK); + + rtl_ephy_init(ioaddr, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1)); +} + +static void rtl_hw_start_8102e_2(void *ioaddr, struct pci_device *pdev) +{ + DBGP ( "rtl_hw_start_8102e_2\n" ); + + rtl_csi_access_enable(ioaddr); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable); + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK); +} + +static void rtl_hw_start_8102e_3(void *ioaddr, struct pci_device *pdev) +{ + DBGP ( "rtl_hw_start_8102e_3\n" ); + + rtl_hw_start_8102e_2(ioaddr, pdev); + + rtl_ephy_write(ioaddr, 0x03, 0xc2f9); +} + +static void rtl_hw_start_8101(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + struct pci_device *pdev = tp->pci_dev; + + DBGP ( "rtl_hw_start_8101\n" ); + + if ((tp->mac_version == RTL_GIGA_MAC_VER_13) || + (tp->mac_version == RTL_GIGA_MAC_VER_16)) { + int cap = tp->pcie_cap; + + if (cap) { + pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, + PCI_EXP_DEVCTL_NOSNOOP_EN); + } + } + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_07: + rtl_hw_start_8102e_1(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_08: + rtl_hw_start_8102e_3(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_09: + rtl_hw_start_8102e_2(ioaddr, pdev); + break; + } + + RTL_W8(Cfg9346, Cfg9346_Unlock); + + RTL_W8(EarlyTxThres, EarlyTxThld); + + rtl_set_rx_max_size(ioaddr); + + tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW; + + RTL_W16(CPlusCmd, tp->cp_cmd); + + RTL_W16(IntrMitigate, 0x0000); + + rtl_set_rx_tx_desc_registers(tp, ioaddr); + + RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); + rtl_set_rx_tx_config_registers(tp); + + RTL_W8(Cfg9346, Cfg9346_Lock); + + RTL_R8(IntrMask); + + rtl_set_rx_mode(dev); + + RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); + + RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000); + + // RTL_W16(IntrMask, tp->intr_event); +} + +/*** gPXE API Support Routines ***/ + +/** + * setup_tx_resources - allocate tx resources (descriptors) + * + * @v tp Driver private storage + * + * @ret rc Returns 0 on success, negative on failure + **/ +static int +rtl8169_setup_tx_resources ( struct rtl8169_private *tp ) +{ + DBGP ( "rtl8169_setup_tx_resources\n" ); + + tp->tx_base = malloc_dma ( R8169_TX_RING_BYTES, TX_RING_ALIGN ); + + if ( ! tp->tx_base ) { + return -ENOMEM; + } + + memset ( tp->tx_base, 0, R8169_TX_RING_BYTES ); + + DBG ( "tp->tx_base = %#08lx\n", virt_to_bus ( tp->tx_base ) ); + + tp->tx_fill_ctr = 0; + tp->tx_curr = 0; + tp->tx_tail = 0; + + return 0; +} + +static void +rtl8169_process_tx_packets ( struct net_device *netdev ) +{ + struct rtl8169_private *tp = netdev_priv ( netdev ); + + uint32_t tx_status; + struct TxDesc *tx_curr_desc; + + DBGP ( "rtl8169_process_tx_packets\n" ); + + while ( tp->tx_tail != tp->tx_curr ) { + + tx_curr_desc = tp->tx_base + tp->tx_tail; + + tx_status = tx_curr_desc->opts1; + + DBG2 ( "Before DescOwn check tx_status: %#08lx\n", tx_status ); + + /* if the packet at tx_tail is not owned by hardware it is for us */ + if ( tx_status & DescOwn ) + break; + + DBG ( "Transmitted packet.\n" ); + DBG ( "tp->tx_fill_ctr = %ld\n", tp->tx_fill_ctr ); + DBG ( "tp->tx_tail = %ld\n", tp->tx_tail ); + DBG ( "tp->tx_curr = %ld\n", tp->tx_curr ); + DBG ( "tx_status = %ld\n", tx_status ); + DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) ); + + /* Pass packet to core for processing */ + netdev_tx_complete ( netdev, tp->tx_iobuf[tp->tx_tail] ); + + memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) ); + + /* Decrement count of used descriptors */ + tp->tx_fill_ctr--; + + /* Increment sent packets index */ + tp->tx_tail = ( tp->tx_tail + 1 ) % NUM_TX_DESC; + } +} + +static void +rtl8169_free_tx_resources ( struct rtl8169_private *tp ) +{ + DBGP ( "rtl8169_free_tx_resources\n" ); + + free_dma ( tp->tx_base, R8169_TX_RING_BYTES ); +} + +static void +rtl8169_populate_rx_descriptor ( struct rtl8169_private *tp, struct RxDesc *rx_desc, uint32_t index ) +{ + DBGP ( "rtl8169_populate_rx_descriptor\n" ); + + DBG ( "Populating rx descriptor %ld\n", index ); + + memset ( rx_desc, 0, sizeof ( *rx_desc ) ); + + rx_desc->addr_hi = 0; + rx_desc->addr_lo = virt_to_bus ( tp->rx_iobuf[index]->data ); + rx_desc->opts2 = 0; + rx_desc->opts1 = ( index == ( NUM_RX_DESC - 1 ) ? RingEnd : 0 ) | + RX_BUF_SIZE; + rx_desc->opts1 |= DescOwn; +} + +/** + * Refill descriptor ring + * + * @v netdev Net device + */ +static void rtl8169_refill_rx_ring ( struct rtl8169_private *tp ) +{ + struct RxDesc *rx_curr_desc; + int i; + + DBGP ( "rtl8169_refill_rx_ring\n" ); + + for ( i = 0; i < NUM_RX_DESC; i++ ) { + + rx_curr_desc = ( tp->rx_base ) + i; + + /* Don't touch descriptors owned by the NIC */ + if ( rx_curr_desc->opts1 & DescOwn ) + continue; + + /* Don't touch descriptors with iobufs, they still need to be + processed by the poll routine */ + if ( tp->rx_iobuf[tp->rx_curr] != NULL ) + continue; + + /** If we can't get an iobuf for this descriptor + try again later (next poll). + */ + if ( ! ( tp->rx_iobuf[i] = alloc_iob ( RX_BUF_SIZE ) ) ) { + DBG ( "Refill rx ring failed!!\n" ); + break; + } + + rtl8169_populate_rx_descriptor ( tp, rx_curr_desc, i ); + } +} + +/** + * setup_rx_resources - allocate Rx resources (Descriptors) + * + * @v tp: Driver private structure + * + * @ret rc Returns 0 on success, negative on failure + * + **/ +static int +rtl8169_setup_rx_resources ( struct rtl8169_private *tp ) +{ + DBGP ( "rtl8169_setup_rx_resources\n" ); + + tp->rx_base = malloc_dma ( R8169_RX_RING_BYTES, RX_RING_ALIGN ); + + DBG ( "tp->rx_base = %#08lx\n", virt_to_bus ( tp->rx_base ) ); + + if ( ! tp->rx_base ) { + return -ENOMEM; + } + memset ( tp->rx_base, 0, R8169_RX_RING_BYTES ); + + rtl8169_refill_rx_ring ( tp ); + + tp->rx_curr = 0; + + return 0; +} + +static void +rtl8169_process_rx_packets ( struct net_device *netdev ) +{ + struct rtl8169_private *tp = netdev_priv ( netdev ); + uint32_t rx_status; + uint16_t rx_len; + struct RxDesc *rx_curr_desc; + int i; + + DBGP ( "rtl8169_process_rx_packets\n" ); + + for ( i = 0; i < NUM_RX_DESC; i++ ) { + + rx_curr_desc = tp->rx_base + tp->rx_curr; + + rx_status = rx_curr_desc->opts1; + + DBG2 ( "Before DescOwn check rx_status: %#08lx\n", rx_status ); + + /* Hardware still owns the descriptor */ + if ( rx_status & DescOwn ) + break; + + /* We own the descriptor, but it has not been refilled yet */ + if ( tp->rx_iobuf[tp->rx_curr] == NULL ) + break; + + rx_len = rx_status & 0x3fff; + + DBG ( "Received packet.\n" ); + DBG ( "tp->rx_curr = %ld\n", tp->rx_curr ); + DBG ( "rx_len = %d\n", rx_len ); + DBG ( "rx_status = %#08lx\n", rx_status ); + DBG ( "rx_curr_desc = %#08lx\n", virt_to_bus ( rx_curr_desc ) ); + + if ( rx_status & RxRES ) { + + netdev_rx_err ( netdev, tp->rx_iobuf[tp->rx_curr], -EINVAL ); + + DBG ( "rtl8169_poll: Corrupted packet received!\n" + " rx_status: %#08lx\n", rx_status ); + + } else { + + /* Adjust size of the iobuf to reflect received data */ + iob_put ( tp->rx_iobuf[tp->rx_curr], rx_len ); + + /* Add this packet to the receive queue. */ + netdev_rx ( netdev, tp->rx_iobuf[tp->rx_curr] ); + } + + /* Invalidate this iobuf and descriptor */ + tp->rx_iobuf[tp->rx_curr] = NULL; + memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) ); + + /* Update pointer to next available rx descriptor */ + tp->rx_curr = ( tp->rx_curr + 1 ) % NUM_RX_DESC; + } + rtl8169_refill_rx_ring ( tp ); +} + +static void +rtl8169_free_rx_resources ( struct rtl8169_private *tp ) +{ + int i; + + DBGP ( "rtl8169_free_rx_resources\n" ); + + free_dma ( tp->rx_base, R8169_RX_RING_BYTES ); + + for ( i = 0; i < NUM_RX_DESC; i++ ) { + free_iob ( tp->rx_iobuf[i] ); + tp->rx_iobuf[i] = NULL; + } +} + +/** + FIXME: Because gPXE's pci_device_id structure does not contain a + field to contain arbitrary data, we need the following table to + associate PCI IDs with nic variants, because a lot of driver + routines depend on knowing which kind of variant they are dealing + with. --mdc + **/ + +#define _R(VENDOR,DEVICE,INDEX) \ + { .vendor = VENDOR, .device = DEVICE, .index = INDEX } + +static const struct { + uint16_t vendor; + uint16_t device; + int index; +} nic_variant_table[] = { + _R(0x10ec, 0x8129, RTL_CFG_0), + _R(0x10ec, 0x8136, RTL_CFG_2), + _R(0x10ec, 0x8167, RTL_CFG_0), + _R(0x10ec, 0x8168, RTL_CFG_1), + _R(0x10ec, 0x8169, RTL_CFG_0), + _R(0x1186, 0x4300, RTL_CFG_0), + _R(0x1259, 0xc107, RTL_CFG_0), + _R(0x16ec, 0x0116, RTL_CFG_0), + _R(0x1737, 0x1032, RTL_CFG_0), + _R(0x0001, 0x8168, RTL_CFG_2), +}; +#undef _R + +static int +rtl8169_get_nic_variant ( uint16_t vendor, uint16_t device ) +{ + u32 i; + + DBGP ( "rtl8169_get_nic_variant\n" ); + + for (i = 0; i < ARRAY_SIZE(nic_variant_table); i++) { + if ( ( nic_variant_table[i].vendor == vendor ) && + ( nic_variant_table[i].device == device ) ) { + return ( nic_variant_table[i].index ); + } + } + DBG ( "No matching NIC variant found!\n" ); + return ( RTL_CFG_0 ); +} + +static void rtl8169_irq_enable ( struct rtl8169_private *tp ) +{ + void *ioaddr = tp->mmio_addr; + + DBGP ( "rtl8169_irq_enable\n" ); + + RTL_W16 ( IntrMask, tp->intr_event ); +} + +static void rtl8169_irq_disable ( struct rtl8169_private *tp ) +{ + void *ioaddr = tp->mmio_addr; + + DBGP ( "rtl8169_irq_disable\n" ); + + rtl8169_irq_mask_and_ack ( ioaddr ); +} + +/*** gPXE Core API Routines ***/ + +/** + * open - Called when a network interface is made active + * + * @v netdev network interface device structure + * @ret rc Return status code, 0 on success, negative value on failure + * + **/ +static int +rtl8169_open ( struct net_device *netdev ) +{ + struct rtl8169_private *tp = netdev_priv ( netdev ); + void *ioaddr = tp->mmio_addr; + int rc; + + DBGP ( "rtl8169_open\n" ); + + /* allocate transmit descriptors */ + rc = rtl8169_setup_tx_resources ( tp ); + if ( rc ) { + DBG ( "Error setting up TX resources!\n" ); + goto err_setup_tx; + } + + /* allocate receive descriptors */ + rc = rtl8169_setup_rx_resources ( tp ); + if ( rc ) { + DBG ( "Error setting up RX resources!\n" ); + goto err_setup_rx; + } + + rtl_hw_start ( netdev ); + + DBG ( "TxDescStartAddrHigh = %#08lx\n", RTL_R32 ( TxDescStartAddrHigh ) ); + DBG ( "TxDescStartAddrLow = %#08lx\n", RTL_R32 ( TxDescStartAddrLow ) ); + DBG ( "RxDescAddrHigh = %#08lx\n", RTL_R32 ( RxDescAddrHigh ) ); + DBG ( "RxDescAddrLow = %#08lx\n", RTL_R32 ( RxDescAddrLow ) ); + + return 0; + +err_setup_rx: + rtl8169_free_tx_resources ( tp ); +err_setup_tx: + rtl8169_hw_reset ( ioaddr ); + + return rc; +} + +/** + * transmit - Transmit a packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * + * @ret rc Returns 0 on success, negative on failure + */ +static int +rtl8169_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) +{ + struct rtl8169_private *tp = netdev_priv ( netdev ); + void *ioaddr = tp->mmio_addr; + uint32_t tx_len = iob_len ( iobuf ); + + struct TxDesc *tx_curr_desc; + + DBGP ("rtl8169_transmit\n"); + + if ( tp->tx_fill_ctr == NUM_TX_DESC ) { + DBG ("TX overflow\n"); + return -ENOBUFS; + } + + /** + * The rtl8169 family automatically pads short packets to a + * minimum size, but if it did not, like some older cards, + * we could do: + * iob_pad ( iobuf, ETH_ZLEN ); + */ + + /* Save pointer to this iobuf we have been given to transmit so + we can pass it to netdev_tx_complete() later */ + tp->tx_iobuf[tp->tx_curr] = iobuf; + + tx_curr_desc = tp->tx_base + tp->tx_curr; + + DBG ( "tp->tx_fill_ctr = %ld\n", tp->tx_fill_ctr ); + DBG ( "tp->tx_curr = %ld\n", tp->tx_curr ); + DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) ); + DBG ( "iobuf->data = %#08lx\n", virt_to_bus ( iobuf->data ) ); + DBG ( "tx_len = %ld\n", tx_len ); + + /* Configure current descriptor to transmit supplied packet */ + tx_curr_desc->addr_hi = 0; + tx_curr_desc->addr_lo = virt_to_bus ( iobuf->data ); + tx_curr_desc->opts2 = 0; + tx_curr_desc->opts1 = FirstFrag | LastFrag | + ( tp->tx_curr == ( NUM_TX_DESC - 1 ) ? RingEnd : 0 ) | + tx_len; + + /* Mark descriptor as owned by NIC */ + tx_curr_desc->opts1 |= DescOwn; + + DBG ( "tx_curr_desc->opts1 = %#08lx\n", tx_curr_desc->opts1 ); + DBG ( "tx_curr_desc->opts2 = %#08lx\n", tx_curr_desc->opts2 ); + DBG ( "tx_curr_desc->addr_hi = %#08lx\n", tx_curr_desc->addr_hi ); + DBG ( "tx_curr_desc->addr_lo = %#08lx\n", tx_curr_desc->addr_lo ); + + RTL_W8 ( TxPoll, NPQ ); /* set polling bit */ + + /* Point to next free descriptor */ + tp->tx_curr = ( tp->tx_curr + 1 ) % NUM_TX_DESC; + + /* Increment number of tx descriptors in use */ + tp->tx_fill_ctr++; + + return 0; +} + +/** + * poll - Poll for received packets + * + * @v netdev Network device + */ +static void +rtl8169_poll ( struct net_device *netdev ) +{ + struct rtl8169_private *tp = netdev_priv ( netdev ); + void *ioaddr = tp->mmio_addr; + + uint16_t intr_status; + uint16_t intr_mask; + + DBGP ( "rtl8169_poll\n" ); + + intr_status = RTL_R16 ( IntrStatus ); + intr_mask = RTL_R16 ( IntrMask ); + + DBG2 ( "rtl8169_poll (before): intr_mask = %#04x intr_status = %#04x\n", + intr_mask, intr_status ); + + RTL_W16 ( IntrStatus, 0xffff ); + + /* hotplug / major error / no more work / shared irq */ + if ( intr_status == 0xffff ) + return; + + /* Process transmitted packets */ + rtl8169_process_tx_packets ( netdev ); + + /* Process received packets */ + rtl8169_process_rx_packets ( netdev ); +} + +/** + * close - Disable network interface + * + * @v netdev network interface device structure + * + **/ +static void +rtl8169_close ( struct net_device *netdev ) +{ + struct rtl8169_private *tp = netdev_priv ( netdev ); + void *ioaddr = tp->mmio_addr; + + DBGP ( "r8169_close\n" ); + + rtl8169_hw_reset ( ioaddr ); + + rtl8169_free_tx_resources ( tp ); + rtl8169_free_rx_resources ( tp ); +} + +/** + * irq - enable or Disable interrupts + * + * @v netdev network adapter + * @v action requested interrupt action + * + **/ +static void +rtl8169_irq ( struct net_device *netdev, int action ) +{ + struct rtl8169_private *tp = netdev_priv ( netdev ); + + DBGP ( "rtl8169_irq\n" ); + + switch ( action ) { + case 0 : + rtl8169_irq_disable ( tp ); + break; + default : + rtl8169_irq_enable ( tp ); + break; + } +} + +static struct net_device_operations rtl8169_operations = { + .open = rtl8169_open, + .transmit = rtl8169_transmit, + .poll = rtl8169_poll, + .close = rtl8169_close, + .irq = rtl8169_irq, +}; + +/** + * probe - Initial configuration of NIC + * + * @v pci PCI device + * @v id PCI IDs + * + * @ret rc Return status code + **/ +static int +rtl8169_probe ( struct pci_device *pdev, const struct pci_device_id *ent ) +{ + int i, rc; + struct net_device *netdev; + struct rtl8169_private *tp; + void *ioaddr; + + /** FIXME: This lookup is necessary because gPXE does not have a "data" + element in the structure pci_device_id which can pass an arbitrary + piece of data to the driver. It might be useful to add it. Then we + could just use ent->data instead of having to look up cfg_index. + **/ + int cfg_index = rtl8169_get_nic_variant ( ent->vendor, ent->device ); + const struct rtl_cfg_info *cfg = rtl_cfg_infos + cfg_index; + + DBGP ( "rtl8169_probe\n" ); + + DBG ( "ent->vendor = %#04x, ent->device = %#04x\n", ent->vendor, ent->device ); + + DBG ( "cfg_index = %d\n", cfg_index ); + DBG ( "cfg->intr_event = %#04x\n", cfg->intr_event ); + + rc = -ENOMEM; + + /* Allocate net device ( also allocates memory for netdev->priv + and makes netdev-priv point to it ) + */ + netdev = alloc_etherdev ( sizeof ( *tp ) ); + + if ( ! netdev ) + goto err_alloc_etherdev; + + /* Associate driver-specific network operations with + generic network device layer + */ + netdev_init ( netdev, &rtl8169_operations ); + + /* Associate this network device with the given PCI device */ + pci_set_drvdata ( pdev, netdev ); + netdev->dev = &pdev->dev; + + /* Initialize driver private storage */ + tp = netdev_priv ( netdev ); + memset ( tp, 0, ( sizeof ( *tp ) ) ); + + tp->pci_dev = pdev; + tp->irqno = pdev->irq; + tp->netdev = netdev; + tp->cfg_index = cfg_index; + tp->intr_event = cfg->intr_event; + tp->cp_cmd = PCIMulRW; + + tp->hw_start = cfg->hw_start; + + rc = -EIO; + + adjust_pci_device ( pdev ); + + /* ioremap MMIO region */ + ioaddr = ioremap ( pdev->membase, R8169_REGS_SIZE ); + + if ( ! ioaddr ) { + DBG ( "cannot remap MMIO\n" ); + rc = -EIO; + goto err_ioremap; + } + + tp->mmio_addr = ioaddr; + + tp->pcie_cap = pci_find_capability ( pdev, PCI_CAP_ID_EXP ); + if ( tp->pcie_cap ) { + DBG ( "PCI Express capability\n" ); + } else { + DBG ( "No PCI Express capability\n" ); + } + + /* Mask interrupts just in case */ + rtl8169_irq_mask_and_ack ( ioaddr ); + + /* Soft reset NIC */ + rtl_soft_reset ( netdev ); + + /* Identify chip attached to board */ + rtl8169_get_mac_version ( tp, ioaddr ); + + for ( i = 0; (u32) i < ARRAY_SIZE ( rtl_chip_info ); i++ ) { + if ( tp->mac_version == rtl_chip_info[i].mac_version ) + break; + } + if ( i == ARRAY_SIZE(rtl_chip_info ) ) { + /* Unknown chip: assume array element #0, original RTL-8169 */ + DBG ( "Unknown chip version, assuming %s\n", rtl_chip_info[0].name ); + i = 0; + } + tp->chipset = i; + + if ((tp->mac_version <= RTL_GIGA_MAC_VER_06) && + (RTL_R8(PHYstatus) & TBI_Enable)) { + tp->set_speed = rtl8169_set_speed_tbi; + tp->phy_reset_enable = rtl8169_tbi_reset_enable; + tp->phy_reset_pending = rtl8169_tbi_reset_pending; + tp->link_ok = rtl8169_tbi_link_ok; + + tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */ + } else { + tp->set_speed = rtl8169_set_speed_xmii; + tp->phy_reset_enable = rtl8169_xmii_reset_enable; + tp->phy_reset_pending = rtl8169_xmii_reset_pending; + tp->link_ok = rtl8169_xmii_link_ok; + } + + /* Get MAC address */ + for ( i = 0; i < MAC_ADDR_LEN; i++ ) + netdev->ll_addr[i] = RTL_R8 ( MAC0 + i ); + + DBG ( "%s\n", eth_ntoa ( netdev->ll_addr ) ); + + rtl8169_init_phy ( netdev, tp ); + + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register; + + /* Mark as link up; we don't yet handle link state */ + netdev_link_up ( netdev ); + + DBG ( "rtl8169_probe succeeded!\n" ); + + /* No errors, return success */ + return 0; + +/* Error return paths */ +err_register: +err_ioremap: + netdev_put ( netdev ); +err_alloc_etherdev: + return rc; +} + +/** + * remove - Device Removal Routine + * + * @v pdev PCI device information struct + * + **/ +static void +rtl8169_remove ( struct pci_device *pdev ) +{ + struct net_device *netdev = pci_get_drvdata ( pdev ); + struct rtl8169_private *tp = netdev_priv ( netdev ); + void *ioaddr = tp->mmio_addr; + + DBGP ( "rtl8169_remove\n" ); + + rtl8169_hw_reset ( ioaddr ); + + unregister_netdev ( netdev ); + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +static struct pci_device_id rtl8169_nics[] = { + PCI_ROM(0x10ec, 0x8129, "rtl8169-0x8129", "rtl8169-0x8129"), + PCI_ROM(0x10ec, 0x8136, "rtl8169-0x8136", "rtl8169-0x8136"), + PCI_ROM(0x10ec, 0x8167, "rtl8169-0x8167", "rtl8169-0x8167"), + PCI_ROM(0x10ec, 0x8168, "rtl8169-0x8168", "rtl8169-0x8168"), + PCI_ROM(0x10ec, 0x8169, "rtl8169-0x8169", "rtl8169-0x8169"), + PCI_ROM(0x1186, 0x4300, "rtl8169-0x4300", "rtl8169-0x4300"), + PCI_ROM(0x1259, 0xc107, "rtl8169-0xc107", "rtl8169-0xc107"), + PCI_ROM(0x16ec, 0x0116, "rtl8169-0x0116", "rtl8169-0x0116"), + PCI_ROM(0x1737, 0x1032, "rtl8169-0x1032", "rtl8169-0x1032"), + PCI_ROM(0x0001, 0x8168, "rtl8169-0x8168", "rtl8169-0x8168"), +}; + +struct pci_driver rtl8169_driver __pci_driver = { + .ids = rtl8169_nics, + .id_count = ( sizeof ( rtl8169_nics ) / sizeof ( rtl8169_nics[0] ) ), + .probe = rtl8169_probe, + .remove = rtl8169_remove, +}; /* * Local variables: diff --git a/gpxe/src/drivers/net/r8169.h b/gpxe/src/drivers/net/r8169.h new file mode 100644 index 00000000..d3536326 --- /dev/null +++ b/gpxe/src/drivers/net/r8169.h @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2008 Marty Connor + * 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 + * Copyright (c) 2003 - 2007 Francois Romieu + * Copyright (c) a lot of people too. Please respect their work. + * + */ + +#ifndef _R8169_H_ +#define _R8169_H_ + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +/** FIXME: include/linux/pci_regs.h has these PCI regs, maybe + we need such a file in gPXE? +**/ +#define PCI_EXP_DEVCTL 8 /* Device Control */ +#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ +#define PCI_EXP_LNKCTL 16 /* Link Control */ +#define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */ +#define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */ + +/** FIXME: update mii.h in src/include/mii.h from Linux sources + so we don't have to include these definitiions. +**/ +/* The forced speed, 10Mb, 100Mb, gigabit, 2.5Gb, 10GbE. */ +#define SPEED_10 10 +#define SPEED_100 100 +#define SPEED_1000 1000 +#define SPEED_2500 2500 +#define SPEED_10000 10000 + +/* Duplex, half or full. */ +#define DUPLEX_HALF 0x00 +#define DUPLEX_FULL 0x01 + +/* Generic MII registers. */ + +#define MII_BMCR 0x00 /* Basic mode control register */ +#define MII_BMSR 0x01 /* Basic mode status register */ +#define MII_PHYSID1 0x02 /* PHYS ID 1 */ +#define MII_PHYSID2 0x03 /* PHYS ID 2 */ +#define MII_ADVERTISE 0x04 /* Advertisement control reg */ +#define MII_LPA 0x05 /* Link partner ability reg */ +#define MII_EXPANSION 0x06 /* Expansion register */ +#define MII_CTRL1000 0x09 /* 1000BASE-T control */ +#define MII_STAT1000 0x0a /* 1000BASE-T status */ +#define MII_ESTATUS 0x0f /* Extended Status */ +#define MII_DCOUNTER 0x12 /* Disconnect counter */ +#define MII_FCSCOUNTER 0x13 /* False carrier counter */ +#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */ +#define MII_RERRCOUNTER 0x15 /* Receive error counter */ +#define MII_SREVISION 0x16 /* Silicon revision */ +#define MII_RESV1 0x17 /* Reserved... */ +#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */ +#define MII_PHYADDR 0x19 /* PHY address */ +#define MII_RESV2 0x1a /* Reserved... */ +#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */ +#define MII_NCONFIG 0x1c /* Network interface config */ + +/* Basic mode control register. */ +#define BMCR_RESV 0x003f /* Unused... */ +#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */ +#define BMCR_CTST 0x0080 /* Collision test */ +#define BMCR_FULLDPLX 0x0100 /* Full duplex */ +#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */ +#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */ +#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */ +#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */ +#define BMCR_SPEED100 0x2000 /* Select 100Mbps */ +#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */ +#define BMCR_RESET 0x8000 /* Reset the DP83840 */ + +/* Basic mode status register. */ +#define BMSR_ERCAP 0x0001 /* Ext-reg capability */ +#define BMSR_JCD 0x0002 /* Jabber detected */ +#define BMSR_LSTATUS 0x0004 /* Link status */ +#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */ +#define BMSR_RFAULT 0x0010 /* Remote fault detected */ +#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */ +#define BMSR_RESV 0x00c0 /* Unused... */ +#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */ +#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */ +#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */ +#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */ +#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */ +#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */ +#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */ +#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */ + +#define AUTONEG_DISABLE 0x00 +#define AUTONEG_ENABLE 0x01 + +#define MII_ADVERTISE 0x04 /* Advertisement control reg */ +#define ADVERTISE_SLCT 0x001f /* Selector bits */ +#define ADVERTISE_CSMA 0x0001 /* Only selector supported */ +#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ +#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */ +#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ +#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */ +#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ +#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */ +#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ +#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */ +#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ +#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ +#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */ +#define ADVERTISE_RESV 0x1000 /* Unused... */ +#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */ +#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */ +#define ADVERTISE_NPAGE 0x8000 /* Next page bit */ +#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \ + ADVERTISE_CSMA) +#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \ + ADVERTISE_100HALF | ADVERTISE_100FULL) + +/* 1000BASE-T Control register */ +#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */ +#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */ + +/* MAC address length */ +#define MAC_ADDR_LEN 6 + +#define MAX_READ_REQUEST_SHIFT 12 +#define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */ +#define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ +#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ +#define EarlyTxThld 0x3F /* 0x3F means NO early transmit */ +#define RxPacketMaxSize 0x3FE8 /* 16K - 1 - ETH_HLEN - VLAN - CRC... */ +#define SafeMtu 0x1c20 /* ... actually life sucks beyond ~7k */ +#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ + +#define R8169_REGS_SIZE 256 +#define R8169_NAPI_WEIGHT 64 +#define NUM_TX_DESC 8 /* Number of Tx descriptor registers */ +#define NUM_RX_DESC 8 /* Number of Rx descriptor registers */ +#define RX_BUF_SIZE 1536 /* Rx Buffer size */ +#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc)) +#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc)) + +#define TX_RING_ALIGN 256 +#define RX_RING_ALIGN 256 + +#define RTL8169_TX_TIMEOUT (6*HZ) +#define RTL8169_PHY_TIMEOUT (10*HZ) + +#define RTL_EEPROM_SIG cpu_to_le32(0x8129) +#define RTL_EEPROM_SIG_MASK cpu_to_le32(0xffff) +#define RTL_EEPROM_SIG_ADDR 0x0000 + +/* write/read MMIO register */ +#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg)) +#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg)) +#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg)) +#define RTL_R8(reg) readb (ioaddr + (reg)) +#define RTL_R16(reg) readw (ioaddr + (reg)) +#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg))) + +enum mac_version { + RTL_GIGA_MAC_VER_01 = 0x01, // 8169 + RTL_GIGA_MAC_VER_02 = 0x02, // 8169S + RTL_GIGA_MAC_VER_03 = 0x03, // 8110S + RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB + RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd + RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe + RTL_GIGA_MAC_VER_07 = 0x07, // 8102e + RTL_GIGA_MAC_VER_08 = 0x08, // 8102e + RTL_GIGA_MAC_VER_09 = 0x09, // 8102e + RTL_GIGA_MAC_VER_10 = 0x0a, // 8101e + RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb + RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be + RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb + RTL_GIGA_MAC_VER_14 = 0x0e, // 8101 ? + RTL_GIGA_MAC_VER_15 = 0x0f, // 8101 ? + RTL_GIGA_MAC_VER_16 = 0x11, // 8101Ec + RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf + RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP + RTL_GIGA_MAC_VER_19 = 0x13, // 8168C + RTL_GIGA_MAC_VER_20 = 0x14, // 8168C + RTL_GIGA_MAC_VER_21 = 0x15, // 8168C + RTL_GIGA_MAC_VER_22 = 0x16, // 8168C + RTL_GIGA_MAC_VER_23 = 0x17, // 8168CP + RTL_GIGA_MAC_VER_24 = 0x18, // 8168CP + RTL_GIGA_MAC_VER_25 = 0x19, // 8168D +}; + +#define _R(NAME,MAC,MASK) \ + { .name = NAME, .mac_version = MAC, .RxConfigMask = MASK } + +static const struct { + const char *name; + u8 mac_version; + u32 RxConfigMask; /* Clears the bits supported by this chip */ +} rtl_chip_info[] = { + _R("RTL8169", RTL_GIGA_MAC_VER_01, 0xff7e1880), // 8169 + _R("RTL8169s", RTL_GIGA_MAC_VER_02, 0xff7e1880), // 8169S + _R("RTL8110s", RTL_GIGA_MAC_VER_03, 0xff7e1880), // 8110S + _R("RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880), // 8169SB + _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_05, 0xff7e1880), // 8110SCd + _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_06, 0xff7e1880), // 8110SCe + _R("RTL8102e", RTL_GIGA_MAC_VER_07, 0xff7e1880), // PCI-E + _R("RTL8102e", RTL_GIGA_MAC_VER_08, 0xff7e1880), // PCI-E + _R("RTL8102e", RTL_GIGA_MAC_VER_09, 0xff7e1880), // PCI-E + _R("RTL8101e", RTL_GIGA_MAC_VER_10, 0xff7e1880), // PCI-E + _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_11, 0xff7e1880), // PCI-E + _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E + _R("RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139 + _R("RTL8100e", RTL_GIGA_MAC_VER_14, 0xff7e1880), // PCI-E 8139 + _R("RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880), // PCI-E 8139 + _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_17, 0xff7e1880), // PCI-E + _R("RTL8101e", RTL_GIGA_MAC_VER_16, 0xff7e1880), // PCI-E + _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_18, 0xff7e1880), // PCI-E + _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_19, 0xff7e1880), // PCI-E + _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_20, 0xff7e1880), // PCI-E + _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_21, 0xff7e1880), // PCI-E + _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_22, 0xff7e1880), // PCI-E + _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_23, 0xff7e1880), // PCI-E + _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_24, 0xff7e1880), // PCI-E + _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_25, 0xff7e1880) // PCI-E +}; +#undef _R + +enum cfg_version { + RTL_CFG_0 = 0x00, + RTL_CFG_1, + RTL_CFG_2 +}; + +#if 0 +/** Device Table from Linux Driver **/ +static struct pci_device_id rtl8169_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), 0, 0, RTL_CFG_0 }, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), 0, 0, RTL_CFG_2 }, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), 0, 0, RTL_CFG_0 }, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_1 }, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 }, + { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), 0, 0, RTL_CFG_0 }, + { PCI_DEVICE(PCI_VENDOR_ID_AT, 0xc107), 0, 0, RTL_CFG_0 }, + { PCI_DEVICE(0x16ec, 0x0116), 0, 0, RTL_CFG_0 }, + { PCI_VENDOR_ID_LINKSYS, 0x1032, + PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 }, + { 0x0001, 0x8168, + PCI_ANY_ID, 0x2410, 0, 0, RTL_CFG_2 }, + {0,}, +}; +#endif + +enum rtl_registers { + MAC0 = 0, /* Ethernet hardware address. */ + MAC4 = 4, + MAR0 = 8, /* Multicast filter. */ + CounterAddrLow = 0x10, + CounterAddrHigh = 0x14, + TxDescStartAddrLow = 0x20, + TxDescStartAddrHigh = 0x24, + TxHDescStartAddrLow = 0x28, + TxHDescStartAddrHigh = 0x2c, + FLASH = 0x30, + ERSR = 0x36, + ChipCmd = 0x37, + TxPoll = 0x38, + IntrMask = 0x3c, + IntrStatus = 0x3e, + TxConfig = 0x40, + RxConfig = 0x44, + RxMissed = 0x4c, + Cfg9346 = 0x50, + Config0 = 0x51, + Config1 = 0x52, + Config2 = 0x53, + Config3 = 0x54, + Config4 = 0x55, + Config5 = 0x56, + MultiIntr = 0x5c, + PHYAR = 0x60, + PHYstatus = 0x6c, + RxMaxSize = 0xda, + CPlusCmd = 0xe0, + IntrMitigate = 0xe2, + RxDescAddrLow = 0xe4, + RxDescAddrHigh = 0xe8, + EarlyTxThres = 0xec, + FuncEvent = 0xf0, + FuncEventMask = 0xf4, + FuncPresetState = 0xf8, + FuncForceEvent = 0xfc, +}; + +enum rtl8110_registers { + TBICSR = 0x64, + TBI_ANAR = 0x68, + TBI_LPAR = 0x6a, +}; + +enum rtl8168_8101_registers { + CSIDR = 0x64, + CSIAR = 0x68, +#define CSIAR_FLAG 0x80000000 +#define CSIAR_WRITE_CMD 0x80000000 +#define CSIAR_BYTE_ENABLE 0x0f +#define CSIAR_BYTE_ENABLE_SHIFT 12 +#define CSIAR_ADDR_MASK 0x0fff + + EPHYAR = 0x80, +#define EPHYAR_FLAG 0x80000000 +#define EPHYAR_WRITE_CMD 0x80000000 +#define EPHYAR_REG_MASK 0x1f +#define EPHYAR_REG_SHIFT 16 +#define EPHYAR_DATA_MASK 0xffff + DBG_REG = 0xd1, +#define FIX_NAK_1 (1 << 4) +#define FIX_NAK_2 (1 << 3) +}; + +enum rtl_register_content { + /* InterruptStatusBits */ + SYSErr = 0x8000, + PCSTimeout = 0x4000, + SWInt = 0x0100, + TxDescUnavail = 0x0080, + RxFIFOOver = 0x0040, + LinkChg = 0x0020, + RxOverflow = 0x0010, + TxErr = 0x0008, + TxOK = 0x0004, + RxErr = 0x0002, + RxOK = 0x0001, + + /* RxStatusDesc */ + RxFOVF = (1 << 23), + RxRWT = (1 << 22), + RxRES = (1 << 21), + RxRUNT = (1 << 20), + RxCRC = (1 << 19), + + /* ChipCmdBits */ + CmdReset = 0x10, + CmdRxEnb = 0x08, + CmdTxEnb = 0x04, + RxBufEmpty = 0x01, + + /* TXPoll register p.5 */ + HPQ = 0x80, /* Poll cmd on the high prio queue */ + NPQ = 0x40, /* Poll cmd on the low prio queue */ + FSWInt = 0x01, /* Forced software interrupt */ + + /* Cfg9346Bits */ + Cfg9346_Lock = 0x00, + Cfg9346_Unlock = 0xc0, + + /* rx_mode_bits */ + AcceptErr = 0x20, + AcceptRunt = 0x10, + AcceptBroadcast = 0x08, + AcceptMulticast = 0x04, + AcceptMyPhys = 0x02, + AcceptAllPhys = 0x01, + + /* RxConfigBits */ + RxCfgFIFOShift = 13, + RxCfgDMAShift = 8, + + /* TxConfigBits */ + TxInterFrameGapShift = 24, + TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ + + /* Config1 register p.24 */ + LEDS1 = (1 << 7), + LEDS0 = (1 << 6), + MSIEnable = (1 << 5), /* Enable Message Signaled Interrupt */ + Speed_down = (1 << 4), + MEMMAP = (1 << 3), + IOMAP = (1 << 2), + VPD = (1 << 1), + PMEnable = (1 << 0), /* Power Management Enable */ + + /* Config2 register p. 25 */ + PCI_Clock_66MHz = 0x01, + PCI_Clock_33MHz = 0x00, + + /* Config3 register p.25 */ + MagicPacket = (1 << 5), /* Wake up when receives a Magic Packet */ + LinkUp = (1 << 4), /* Wake up when the cable connection is re-established */ + Beacon_en = (1 << 0), /* 8168 only. Reserved in the 8168b */ + + /* Config5 register p.27 */ + BWF = (1 << 6), /* Accept Broadcast wakeup frame */ + MWF = (1 << 5), /* Accept Multicast wakeup frame */ + UWF = (1 << 4), /* Accept Unicast wakeup frame */ + LanWake = (1 << 1), /* LanWake enable/disable */ + PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */ + + /* TBICSR p.28 */ + TBIReset = 0x80000000, + TBILoopback = 0x40000000, + TBINwEnable = 0x20000000, + TBINwRestart = 0x10000000, + TBILinkOk = 0x02000000, + TBINwComplete = 0x01000000, + + /* CPlusCmd p.31 */ + EnableBist = (1 << 15), // 8168 8101 + Mac_dbgo_oe = (1 << 14), // 8168 8101 + Normal_mode = (1 << 13), // unused + Force_half_dup = (1 << 12), // 8168 8101 + Force_rxflow_en = (1 << 11), // 8168 8101 + Force_txflow_en = (1 << 10), // 8168 8101 + Cxpl_dbg_sel = (1 << 9), // 8168 8101 + ASF = (1 << 8), // 8168 8101 + PktCntrDisable = (1 << 7), // 8168 8101 + Mac_dbgo_sel = 0x001c, // 8168 + RxVlan = (1 << 6), + RxChkSum = (1 << 5), + PCIDAC = (1 << 4), + PCIMulRW = (1 << 3), + INTT_0 = 0x0000, // 8168 + INTT_1 = 0x0001, // 8168 + INTT_2 = 0x0002, // 8168 + INTT_3 = 0x0003, // 8168 + + /* rtl8169_PHYstatus */ + TBI_Enable = 0x80, + TxFlowCtrl = 0x40, + RxFlowCtrl = 0x20, + _1000bpsF = 0x10, + _100bps = 0x08, + _10bps = 0x04, + LinkStatus = 0x02, + FullDup = 0x01, + + /* _TBICSRBit */ + TBILinkOK = 0x02000000, + + /* DumpCounterCommand */ + CounterDump = 0x8, +}; + +enum desc_status_bit { + DescOwn = (1 << 31), /* Descriptor is owned by NIC */ + RingEnd = (1 << 30), /* End of descriptor ring */ + FirstFrag = (1 << 29), /* First segment of a packet */ + LastFrag = (1 << 28), /* Final segment of a packet */ + + /* Tx private */ + LargeSend = (1 << 27), /* TCP Large Send Offload (TSO) */ + MSSShift = 16, /* MSS value position */ + MSSMask = 0xfff, /* MSS value + LargeSend bit: 12 bits */ + IPCS = (1 << 18), /* Calculate IP checksum */ + UDPCS = (1 << 17), /* Calculate UDP/IP checksum */ + TCPCS = (1 << 16), /* Calculate TCP/IP checksum */ + TxVlanTag = (1 << 17), /* Add VLAN tag */ + + /* Rx private */ + PID1 = (1 << 18), /* Protocol ID bit 1/2 */ + PID0 = (1 << 17), /* Protocol ID bit 2/2 */ + +#define RxProtoUDP (PID1) +#define RxProtoTCP (PID0) +#define RxProtoIP (PID1 | PID0) +#define RxProtoMask RxProtoIP + + IPFail = (1 << 16), /* IP checksum failed */ + UDPFail = (1 << 15), /* UDP/IP checksum failed */ + TCPFail = (1 << 14), /* TCP/IP checksum failed */ + RxVlanTag = (1 << 16), /* VLAN tag available */ +}; + +#define RsvdMask 0x3fffc000 + +struct TxDesc { + volatile uint32_t opts1; + volatile uint32_t opts2; + volatile uint32_t addr_lo; + volatile uint32_t addr_hi; +}; + +struct RxDesc { + volatile uint32_t opts1; + volatile uint32_t opts2; + volatile uint32_t addr_lo; + volatile uint32_t addr_hi; +}; + +enum features { + RTL_FEATURE_WOL = (1 << 0), + RTL_FEATURE_MSI = (1 << 1), + RTL_FEATURE_GMII = (1 << 2), +}; + +static void rtl_hw_start_8169(struct net_device *); +static void rtl_hw_start_8168(struct net_device *); +static void rtl_hw_start_8101(struct net_device *); + +struct rtl8169_private { + + struct pci_device *pci_dev; + struct net_device *netdev; + uint8_t *hw_addr; + void *mmio_addr; + uint32_t irqno; + + int chipset; + int mac_version; + int cfg_index; + u16 intr_event; + + struct io_buffer *tx_iobuf[NUM_TX_DESC]; + struct io_buffer *rx_iobuf[NUM_RX_DESC]; + + struct TxDesc *tx_base; + struct RxDesc *rx_base; + + uint32_t tx_curr; + uint32_t rx_curr; + + uint32_t tx_tail; + + uint32_t tx_fill_ctr; + + u16 cp_cmd; + + int phy_auto_nego_reg; + int phy_1000_ctrl_reg; + + int ( *set_speed ) (struct net_device *, u8 autoneg, u16 speed, u8 duplex ); + void ( *phy_reset_enable ) ( void *ioaddr ); + void ( *hw_start ) ( struct net_device * ); + unsigned int ( *phy_reset_pending ) ( void *ioaddr ); + unsigned int ( *link_ok ) ( void *ioaddr ); + + int pcie_cap; + + unsigned features; + +}; + +static const unsigned int rtl8169_rx_config = + (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); + +#endif /* _R8169_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * c-indent-level: 8 + * tab-width: 8 + * End: + */ diff --git a/gpxe/src/drivers/net/rtl8139.c b/gpxe/src/drivers/net/rtl8139.c index 509047a9..2dff324c 100644 --- a/gpxe/src/drivers/net/rtl8139.c +++ b/gpxe/src/drivers/net/rtl8139.c @@ -69,7 +69,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/gpxe/src/drivers/net/tg3.c b/gpxe/src/drivers/net/tg3.c index bda832e8..bcb9dda7 100644 --- a/gpxe/src/drivers/net/tg3.c +++ b/gpxe/src/drivers/net/tg3.c @@ -3399,6 +3399,7 @@ PCI_ROM(0x14e4, 0x1677, "tg3-5751", "Broadcom Tigon 3 5751"), PCI_ROM(0x14e4, 0x167a, "tg3-5754", "Broadcom Tigon 3 5754"), PCI_ROM(0x14e4, 0x1693, "tg3-5787", "Broadcom Tigon 3 5787"), PCI_ROM(0x14e4, 0x1696, "tg3-5782", "Broadcom Tigon 3 5782"), +PCI_ROM(0x14e4, 0x169a, "tg3-5786", "Broadcom Tigon 3 5786"), PCI_ROM(0x14e4, 0x169c, "tg3-5788", "Broadcom Tigon 3 5788"), PCI_ROM(0x14e4, 0x169d, "tg3-5789", "Broadcom Tigon 3 5789"), PCI_ROM(0x14e4, 0x16a6, "tg3-5702X", "Broadcom Tigon 3 5702X"), diff --git a/gpxe/src/drivers/net/via-rhine.c b/gpxe/src/drivers/net/via-rhine.c index fb43a924..201ebb08 100644 --- a/gpxe/src/drivers/net/via-rhine.c +++ b/gpxe/src/drivers/net/via-rhine.c @@ -784,7 +784,7 @@ ReadMII (int byMIIIndex, int ioaddr) char byMIIAdrbak; char byMIICRbak; char byMIItemp; - tick_t ct; + unsigned long ct; byMIIAdrbak = inb (byMIIAD); byMIICRbak = inb (byMIICR); @@ -800,7 +800,7 @@ ReadMII (int byMIIIndex, int ioaddr) byMIItemp = byMIItemp & 0x40; ct = currticks(); - while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks()) + while (byMIItemp != 0 && ct + 2*1000 < currticks()) { byMIItemp = inb (byMIICR); byMIItemp = byMIItemp & 0x40; @@ -825,7 +825,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr) char byMIIAdrbak; char byMIICRbak; char byMIItemp; - tick_t ct; + unsigned long ct; byMIIAdrbak = inb (byMIIAD); @@ -842,7 +842,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr) byMIItemp = byMIItemp & 0x40; ct = currticks(); - while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks()) + while (byMIItemp != 0 && ct + 2*1000 < currticks()) { byMIItemp = inb (byMIICR); byMIItemp = byMIItemp & 0x40; @@ -872,7 +872,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr) byMIItemp = byMIItemp & 0x20; ct = currticks(); - while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks()) + while (byMIItemp != 0 && ct + 2*1000 < currticks()) { byMIItemp = inb (byMIICR); byMIItemp = byMIItemp & 0x20; @@ -1008,7 +1008,7 @@ rhine_probe1 (struct nic *nic, struct pci_device *pci, int ioaddr, int chip_id, unsigned char mode3_reg; if (rhine_debug > 0 && did_version++ == 0) - printf (version); + printf ("%s",version); // get revision id. pci_read_config_byte(pci, PCI_REVISION, &revision_id); @@ -1346,7 +1346,7 @@ rhine_transmit (struct nic *nic, unsigned char CR1bak; unsigned char CR0bak; unsigned int nstype; - tick_t ct; + unsigned long ct; /*printf ("rhine_transmit\n"); */ @@ -1390,7 +1390,7 @@ rhine_transmit (struct nic *nic, ct = currticks(); /* Wait until transmit is finished or timeout*/ while((tp->tx_ring[entry].tx_status.bits.own_bit !=0) && - ct + 10*USECS_IN_MSEC < currticks()) + ct + 10*1000 < currticks()) ; if(tp->tx_ring[entry].tx_status.bits.terr == 0) diff --git a/gpxe/src/drivers/net/virtio-net.c b/gpxe/src/drivers/net/virtio-net.c index 4ec154df..68c84d79 100644 --- a/gpxe/src/drivers/net/virtio-net.c +++ b/gpxe/src/drivers/net/virtio-net.c @@ -187,6 +187,8 @@ static int vring_get_buf(int queue_index, unsigned int *len) u32 id; int ret; + BUG_ON(!vring_more_used(queue_index)); + elem = &vr->used->ring[last_used_idx[queue_index] % vr->num]; wmb(); id = elem->id; @@ -365,6 +367,8 @@ static void virtnet_transmit(struct nic *nic, const char *destaddr, vring_add_buf(TX_INDEX, 0, 0); + vring_kick(nic, TX_INDEX, 1); + /* * http://www.etherboot.org/wiki/dev/devmanual * @@ -372,13 +376,11 @@ static void virtnet_transmit(struct nic *nic, const char *destaddr, * before returning from this routine" */ - while (vring_more_used(TX_INDEX)) { + while (!vring_more_used(TX_INDEX)) { mb(); udelay(10); } - vring_kick(nic, TX_INDEX, 1); - /* free desc */ (void)vring_get_buf(TX_INDEX, NULL); diff --git a/gpxe/src/drivers/net/w89c840.c b/gpxe/src/drivers/net/w89c840.c index 14497640..5abc0b35 100644 --- a/gpxe/src/drivers/net/w89c840.c +++ b/gpxe/src/drivers/net/w89c840.c @@ -112,7 +112,7 @@ static const char *w89c840_version = "driver Version 0.94 - December 12, 2003"; /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (10*USECS_IN_MSEC) +#define TX_TIMEOUT (10*1000) #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ @@ -486,7 +486,7 @@ static void w89c840_transmit( /* send the packet to destination */ unsigned entry; int transmit_status; - tick_t ct; + unsigned long ct; /* Caution: the write order is important here, set the field with the "ownership" bits last. */ diff --git a/gpxe/src/hci/commands/config_cmd.c b/gpxe/src/hci/commands/config_cmd.c index 660c6423..87abb05a 100644 --- a/gpxe/src/hci/commands/config_cmd.c +++ b/gpxe/src/hci/commands/config_cmd.c @@ -16,7 +16,7 @@ static int config_exec ( int argc, char **argv ) { } settings_name = ( ( argc == 2 ) ? argv[1] : "" ); - settings = find_settings ( argv[1] ); + settings = find_settings ( settings_name ); if ( ! settings ) { printf ( "No such scope \"%s\"\n", settings_name ); return 1; diff --git a/gpxe/src/image/efi_image.c b/gpxe/src/image/efi_image.c new file mode 100644 index 00000000..c80cd264 --- /dev/null +++ b/gpxe/src/image/efi_image.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2008 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 ); + +struct image_type efi_image_type __image_type ( PROBE_NORMAL ); + +/** + * Execute EFI image + * + * @v image EFI image + * @ret rc Return status code + */ +static int efi_image_exec ( struct image *image ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE handle; + UINTN exit_data_size; + CHAR16 *exit_data; + EFI_STATUS efirc; + + /* Attempt loading image */ + if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL, + user_to_virt ( image->data, 0 ), + image->len, &handle ) ) != 0 ) { + /* Not an EFI image */ + DBGC ( image, "EFIIMAGE %p could not load: %lx\n", + image, efirc ); + return -ENOEXEC; + } + + /* Start the image */ + if ( ( efirc = bs->StartImage ( handle, &exit_data_size, + &exit_data ) ) != 0 ) { + DBGC ( image, "EFIIMAGE %p returned with status %lx\n", + image, efirc ); + goto done; + } + + done: + /* Unload the image. We can't leave it loaded, because we + * have no "unload" operation. + */ + bs->UnloadImage ( handle ); + + return EFIRC_TO_RC ( efirc ); +} + +/** + * Load EFI image into memory + * + * @v image EFI file + * @ret rc Return status code + */ +static int efi_image_load ( struct image *image ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE handle; + EFI_STATUS efirc; + + /* Attempt loading image */ + if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL, + user_to_virt ( image->data, 0 ), + image->len, &handle ) ) != 0 ) { + /* Not an EFI image */ + DBGC ( image, "EFIIMAGE %p could not load: %lx\n", + image, efirc ); + return -ENOEXEC; + } + + /* This is an EFI image */ + if ( ! image->type ) + image->type = &efi_image_type; + + /* Unload the image. We can't leave it loaded, because we + * have no "unload" operation. + */ + bs->UnloadImage ( handle ); + + return 0; +} + +/** EFI image type */ +struct image_type efi_image_type __image_type ( PROBE_NORMAL ) = { + .name = "EFI", + .load = efi_image_load, + .exec = efi_image_exec, +}; diff --git a/gpxe/src/include/compiler.h b/gpxe/src/include/compiler.h index 8ab7b8ae..b6a6f8e2 100644 --- a/gpxe/src/include/compiler.h +++ b/gpxe/src/include/compiler.h @@ -131,11 +131,26 @@ extern void dbg_decolourise ( void ); extern void dbg_hex_dump_da ( unsigned long dispaddr, const void *data, unsigned long len ); -/* Compatibility with existing Makefile */ #if DEBUG_SYMBOL -#define DBGLVL DEBUG_SYMBOL +#define DBGLVL_MAX DEBUG_SYMBOL +#else +#define DBGLVL_MAX 0 +#endif + +/* Allow for selective disabling of enabled debug levels */ +#if DBGLVL_MAX +int __debug_disable; +#define DBGLVL ( DBGLVL_MAX & ~__debug_disable ) +#define DBG_DISABLE( level ) do { \ + __debug_disable |= ( (level) & DBGLVL_MAX ); \ + } while ( 0 ) +#define DBG_ENABLE( level ) do { \ + __debug_disable &= ~( (level) & DBGLVL_MAX ); \ + } while ( 0 ) #else #define DBGLVL 0 +#define DBG_DISABLE( level ) do { } while ( 0 ) +#define DBG_ENABLE( level ) do { } while ( 0 ) #endif #define DBGLVL_LOG 1 @@ -325,6 +340,9 @@ extern void dbg_hex_dump_da ( unsigned long dispaddr, /** Declare a data structure to be aligned with 16-byte alignment */ #define __aligned __attribute__ (( aligned ( 16 ) )) +/** Declare a function to be always inline */ +#define __always_inline __attribute__ (( always_inline )) + /** * Shared data. * diff --git a/gpxe/src/include/gpxe/api.h b/gpxe/src/include/gpxe/api.h new file mode 100644 index 00000000..df5d1ae3 --- /dev/null +++ b/gpxe/src/include/gpxe/api.h @@ -0,0 +1,82 @@ +#ifndef _GPXE_API_H +#define _GPXE_API_H + +/** @file + * + * gPXE internal APIs + * + * There are various formally-defined APIs internal to gPXE, with + * several differing implementations specific to particular execution + * environments (e.g. PC BIOS, EFI, LinuxBIOS). + * + */ + +/** @defgroup Single-implementation APIs + * + * These are APIs for which only a single implementation may be + * compiled in at any given time. + * + * @{ + */ + +/** + * Calculate function implementation name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + * + * The subsystem prefix should be an empty string for the currently + * selected subsystem, and should be a subsystem-unique string for all + * other subsystems. + */ +#define SINGLE_API_NAME( _prefix, _api_func ) _prefix ## _api_func + +/** + * Calculate static inline function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define SINGLE_API_INLINE( _prefix, _api_func ) \ + SINGLE_API_NAME ( _prefix, _api_func ) + +/** + * Provide an API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_SINGLE_API( _prefix, _api_func, _func ) \ + /* Ensure that _api_func exists */ \ + typeof ( _api_func ) _api_func; \ + /* Ensure that _func exists */ \ + typeof ( _func ) _func; \ + /* Ensure that _func is type-compatible with _api_func */ \ + typeof ( _api_func ) _func; \ + /* Ensure that _subsys_func is non-static */ \ + extern typeof ( _api_func ) SINGLE_API_NAME ( _prefix, _api_func ); \ + /* Provide symbol alias from _subsys_func to _func */ \ + typeof ( _api_func ) SINGLE_API_NAME ( _prefix, _api_func ) \ + __attribute__ (( alias ( #_func ) )); + +/** + * Provide a static inline API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_SINGLE_API_INLINE( _prefix, _api_func ) \ + /* Ensure that _api_func exists */ \ + typeof ( _api_func ) _api_func; \ + /* Ensure that _subsys_func exists and is static */ \ + static typeof ( SINGLE_API_INLINE ( _prefix, _api_func ) ) \ + SINGLE_API_INLINE ( _prefix, _api_func ); \ + /* Ensure that _subsys_func is type-compatible with _api_func */ \ + typeof ( _api_func ) SINGLE_API_INLINE ( _prefix, _api_func ); + +/** @} */ + +#endif /* _GPXE_API_H */ diff --git a/gpxe/src/include/gpxe/bitops.h b/gpxe/src/include/gpxe/bitops.h index f95af7d3..5405c854 100644 --- a/gpxe/src/include/gpxe/bitops.h +++ b/gpxe/src/include/gpxe/bitops.h @@ -1,27 +1,228 @@ #ifndef _GPXE_BITOPS_H #define _GPXE_BITOPS_H -/** @file +/* + * Copyright (C) 2008 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/** + * @file * * Bit operations + * */ #include +#include + +/* Endianness selection. + * + * This is a property of the NIC, not a property of the host CPU. + */ +#ifdef BITOPS_LITTLE_ENDIAN +#define cpu_to_BIT64 cpu_to_le64 +#define cpu_to_BIT32 cpu_to_le32 +#define BIT64_to_cpu le64_to_cpu +#define BIT32_to_cpu le32_to_cpu +#endif +#ifdef BITOPS_BIG_ENDIAN +#define cpu_to_BIT64 cpu_to_be64 +#define cpu_to_BIT32 cpu_to_be32 +#define BIT64_to_cpu be64_to_cpu +#define BIT32_to_cpu be32_to_cpu +#endif + +/** Datatype used to represent a bit in the pseudo-structures */ +typedef unsigned char pseudo_bit_t; + +/** + * Wrapper structure for pseudo_bit_t structures + * + * This structure provides a wrapper around pseudo_bit_t structures. + * It has the correct size, and also encapsulates type information + * about the underlying pseudo_bit_t-based structure, which allows the + * BIT_FILL() etc. macros to work without requiring explicit type + * information. + */ +#define PSEUDO_BIT_STRUCT( _structure ) \ + union { \ + uint8_t bytes[ sizeof ( _structure ) / 8 ]; \ + uint32_t dwords[ sizeof ( _structure ) / 32 ]; \ + uint64_t qwords[ sizeof ( _structure ) / 64 ]; \ + _structure *dummy[0]; \ + } u + +/** Get pseudo_bit_t structure type from wrapper structure pointer */ +#define PSEUDO_BIT_STRUCT_TYPE( _ptr ) \ + typeof ( *((_ptr)->u.dummy[0]) ) + +/** Bit offset of a field within a pseudo_bit_t structure */ +#define BIT_OFFSET( _ptr, _field ) \ + offsetof ( PSEUDO_BIT_STRUCT_TYPE ( _ptr ), _field ) + +/** Bit width of a field within a pseudo_bit_t structure */ +#define BIT_WIDTH( _ptr, _field ) \ + sizeof ( ( ( PSEUDO_BIT_STRUCT_TYPE ( _ptr ) * ) NULL )->_field ) + +/** Qword offset of a field within a pseudo_bit_t structure */ +#define QWORD_OFFSET( _ptr, _field ) \ + ( BIT_OFFSET ( _ptr, _field ) / 64 ) + +/** Qword bit offset of a field within a pseudo_bit_t structure */ +#define QWORD_BIT_OFFSET( _ptr, _index, _field ) \ + ( BIT_OFFSET ( _ptr, _field ) - ( 64 * (_index) ) ) + +/** Bit mask for a field within a pseudo_bit_t structure */ +#define BIT_MASK( _ptr, _field ) \ + ( ( ~( ( uint64_t ) 0 ) ) >> \ + ( 64 - BIT_WIDTH ( _ptr, _field ) ) ) + +/* + * Assemble native-endian qword from named fields and values + * + */ + +#define BIT_ASSEMBLE_1( _ptr, _index, _field, _value ) \ + ( ( ( uint64_t) (_value) ) << \ + QWORD_BIT_OFFSET ( _ptr, _index, _field ) ) + +#define BIT_ASSEMBLE_2( _ptr, _index, _field, _value, ... ) \ + ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \ + BIT_ASSEMBLE_1 ( _ptr, _index, __VA_ARGS__ ) ) + +#define BIT_ASSEMBLE_3( _ptr, _index, _field, _value, ... ) \ + ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \ + BIT_ASSEMBLE_2 ( _ptr, _index, __VA_ARGS__ ) ) + +#define BIT_ASSEMBLE_4( _ptr, _index, _field, _value, ... ) \ + ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \ + BIT_ASSEMBLE_3 ( _ptr, _index, __VA_ARGS__ ) ) + +#define BIT_ASSEMBLE_5( _ptr, _index, _field, _value, ... ) \ + ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \ + BIT_ASSEMBLE_4 ( _ptr, _index, __VA_ARGS__ ) ) + +#define BIT_ASSEMBLE_6( _ptr, _index, _field, _value, ... ) \ + ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \ + BIT_ASSEMBLE_5 ( _ptr, _index, __VA_ARGS__ ) ) + +#define BIT_ASSEMBLE_7( _ptr, _index, _field, _value, ... ) \ + ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \ + BIT_ASSEMBLE_6 ( _ptr, _index, __VA_ARGS__ ) ) + +/* + * Build native-endian (positive) qword bitmasks from named fields + * + */ + +#define BIT_MASK_1( _ptr, _index, _field ) \ + ( BIT_MASK ( _ptr, _field ) << \ + QWORD_BIT_OFFSET ( _ptr, _index, _field ) ) + +#define BIT_MASK_2( _ptr, _index, _field, ... ) \ + ( BIT_MASK_1 ( _ptr, _index, _field ) | \ + BIT_MASK_1 ( _ptr, _index, __VA_ARGS__ ) ) + +#define BIT_MASK_3( _ptr, _index, _field, ... ) \ + ( BIT_MASK_1 ( _ptr, _index, _field ) | \ + BIT_MASK_2 ( _ptr, _index, __VA_ARGS__ ) ) + +#define BIT_MASK_4( _ptr, _index, _field, ... ) \ + ( BIT_MASK_1 ( _ptr, _index, _field ) | \ + BIT_MASK_3 ( _ptr, _index, __VA_ARGS__ ) ) + +#define BIT_MASK_5( _ptr, _index, _field, ... ) \ + ( BIT_MASK_1 ( _ptr, _index, _field ) | \ + BIT_MASK_4 ( _ptr, _index, __VA_ARGS__ ) ) + +#define BIT_MASK_6( _ptr, _index, _field, ... ) \ + ( BIT_MASK_1 ( _ptr, _index, _field ) | \ + BIT_MASK_5 ( _ptr, _index, __VA_ARGS__ ) ) + +#define BIT_MASK_7( _ptr, _index, _field, ... ) \ + ( BIT_MASK_1 ( _ptr, _index, _field ) | \ + BIT_MASK_6 ( _ptr, _index, __VA_ARGS__ ) ) + +/* + * Populate little-endian qwords from named fields and values + * + */ + +#define BIT_FILL( _ptr, _index, _assembled ) do { \ + uint64_t *__ptr = &(_ptr)->u.qwords[(_index)]; \ + uint64_t __assembled = (_assembled); \ + *__ptr = cpu_to_BIT64 ( __assembled ); \ + } while ( 0 ) + +#define BIT_FILL_1( _ptr, _field1, ... ) \ + BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + BIT_ASSEMBLE_1 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + _field1, __VA_ARGS__ ) ) + +#define BIT_FILL_2( _ptr, _field1, ... ) \ + BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + BIT_ASSEMBLE_2 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + _field1, __VA_ARGS__ ) ) + +#define BIT_FILL_3( _ptr, _field1, ... ) \ + BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + BIT_ASSEMBLE_3 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + _field1, __VA_ARGS__ ) ) + +#define BIT_FILL_4( _ptr, _field1, ... ) \ + BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + BIT_ASSEMBLE_4 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + _field1, __VA_ARGS__ ) ) + +#define BIT_FILL_5( _ptr, _field1, ... ) \ + BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + BIT_ASSEMBLE_5 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + _field1, __VA_ARGS__ ) ) -static inline uint32_t rol32 ( uint32_t data, unsigned int rotation ) { - return ( ( data << rotation ) | ( data >> ( 32 - rotation ) ) ); -} +#define BIT_FILL_6( _ptr, _field1, ... ) \ + BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + BIT_ASSEMBLE_6 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + _field1, __VA_ARGS__ ) ) -static inline uint32_t ror32 ( uint32_t data, unsigned int rotation ) { - return ( ( data >> rotation ) | ( data << ( 32 - rotation ) ) ); -} +/** Extract value of named field */ +#define BIT_GET64( _ptr, _field ) \ + ( { \ + unsigned int __index = QWORD_OFFSET ( _ptr, _field ); \ + uint64_t *__ptr = &(_ptr)->u.qwords[__index]; \ + uint64_t __value = BIT64_to_cpu ( *__ptr ); \ + __value >>= \ + QWORD_BIT_OFFSET ( _ptr, __index, _field ); \ + __value &= BIT_MASK ( _ptr, _field ); \ + __value; \ + } ) -static inline uint64_t rol64 ( uint64_t data, unsigned int rotation ) { - return ( ( data << rotation ) | ( data >> ( 64 - rotation ) ) ); -} +/** Extract value of named field (for fields up to the size of a long) */ +#define BIT_GET( _ptr, _field ) \ + ( ( unsigned long ) BIT_GET64 ( _ptr, _field ) ) -static inline uint64_t ror64 ( uint64_t data, unsigned int rotation ) { - return ( ( data >> rotation ) | ( data << ( 64 - rotation ) ) ); -} +#define BIT_SET( _ptr, _field, _value ) do { \ + unsigned int __index = QWORD_OFFSET ( _ptr, _field ); \ + uint64_t *__ptr = &(_ptr)->u.qwords[__index]; \ + unsigned int __shift = \ + QWORD_BIT_OFFSET ( _ptr, __index, _field ); \ + uint64_t __value = (_value); \ + *__ptr &= cpu_to_BIT64 ( ~( BIT_MASK ( _ptr, _field ) << \ + __shift ) ); \ + *__ptr |= cpu_to_BIT64 ( __value << __shift ); \ + } while ( 0 ) #endif /* _GPXE_BITOPS_H */ diff --git a/gpxe/src/include/gpxe/efi/Base.h b/gpxe/src/include/gpxe/efi/Base.h new file mode 100644 index 00000000..cfb54a40 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Base.h @@ -0,0 +1,305 @@ +/** @file + + Root include file for Mde Package Base type modules + + This is the include file for any module of type base. Base modules only use + types defined via this include file and can be ported easily to any + environment. There are a set of base libraries in the Mde Package that can + be used to implement base modules. + +Copyright (c) 2006 - 2008, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#ifndef __BASE_H__ +#define __BASE_H__ + +// +// Include processor specific binding +// +#include + +typedef struct { + UINT32 Data1; + UINT16 Data2; + UINT16 Data3; + UINT8 Data4[8]; +} GUID; + +typedef UINT64 PHYSICAL_ADDRESS; + +/// +/// LIST_ENTRY definition +/// +typedef struct _LIST_ENTRY LIST_ENTRY; + +struct _LIST_ENTRY { + LIST_ENTRY *ForwardLink; + LIST_ENTRY *BackLink; +}; + +// +// Modifiers to absract standard types to aid in debug of problems +// +#define CONST const +#define STATIC static +#define VOID void + +// +// Modifiers for Data Types used to self document code. +// This concept is borrowed for UEFI specification. +// +#ifndef IN +// +// Some other envirnments use this construct, so #ifndef to prevent +// mulitple definition. +// +#define IN +#define OUT +#define OPTIONAL +#endif + +// +// Constants. They may exist in other build structures, so #ifndef them. +// +#ifndef TRUE +// +// UEFI specification claims 1 and 0. We are concerned about the +// complier portability so we did it this way. +// +#define TRUE ((BOOLEAN)(1==1)) +#endif + +#ifndef FALSE +#define FALSE ((BOOLEAN)(0==1)) +#endif + +#ifndef NULL +#define NULL ((VOID *) 0) +#endif + +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 +#define BIT32 0x0000000100000000UL +#define BIT33 0x0000000200000000UL +#define BIT34 0x0000000400000000UL +#define BIT35 0x0000000800000000UL +#define BIT36 0x0000001000000000UL +#define BIT37 0x0000002000000000UL +#define BIT38 0x0000004000000000UL +#define BIT39 0x0000008000000000UL +#define BIT40 0x0000010000000000UL +#define BIT41 0x0000020000000000UL +#define BIT42 0x0000040000000000UL +#define BIT43 0x0000080000000000UL +#define BIT44 0x0000100000000000UL +#define BIT45 0x0000200000000000UL +#define BIT46 0x0000400000000000UL +#define BIT47 0x0000800000000000UL +#define BIT48 0x0001000000000000UL +#define BIT49 0x0002000000000000UL +#define BIT50 0x0004000000000000UL +#define BIT51 0x0008000000000000UL +#define BIT52 0x0010000000000000UL +#define BIT53 0x0020000000000000UL +#define BIT54 0x0040000000000000UL +#define BIT55 0x0080000000000000UL +#define BIT56 0x0100000000000000UL +#define BIT57 0x0200000000000000UL +#define BIT58 0x0400000000000000UL +#define BIT59 0x0800000000000000UL +#define BIT60 0x1000000000000000UL +#define BIT61 0x2000000000000000UL +#define BIT62 0x4000000000000000UL +#define BIT63 0x8000000000000000UL + +// +// Support for variable length argument lists using the ANSI standard. +// +// Since we are using the ANSI standard we used the standard nameing and +// did not folow the coding convention +// +// VA_LIST - typedef for argument list. +// VA_START (VA_LIST Marker, argument before the ...) - Init Marker for use. +// VA_END (VA_LIST Marker) - Clear Marker +// VA_ARG (VA_LIST Marker, var arg size) - Use Marker to get an argumnet from +// the ... list. You must know the size and pass it in this macro. +// +// example: +// +// UINTN +// ExampleVarArg ( +// IN UINTN NumberOfArgs, +// ... +// ) +// { +// VA_LIST Marker; +// UINTN Index; +// UINTN Result; +// +// // +// // Initialize the Marker +// // +// VA_START (Marker, NumberOfArgs); +// for (Index = 0, Result = 0; Index < NumberOfArgs; Index++) { +// // +// // The ... list is a series of UINTN values, so average them up. +// // +// Result += VA_ARG (Marker, UINTN); +// } +// +// VA_END (Marker); +// return Result +// } +// + +#define _INT_SIZE_OF(n) ((sizeof (n) + sizeof (UINTN) - 1) &~(sizeof (UINTN) - 1)) + +// +// Also support coding convention rules for var arg macros +// +#ifndef VA_START + +typedef CHAR8 *VA_LIST; +#define VA_START(ap, v) (ap = (VA_LIST) & (v) + _INT_SIZE_OF (v)) +#define VA_ARG(ap, t) (*(t *) ((ap += _INT_SIZE_OF (t)) - _INT_SIZE_OF (t))) +#define VA_END(ap) (ap = (VA_LIST) 0) + +#endif + +// +// Macro that returns the byte offset of a field in a data structure. +// +#define OFFSET_OF(TYPE, Field) ((UINTN) &(((TYPE *)0)->Field)) + +/// +/// CONTAINING_RECORD - returns a pointer to the structure +/// from one of it's elements. +/// +#define _CR(Record, TYPE, Field) ((TYPE *) ((CHAR8 *) (Record) - (CHAR8 *) &(((TYPE *) 0)->Field))) + +/// +/// ALIGN_POINTER - aligns a pointer to the lowest boundry +/// +#define ALIGN_POINTER(p, s) ((VOID *) ((UINTN)(p) + (((s) - ((UINTN) (p))) & ((s) - 1)))) + +/// +/// ALIGN_VARIABLE - aligns a variable up to the next natural boundry for int size of a processor +/// +#define ALIGN_VARIABLE(Value, Adjustment) \ + Adjustment = 0U; \ + if ((UINTN) (Value) % sizeof (UINTN)) { \ + (Adjustment) = (UINTN)(sizeof (UINTN) - ((UINTN) (Value) % sizeof (UINTN))); \ + } \ + (Value) = (UINTN)((UINTN) (Value) + (UINTN) (Adjustment)) + +// +// Return the maximum of two operands. +// This macro returns the maximum of two operand specified by a and b. +// Both a and b must be the same numerical types, signed or unsigned. +// +#define MAX(a, b) \ + (((a) > (b)) ? (a) : (b)) + + +// +// Return the minimum of two operands. +// This macro returns the minimal of two operand specified by a and b. +// Both a and b must be the same numerical types, signed or unsigned. +// +#define MIN(a, b) \ + (((a) < (b)) ? (a) : (b)) + + +// +// EFI Error Codes common to all execution phases +// + +typedef INTN RETURN_STATUS; + +/// +/// Set the upper bit to indicate EFI Error. +/// +#define ENCODE_ERROR(a) (MAX_BIT | (a)) + +#define ENCODE_WARNING(a) (a) +#define RETURN_ERROR(a) ((INTN) (a) < 0) + +#define RETURN_SUCCESS 0 +#define RETURN_LOAD_ERROR ENCODE_ERROR (1) +#define RETURN_INVALID_PARAMETER ENCODE_ERROR (2) +#define RETURN_UNSUPPORTED ENCODE_ERROR (3) +#define RETURN_BAD_BUFFER_SIZE ENCODE_ERROR (4) +#define RETURN_BUFFER_TOO_SMALL ENCODE_ERROR (5) +#define RETURN_NOT_READY ENCODE_ERROR (6) +#define RETURN_DEVICE_ERROR ENCODE_ERROR (7) +#define RETURN_WRITE_PROTECTED ENCODE_ERROR (8) +#define RETURN_OUT_OF_RESOURCES ENCODE_ERROR (9) +#define RETURN_VOLUME_CORRUPTED ENCODE_ERROR (10) +#define RETURN_VOLUME_FULL ENCODE_ERROR (11) +#define RETURN_NO_MEDIA ENCODE_ERROR (12) +#define RETURN_MEDIA_CHANGED ENCODE_ERROR (13) +#define RETURN_NOT_FOUND ENCODE_ERROR (14) +#define RETURN_ACCESS_DENIED ENCODE_ERROR (15) +#define RETURN_NO_RESPONSE ENCODE_ERROR (16) +#define RETURN_NO_MAPPING ENCODE_ERROR (17) +#define RETURN_TIMEOUT ENCODE_ERROR (18) +#define RETURN_NOT_STARTED ENCODE_ERROR (19) +#define RETURN_ALREADY_STARTED ENCODE_ERROR (20) +#define RETURN_ABORTED ENCODE_ERROR (21) +#define RETURN_ICMP_ERROR ENCODE_ERROR (22) +#define RETURN_TFTP_ERROR ENCODE_ERROR (23) +#define RETURN_PROTOCOL_ERROR ENCODE_ERROR (24) +#define RETURN_INCOMPATIBLE_VERSION ENCODE_ERROR (25) +#define RETURN_SECURITY_VIOLATION ENCODE_ERROR (26) +#define RETURN_CRC_ERROR ENCODE_ERROR (27) +#define RETURN_END_OF_MEDIA ENCODE_ERROR (28) +#define RETURN_END_OF_FILE ENCODE_ERROR (31) +#define RETURN_INVALID_LANGUAGE ENCODE_ERROR (32) + + +#define RETURN_WARN_UNKNOWN_GLYPH ENCODE_WARNING (1) +#define RETURN_WARN_DELETE_FAILURE ENCODE_WARNING (2) +#define RETURN_WARN_WRITE_FAILURE ENCODE_WARNING (3) +#define RETURN_WARN_BUFFER_TOO_SMALL ENCODE_WARNING (4) + +#endif + diff --git a/gpxe/src/include/gpxe/efi/Guid/PcAnsi.h b/gpxe/src/include/gpxe/efi/Guid/PcAnsi.h new file mode 100644 index 00000000..1dab3109 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Guid/PcAnsi.h @@ -0,0 +1,58 @@ +/** @file + Terminal Device Path Vendor Guid. + + Copyright (c) 2006, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + GUIDs defined in UEFI 2.0 spec. + +**/ + +#ifndef __PC_ANSI_H__ +#define __PC_ANSI_H__ + +#define EFI_PC_ANSI_GUID \ + { \ + 0xe0c14753, 0xf9be, 0x11d2, {0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +#define EFI_VT_100_GUID \ + { \ + 0xdfa66065, 0xb419, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +#define EFI_VT_100_PLUS_GUID \ + { \ + 0x7baec70b, 0x57e0, 0x4c76, {0x8e, 0x87, 0x2f, 0x9e, 0x28, 0x08, 0x83, 0x43 } \ + } + +#define EFI_VT_UTF8_GUID \ + { \ + 0xad15a0d6, 0x8bec, 0x4acf, {0xa0, 0x73, 0xd0, 0x1d, 0xe7, 0x7e, 0x2d, 0x88 } \ + } + +#define EFI_UART_DEVICE_PATH_GUID \ + { \ + 0x37499a9d, 0x542f, 0x4c89, {0xa0, 0x26, 0x35, 0xda, 0x14, 0x20, 0x94, 0xe4 } \ + } + +#define EFI_SAS_DEVICE_PATH_GUID \ + { \ + 0xd487ddb4, 0x008b, 0x11d9, {0xaf, 0xdc, 0x00, 0x10, 0x83, 0xff, 0xca, 0x4d } \ + } + +extern EFI_GUID gEfiPcAnsiGuid; +extern EFI_GUID gEfiVT100Guid; +extern EFI_GUID gEfiVT100PlusGuid; +extern EFI_GUID gEfiVTUTF8Guid; +extern EFI_GUID gEfiUartDevicePathGuid; +extern EFI_GUID gEfiSasDevicePathGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Ia32/ProcessorBind.h b/gpxe/src/include/gpxe/efi/Ia32/ProcessorBind.h new file mode 100644 index 00000000..512564ca --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Ia32/ProcessorBind.h @@ -0,0 +1,221 @@ +/** @file + Processor or Compiler specific defines and types for Ia32 architecture. + + Copyright (c) 2006, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __PROCESSOR_BIND_H__ +#define __PROCESSOR_BIND_H__ + +/// +/// Define the processor type so other code can make processor based choices +/// +#define MDE_CPU_IA32 + +// +// Make sure we are useing the correct packing rules per EFI specification +// +#ifndef __GNUC__ +#pragma pack() +#endif + +#if __INTEL_COMPILER +// +// Disable ICC's remark #593: "LocalVariable" was set but never used +// This is legal ANSI C code so we disable the remark that is turned on with -Wall +// +#pragma warning ( disable : 593 ) + +// +// Disable ICC's remark #869: "Parameter" was never referenced warning. +// This is legal ANSI C code so we disable the remark that is turned on with -Wall +// +#pragma warning ( disable : 869 ) + +// +// Disable ICC's remark #1418: external function definition with no prior declaration. +// This is legal ANSI C code so we disable the remark that is turned on with /W4 +// +#pragma warning ( disable : 1418 ) + +// +// Disable ICC's remark #1419: external declaration in primary source file +// This is legal ANSI C code so we disable the remark that is turned on with /W4 +// +#pragma warning ( disable : 1419 ) + +#endif + + +#if _MSC_EXTENSIONS + +// +// Disable warning that make it impossible to compile at /W4 +// This only works for Microsoft* tools +// + +// +// Disabling bitfield type checking warnings. +// +#pragma warning ( disable : 4214 ) + +// +// Disabling the unreferenced formal parameter warnings. +// +#pragma warning ( disable : 4100 ) + +// +// Disable slightly different base types warning as CHAR8 * can not be set +// to a constant string. +// +#pragma warning ( disable : 4057 ) + +// +// ASSERT(FALSE) or while (TRUE) are legal constructes so supress this warning +// +#pragma warning ( disable : 4127 ) + +// +// This warning is caused by functions defined but not used. For precompiled header only. +// +#pragma warning ( disable : 4505 ) + +// +// This warning is caused by empty (after preprocessing) souce file. For precompiled header only. +// +#pragma warning ( disable : 4206 ) + +#endif + + +#if !defined(__GNUC__) && (__STDC_VERSION__ < 199901L) + // + // No ANSI C 2000 stdint.h integer width declarations, so define equivalents + // + + #if _MSC_EXTENSIONS + + // + // use Microsoft* C complier dependent interger width types + // + typedef unsigned __int64 UINT64; + typedef __int64 INT64; + typedef unsigned __int32 UINT32; + typedef __int32 INT32; + typedef unsigned short UINT16; + typedef unsigned short CHAR16; + typedef short INT16; + typedef unsigned char BOOLEAN; + typedef unsigned char UINT8; + typedef char CHAR8; + typedef char INT8; + #else + + // + // Assume standard IA-32 alignment. + // Need to check portability of long long + // + typedef unsigned long long UINT64; + typedef long long INT64; + typedef unsigned int UINT32; + typedef int INT32; + typedef unsigned short UINT16; + typedef unsigned short CHAR16; + typedef short INT16; + typedef unsigned char BOOLEAN; + typedef unsigned char UINT8; + typedef char CHAR8; + typedef char INT8; + #endif + + #define UINT8_MAX 0xff + +#else + // + // Use ANSI C 2000 stdint.h integer width declarations + // + #include "stdint.h" + typedef uint8_t BOOLEAN; + typedef int8_t INT8; + typedef uint8_t UINT8; + typedef int16_t INT16; + typedef uint16_t UINT16; + typedef int32_t INT32; + typedef uint32_t UINT32; + typedef int64_t INT64; + typedef uint64_t UINT64; + typedef char CHAR8; + typedef uint16_t CHAR16; + +#endif + +typedef UINT32 UINTN; +typedef INT32 INTN; + + +/// +/// Processor specific defines +/// +#define MAX_BIT 0x80000000 +#define MAX_2_BITS 0xC0000000 + +/// +/// Maximum legal IA-32 address +/// +#define MAX_ADDRESS 0xFFFFFFFF + +/// +/// The stack alignment required for IA-32 +/// +#define CPU_STACK_ALIGNMENT sizeof(UINTN) + +// +// Modifier to ensure that all protocol member functions and EFI intrinsics +// use the correct C calling convention. All protocol member functions and +// EFI intrinsics are required to modify thier member functions with EFIAPI. +// +#if _MSC_EXTENSIONS + /// + /// Microsoft* compiler requires _EFIAPI useage, __cdecl is Microsoft* specific C. + /// + #define EFIAPI __cdecl +#else + #if __GNUC__ + #define EFIAPI __attribute__((cdecl,regparm(0))) + #endif +#endif + +// +// The Microsoft* C compiler can removed references to unreferenced data items +// if the /OPT:REF linker option is used. We defined a macro as this is a +// a non standard extension +// +#if _MSC_EXTENSIONS + #define GLOBAL_REMOVE_IF_UNREFERENCED __declspec(selectany) +#else + #define GLOBAL_REMOVE_IF_UNREFERENCED +#endif + +// +// For symbol name in GNU assembly code, an extra "_" is necessary +// +#if __GNUC__ + #if defined(linux) + #define ASM_PFX(name) name + #else + #define ASM_PFX(name) _##name + #endif +#endif + +#define FUNCTION_ENTRY_POINT(p) (p) + +#endif + diff --git a/gpxe/src/include/gpxe/efi/IndustryStandard/PeImage.h b/gpxe/src/include/gpxe/efi/IndustryStandard/PeImage.h new file mode 100644 index 00000000..666d4ec3 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/IndustryStandard/PeImage.h @@ -0,0 +1,742 @@ +/** @file + EFI image format for PE32 and PE32+. Please note some data structures are + different for PE32 and PE32+. EFI_IMAGE_NT_HEADERS32 is for PE32 and + EFI_IMAGE_NT_HEADERS64 is for PE32+. + + This file is coded to the Visual Studio, Microsoft Portable Executable and + Common Object File Format Specification, Revision 8.0 - May 16, 2006. + + Copyright (c) 2006 - 2007, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EFI_IMAGE_H__ +#define __EFI_IMAGE_H__ + +// +// PE32+ Subsystem type for EFI images +// +#define EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION 10 +#define EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 +#define EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 +#define EFI_IMAGE_SUBSYSTEM_EFI_EFI_ROM 13 + +#define EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13 + + +// +// PE32+ Machine type for EFI images +// +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_IA64 0x0200 +#define IMAGE_FILE_MACHINE_EBC 0x0EBC +#define IMAGE_FILE_MACHINE_X64 0x8664 +// +// Support old names for backward compatible +// +#define EFI_IMAGE_MACHINE_IA32 IMAGE_FILE_MACHINE_I386 +#define EFI_IMAGE_MACHINE_IA64 IMAGE_FILE_MACHINE_IA64 +#define EFI_IMAGE_MACHINE_IPF IMAGE_FILE_MACHINE_IA64 +#define EFI_IMAGE_MACHINE_EBC IMAGE_FILE_MACHINE_EBC +#define EFI_IMAGE_MACHINE_X64 IMAGE_FILE_MACHINE_X64 + +#define EFI_IMAGE_DOS_SIGNATURE 0x5A4D // MZ +#define EFI_IMAGE_OS2_SIGNATURE 0x454E // NE +#define EFI_IMAGE_OS2_SIGNATURE_LE 0x454C // LE +#define EFI_IMAGE_NT_SIGNATURE 0x00004550 // PE00 + +/// +/// PE images can start with an optional DOS header, so if an image is run +/// under DOS it can print an error message. +/// +typedef struct { + UINT16 e_magic; // Magic number + UINT16 e_cblp; // Bytes on last page of file + UINT16 e_cp; // Pages in file + UINT16 e_crlc; // Relocations + UINT16 e_cparhdr; // Size of header in paragraphs + UINT16 e_minalloc; // Minimum extra paragraphs needed + UINT16 e_maxalloc; // Maximum extra paragraphs needed + UINT16 e_ss; // Initial (relative) SS value + UINT16 e_sp; // Initial SP value + UINT16 e_csum; // Checksum + UINT16 e_ip; // Initial IP value + UINT16 e_cs; // Initial (relative) CS value + UINT16 e_lfarlc; // File address of relocation table + UINT16 e_ovno; // Overlay number + UINT16 e_res[4]; // Reserved words + UINT16 e_oemid; // OEM identifier (for e_oeminfo) + UINT16 e_oeminfo; // OEM information; e_oemid specific + UINT16 e_res2[10]; // Reserved words + UINT32 e_lfanew; // File address of new exe header +} EFI_IMAGE_DOS_HEADER; + +/// +/// File header format. +/// +typedef struct { + UINT16 Machine; + UINT16 NumberOfSections; + UINT32 TimeDateStamp; + UINT32 PointerToSymbolTable; + UINT32 NumberOfSymbols; + UINT16 SizeOfOptionalHeader; + UINT16 Characteristics; +} EFI_IMAGE_FILE_HEADER; + +#define EFI_IMAGE_SIZEOF_FILE_HEADER 20 + +#define EFI_IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file. +#define EFI_IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved externel references). +#define EFI_IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file. +#define EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file. +#define EFI_IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed. +#define EFI_IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine. +#define EFI_IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file +#define EFI_IMAGE_FILE_SYSTEM 0x1000 // System File. +#define EFI_IMAGE_FILE_DLL 0x2000 // File is a DLL. +#define EFI_IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed. +#define EFI_IMAGE_FILE_MACHINE_UNKNOWN 0 +#define EFI_IMAGE_FILE_MACHINE_I386 0x14c // Intel 386. +#define EFI_IMAGE_FILE_MACHINE_R3000 0x162 // MIPS* little-endian, 0540 big-endian +#define EFI_IMAGE_FILE_MACHINE_R4000 0x166 // MIPS* little-endian +#define EFI_IMAGE_FILE_MACHINE_ALPHA 0x184 // Alpha_AXP* +#define EFI_IMAGE_FILE_MACHINE_POWERPC 0x1F0 // IBM* PowerPC Little-Endian +#define EFI_IMAGE_FILE_MACHINE_TAHOE 0x7cc // Intel EM machine +// +// * Other names and brands may be claimed as the property of others. +// + +/// +/// Directory format. +/// +typedef struct { + UINT32 VirtualAddress; + UINT32 Size; +} EFI_IMAGE_DATA_DIRECTORY; + +#define EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16 + +typedef struct { + UINT16 Magic; + UINT8 MajorLinkerVersion; + UINT8 MinorLinkerVersion; + UINT32 SizeOfCode; + UINT32 SizeOfInitializedData; + UINT32 SizeOfUninitializedData; + UINT32 AddressOfEntryPoint; + UINT32 BaseOfCode; + UINT32 BaseOfData; + UINT32 BaseOfBss; + UINT32 GprMask; + UINT32 CprMask[4]; + UINT32 GpValue; +} EFI_IMAGE_ROM_OPTIONAL_HEADER; + +#define EFI_IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 +#define EFI_IMAGE_SIZEOF_ROM_OPTIONAL_HEADER sizeof (EFI_IMAGE_ROM_OPTIONAL_HEADER) + +typedef struct { + EFI_IMAGE_FILE_HEADER FileHeader; + EFI_IMAGE_ROM_OPTIONAL_HEADER OptionalHeader; +} EFI_IMAGE_ROM_HEADERS; + +/// +/// @attention +/// EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC means PE32 and +/// EFI_IMAGE_OPTIONAL_HEADER32 must be used. The data structures only vary +/// after NT additional fields. +/// +#define EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b + +typedef struct { + /// + /// Standard fields. + /// + UINT16 Magic; + UINT8 MajorLinkerVersion; + UINT8 MinorLinkerVersion; + UINT32 SizeOfCode; + UINT32 SizeOfInitializedData; + UINT32 SizeOfUninitializedData; + UINT32 AddressOfEntryPoint; + UINT32 BaseOfCode; + UINT32 BaseOfData; + /// + /// NT additional fields. + /// + UINT32 ImageBase; + UINT32 SectionAlignment; + UINT32 FileAlignment; + UINT16 MajorOperatingSystemVersion; + UINT16 MinorOperatingSystemVersion; + UINT16 MajorImageVersion; + UINT16 MinorImageVersion; + UINT16 MajorSubsystemVersion; + UINT16 MinorSubsystemVersion; + UINT32 Win32VersionValue; + UINT32 SizeOfImage; + UINT32 SizeOfHeaders; + UINT32 CheckSum; + UINT16 Subsystem; + UINT16 DllCharacteristics; + UINT32 SizeOfStackReserve; + UINT32 SizeOfStackCommit; + UINT32 SizeOfHeapReserve; + UINT32 SizeOfHeapCommit; + UINT32 LoaderFlags; + UINT32 NumberOfRvaAndSizes; + EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES]; +} EFI_IMAGE_OPTIONAL_HEADER32; + +/// +/// @attention +/// EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC means PE32+ and +/// EFI_IMAGE_OPTIONAL_HEADER64 must be used. The data structures only vary +/// after NT additional fields. +/// +#define EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b + +typedef struct { + // + // Standard fields. + // + UINT16 Magic; + UINT8 MajorLinkerVersion; + UINT8 MinorLinkerVersion; + UINT32 SizeOfCode; + UINT32 SizeOfInitializedData; + UINT32 SizeOfUninitializedData; + UINT32 AddressOfEntryPoint; + UINT32 BaseOfCode; + // + // NT additional fields. + // + UINT64 ImageBase; + UINT32 SectionAlignment; + UINT32 FileAlignment; + UINT16 MajorOperatingSystemVersion; + UINT16 MinorOperatingSystemVersion; + UINT16 MajorImageVersion; + UINT16 MinorImageVersion; + UINT16 MajorSubsystemVersion; + UINT16 MinorSubsystemVersion; + UINT32 Win32VersionValue; + UINT32 SizeOfImage; + UINT32 SizeOfHeaders; + UINT32 CheckSum; + UINT16 Subsystem; + UINT16 DllCharacteristics; + UINT64 SizeOfStackReserve; + UINT64 SizeOfStackCommit; + UINT64 SizeOfHeapReserve; + UINT64 SizeOfHeapCommit; + UINT32 LoaderFlags; + UINT32 NumberOfRvaAndSizes; + EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES]; +} EFI_IMAGE_OPTIONAL_HEADER64; + + +/// +/// @attention +/// EFI_IMAGE_NT_HEADERS32 and EFI_IMAGE_HEADERS64 are for use ONLY +/// by tools. All proper EFI code MUST use EFI_IMAGE_NT_HEADERS ONLY!!! +/// +typedef struct { + UINT32 Signature; + EFI_IMAGE_FILE_HEADER FileHeader; + EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader; +} EFI_IMAGE_NT_HEADERS32; + +#define EFI_IMAGE_SIZEOF_NT_OPTIONAL32_HEADER sizeof (EFI_IMAGE_NT_HEADERS32) + +typedef struct { + UINT32 Signature; + EFI_IMAGE_FILE_HEADER FileHeader; + EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader; +} EFI_IMAGE_NT_HEADERS64; + +#define EFI_IMAGE_SIZEOF_NT_OPTIONAL64_HEADER sizeof (EFI_IMAGE_NT_HEADERS64) + + +// +// Processor specific definition of EFI_IMAGE_OPTIONAL_HEADER so the +// type name EFI_IMAGE_OPTIONAL_HEADER is appropriate to the build. Same for +// EFI_IMAGE_NT_HEADERS. These definitions MUST be used by ALL EFI code. +// +#if defined (MDE_CPU_IA32) + +#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \ + (((Machine) == EFI_IMAGE_MACHINE_IA32) || ((Machine) == EFI_IMAGE_MACHINE_EBC)) + +#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) ((Machine) == EFI_IMAGE_MACHINE_X64) + +// +// @bug - Remove me when other package updated. +// +typedef EFI_IMAGE_NT_HEADERS32 EFI_IMAGE_NT_HEADERS; + +#elif defined (MDE_CPU_IPF) + +#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \ + (((Machine) == EFI_IMAGE_MACHINE_IPF) || ((Machine) == EFI_IMAGE_MACHINE_EBC)) + +#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) (FALSE) + +// +// @bug - Remove me when other package updated. +// +typedef EFI_IMAGE_NT_HEADERS64 EFI_IMAGE_NT_HEADERS; + +#elif defined (MDE_CPU_X64) + +#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \ + (((Machine) == EFI_IMAGE_MACHINE_X64) || ((Machine) == EFI_IMAGE_MACHINE_EBC)) + +#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) ((Machine) == EFI_IMAGE_MACHINE_IA32) + +// +// @bug - Remove me when other package updated. +// +typedef EFI_IMAGE_NT_HEADERS64 EFI_IMAGE_NT_HEADERS; + +#elif defined (MDE_CPU_EBC) + +/// +/// This is just to make sure you can cross compile with the EBC compiiler. +/// It does not make sense to have a PE loader coded in EBC. You need to +/// understand the basic +/// +#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) ((Machine) == EFI_IMAGE_MACHINE_EBC) + +#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) (FALSE) + +// +// @bug - Remove me when other package updated. +// +typedef EFI_IMAGE_NT_HEADERS64 EFI_IMAGE_NT_HEADERS; + +#else +#error Unknown Processor Type +#endif + + +#define EFI_IMAGE_FIRST_SECTION(ntheader) \ + ( \ + (EFI_IMAGE_SECTION_HEADER *) \ + ( \ + (UINT32) ntheader + \ + FIELD_OFFSET (EFI_IMAGE_NT_HEADERS, OptionalHeader) + \ + ((EFI_IMAGE_NT_HEADERS *) (ntheader))->FileHeader.SizeOfOptionalHeader \ + ) \ + ) + +// +// Subsystem Values +// +#define EFI_IMAGE_SUBSYSTEM_UNKNOWN 0 +#define EFI_IMAGE_SUBSYSTEM_NATIVE 1 +#define EFI_IMAGE_SUBSYSTEM_WINDOWS_GUI 2 +#define EFI_IMAGE_SUBSYSTEM_WINDOWS_CUI 3. +#define EFI_IMAGE_SUBSYSTEM_OS2_CUI 5 +#define EFI_IMAGE_SUBSYSTEM_POSIX_CUI 7 + +// +// Directory Entries +// +#define EFI_IMAGE_DIRECTORY_ENTRY_EXPORT 0 +#define EFI_IMAGE_DIRECTORY_ENTRY_IMPORT 1 +#define EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE 2 +#define EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 +#define EFI_IMAGE_DIRECTORY_ENTRY_SECURITY 4 +#define EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC 5 +#define EFI_IMAGE_DIRECTORY_ENTRY_DEBUG 6 +#define EFI_IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 +#define EFI_IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 +#define EFI_IMAGE_DIRECTORY_ENTRY_TLS 9 +#define EFI_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 + +// +// Section header format. +// +#define EFI_IMAGE_SIZEOF_SHORT_NAME 8 + +typedef struct { + UINT8 Name[EFI_IMAGE_SIZEOF_SHORT_NAME]; + union { + UINT32 PhysicalAddress; + UINT32 VirtualSize; + } Misc; + UINT32 VirtualAddress; + UINT32 SizeOfRawData; + UINT32 PointerToRawData; + UINT32 PointerToRelocations; + UINT32 PointerToLinenumbers; + UINT16 NumberOfRelocations; + UINT16 NumberOfLinenumbers; + UINT32 Characteristics; +} EFI_IMAGE_SECTION_HEADER; + +#define EFI_IMAGE_SIZEOF_SECTION_HEADER 40 + +#define EFI_IMAGE_SCN_TYPE_NO_PAD 0x00000008 // Reserved. +#define EFI_IMAGE_SCN_CNT_CODE 0x00000020 +#define EFI_IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 + +#define EFI_IMAGE_SCN_LNK_OTHER 0x00000100 // Reserved. +#define EFI_IMAGE_SCN_LNK_INFO 0x00000200 // Section contains comments or some other type of information. +#define EFI_IMAGE_SCN_LNK_REMOVE 0x00000800 // Section contents will not become part of image. +#define EFI_IMAGE_SCN_LNK_COMDAT 0x00001000 + +#define EFI_IMAGE_SCN_ALIGN_1BYTES 0x00100000 +#define EFI_IMAGE_SCN_ALIGN_2BYTES 0x00200000 +#define EFI_IMAGE_SCN_ALIGN_4BYTES 0x00300000 +#define EFI_IMAGE_SCN_ALIGN_8BYTES 0x00400000 +#define EFI_IMAGE_SCN_ALIGN_16BYTES 0x00500000 +#define EFI_IMAGE_SCN_ALIGN_32BYTES 0x00600000 +#define EFI_IMAGE_SCN_ALIGN_64BYTES 0x00700000 + +#define EFI_IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define EFI_IMAGE_SCN_MEM_NOT_CACHED 0x04000000 +#define EFI_IMAGE_SCN_MEM_NOT_PAGED 0x08000000 +#define EFI_IMAGE_SCN_MEM_SHARED 0x10000000 +#define EFI_IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define EFI_IMAGE_SCN_MEM_READ 0x40000000 +#define EFI_IMAGE_SCN_MEM_WRITE 0x80000000 + +/// +/// Symbol format. +/// +#define EFI_IMAGE_SIZEOF_SYMBOL 18 + +// +// Section values. +// +// Symbols have a section number of the section in which they are +// defined. Otherwise, section numbers have the following meanings: +// +#define EFI_IMAGE_SYM_UNDEFINED (UINT16) 0 // Symbol is undefined or is common. +#define EFI_IMAGE_SYM_ABSOLUTE (UINT16) -1 // Symbol is an absolute value. +#define EFI_IMAGE_SYM_DEBUG (UINT16) -2 // Symbol is a special debug item. +// +// Type (fundamental) values. +// +#define EFI_IMAGE_SYM_TYPE_NULL 0 // no type. +#define EFI_IMAGE_SYM_TYPE_VOID 1 // +#define EFI_IMAGE_SYM_TYPE_CHAR 2 // type character. +#define EFI_IMAGE_SYM_TYPE_SHORT 3 // type short integer. +#define EFI_IMAGE_SYM_TYPE_INT 4 +#define EFI_IMAGE_SYM_TYPE_LONG 5 +#define EFI_IMAGE_SYM_TYPE_FLOAT 6 +#define EFI_IMAGE_SYM_TYPE_DOUBLE 7 +#define EFI_IMAGE_SYM_TYPE_STRUCT 8 +#define EFI_IMAGE_SYM_TYPE_UNION 9 +#define EFI_IMAGE_SYM_TYPE_ENUM 10 // enumeration. +#define EFI_IMAGE_SYM_TYPE_MOE 11 // member of enumeration. +#define EFI_IMAGE_SYM_TYPE_BYTE 12 +#define EFI_IMAGE_SYM_TYPE_WORD 13 +#define EFI_IMAGE_SYM_TYPE_UINT 14 +#define EFI_IMAGE_SYM_TYPE_DWORD 15 + +// +// Type (derived) values. +// +#define EFI_IMAGE_SYM_DTYPE_NULL 0 // no derived type. +#define EFI_IMAGE_SYM_DTYPE_POINTER 1 +#define EFI_IMAGE_SYM_DTYPE_FUNCTION 2 +#define EFI_IMAGE_SYM_DTYPE_ARRAY 3 + +// +// Storage classes. +// +#define EFI_IMAGE_SYM_CLASS_END_OF_FUNCTION (UINT8) -1 +#define EFI_IMAGE_SYM_CLASS_NULL 0 +#define EFI_IMAGE_SYM_CLASS_AUTOMATIC 1 +#define EFI_IMAGE_SYM_CLASS_EXTERNAL 2 +#define EFI_IMAGE_SYM_CLASS_STATIC 3 +#define EFI_IMAGE_SYM_CLASS_REGISTER 4 +#define EFI_IMAGE_SYM_CLASS_EXTERNAL_DEF 5 +#define EFI_IMAGE_SYM_CLASS_LABEL 6 +#define EFI_IMAGE_SYM_CLASS_UNDEFINED_LABEL 7 +#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8 +#define EFI_IMAGE_SYM_CLASS_ARGUMENT 9 +#define EFI_IMAGE_SYM_CLASS_STRUCT_TAG 10 +#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_UNION 11 +#define EFI_IMAGE_SYM_CLASS_UNION_TAG 12 +#define EFI_IMAGE_SYM_CLASS_TYPE_DEFINITION 13 +#define EFI_IMAGE_SYM_CLASS_UNDEFINED_STATIC 14 +#define EFI_IMAGE_SYM_CLASS_ENUM_TAG 15 +#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16 +#define EFI_IMAGE_SYM_CLASS_REGISTER_PARAM 17 +#define EFI_IMAGE_SYM_CLASS_BIT_FIELD 18 +#define EFI_IMAGE_SYM_CLASS_BLOCK 100 +#define EFI_IMAGE_SYM_CLASS_FUNCTION 101 +#define EFI_IMAGE_SYM_CLASS_END_OF_STRUCT 102 +#define EFI_IMAGE_SYM_CLASS_FILE 103 +#define EFI_IMAGE_SYM_CLASS_SECTION 104 +#define EFI_IMAGE_SYM_CLASS_WEAK_EXTERNAL 105 + +// +// type packing constants +// +#define EFI_IMAGE_N_BTMASK 017 +#define EFI_IMAGE_N_TMASK 060 +#define EFI_IMAGE_N_TMASK1 0300 +#define EFI_IMAGE_N_TMASK2 0360 +#define EFI_IMAGE_N_BTSHFT 4 +#define EFI_IMAGE_N_TSHIFT 2 + +// +// Communal selection types. +// +#define EFI_IMAGE_COMDAT_SELECT_NODUPLICATES 1 +#define EFI_IMAGE_COMDAT_SELECT_ANY 2 +#define EFI_IMAGE_COMDAT_SELECT_SAME_SIZE 3 +#define EFI_IMAGE_COMDAT_SELECT_EXACT_MATCH 4 +#define EFI_IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 + +#define EFI_IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 +#define EFI_IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 +#define EFI_IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 + +/// +/// Relocation format. +/// +typedef struct { + UINT32 VirtualAddress; + UINT32 SymbolTableIndex; + UINT16 Type; +} EFI_IMAGE_RELOCATION; + +#define EFI_IMAGE_SIZEOF_RELOCATION 10 + +// +// I386 relocation types. +// +#define EFI_IMAGE_REL_I386_ABSOLUTE 0x0000 // Reference is absolute, no relocation is necessary +#define EFI_IMAGE_REL_I386_DIR16 0x0001 // Direct 16-bit reference to the symbols virtual address +#define EFI_IMAGE_REL_I386_REL16 0x0002 // PC-relative 16-bit reference to the symbols virtual address +#define EFI_IMAGE_REL_I386_DIR32 0x0006 // Direct 32-bit reference to the symbols virtual address +#define EFI_IMAGE_REL_I386_DIR32NB 0x0007 // Direct 32-bit reference to the symbols virtual address, base not included +#define EFI_IMAGE_REL_I386_SEG12 0x0009 // Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address +#define EFI_IMAGE_REL_I386_SECTION 0x001a +#define EFI_IMAGE_REL_I386_SECREL 0x000b +#define EFI_IMAGE_REL_I386_REL32 0x0014 // PC-relative 32-bit reference to the symbols virtual address + +// +// x64 processor relocation types. +// +#define IMAGE_REL_AMD64_ABSOLUTE 0x0000 +#define IMAGE_REL_AMD64_ADDR64 0x0001 +#define IMAGE_REL_AMD64_ADDR32 0x0002 +#define IMAGE_REL_AMD64_ADDR32NB 0x0003 +#define IMAGE_REL_AMD64_REL32 0x0004 +#define IMAGE_REL_AMD64_REL32_1 0x0005 +#define IMAGE_REL_AMD64_REL32_2 0x0006 +#define IMAGE_REL_AMD64_REL32_3 0x0007 +#define IMAGE_REL_AMD64_REL32_4 0x0008 +#define IMAGE_REL_AMD64_REL32_5 0x0009 +#define IMAGE_REL_AMD64_SECTION 0x000A +#define IMAGE_REL_AMD64_SECREL 0x000B +#define IMAGE_REL_AMD64_SECREL7 0x000C +#define IMAGE_REL_AMD64_TOKEN 0x000D +#define IMAGE_REL_AMD64_SREL32 0x000E +#define IMAGE_REL_AMD64_PAIR 0x000F +#define IMAGE_REL_AMD64_SSPAN32 0x0010 + +/// +/// Based relocation format. +/// +typedef struct { + UINT32 VirtualAddress; + UINT32 SizeOfBlock; +} EFI_IMAGE_BASE_RELOCATION; + +#define EFI_IMAGE_SIZEOF_BASE_RELOCATION 8 + +// +// Based relocation types. +// +#define EFI_IMAGE_REL_BASED_ABSOLUTE 0 +#define EFI_IMAGE_REL_BASED_HIGH 1 +#define EFI_IMAGE_REL_BASED_LOW 2 +#define EFI_IMAGE_REL_BASED_HIGHLOW 3 +#define EFI_IMAGE_REL_BASED_HIGHADJ 4 +#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define EFI_IMAGE_REL_BASED_IA64_IMM64 9 +#define EFI_IMAGE_REL_BASED_DIR64 10 + +/// +/// Line number format. +/// +typedef struct { + union { + UINT32 SymbolTableIndex; // Symbol table index of function name if Linenumber is 0. + UINT32 VirtualAddress; // Virtual address of line number. + } Type; + UINT16 Linenumber; // Line number. +} EFI_IMAGE_LINENUMBER; + +#define EFI_IMAGE_SIZEOF_LINENUMBER 6 + +// +// Archive format. +// +#define EFI_IMAGE_ARCHIVE_START_SIZE 8 +#define EFI_IMAGE_ARCHIVE_START "!\n" +#define EFI_IMAGE_ARCHIVE_END "`\n" +#define EFI_IMAGE_ARCHIVE_PAD "\n" +#define EFI_IMAGE_ARCHIVE_LINKER_MEMBER "/ " +#define EFI_IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " + +typedef struct { + UINT8 Name[16]; // File member name - `/' terminated. + UINT8 Date[12]; // File member date - decimal. + UINT8 UserID[6]; // File member user id - decimal. + UINT8 GroupID[6]; // File member group id - decimal. + UINT8 Mode[8]; // File member mode - octal. + UINT8 Size[10]; // File member size - decimal. + UINT8 EndHeader[2]; // String to end header. +} EFI_IMAGE_ARCHIVE_MEMBER_HEADER; + +#define EFI_IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 + +// +// DLL support. +// + +/// +/// DLL Export Format +/// +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT32 Name; + UINT32 Base; + UINT32 NumberOfFunctions; + UINT32 NumberOfNames; + UINT32 AddressOfFunctions; + UINT32 AddressOfNames; + UINT32 AddressOfNameOrdinals; +} EFI_IMAGE_EXPORT_DIRECTORY; + +/// +/// DLL support. +/// Import Format +/// +typedef struct { + UINT16 Hint; + UINT8 Name[1]; +} EFI_IMAGE_IMPORT_BY_NAME; + +typedef struct { + union { + UINT32 Function; + UINT32 Ordinal; + EFI_IMAGE_IMPORT_BY_NAME *AddressOfData; + } u1; +} EFI_IMAGE_THUNK_DATA; + +#define EFI_IMAGE_ORDINAL_FLAG 0x80000000 +#define EFI_IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & EFI_IMAGE_ORDINAL_FLAG) != 0) +#define EFI_IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) + +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT32 ForwarderChain; + UINT32 Name; + EFI_IMAGE_THUNK_DATA *FirstThunk; +} EFI_IMAGE_IMPORT_DESCRIPTOR; + +/// +/// Debug Format +/// +#define EFI_IMAGE_DEBUG_TYPE_CODEVIEW 2 + +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT32 Type; + UINT32 SizeOfData; + UINT32 RVA; + UINT32 FileOffset; +} EFI_IMAGE_DEBUG_DIRECTORY_ENTRY; + +#define CODEVIEW_SIGNATURE_NB10 0x3031424E // "NB10" +typedef struct { + UINT32 Signature; // "NB10" + UINT32 Unknown; + UINT32 Unknown2; + UINT32 Unknown3; + // + // Filename of .PDB goes here + // +} EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY; + +#define CODEVIEW_SIGNATURE_RSDS 0x53445352 // "RSDS" +typedef struct { + UINT32 Signature; // "RSDS" + UINT32 Unknown; + UINT32 Unknown2; + UINT32 Unknown3; + UINT32 Unknown4; + UINT32 Unknown5; + // + // Filename of .PDB goes here + // +} EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY; + +/// +/// Header format for TE images +/// +typedef struct { + UINT16 Signature; // signature for TE format = "VZ" + UINT16 Machine; // from the original file header + UINT8 NumberOfSections; // from the original file header + UINT8 Subsystem; // from original optional header + UINT16 StrippedSize; // how many bytes we removed from the header + UINT32 AddressOfEntryPoint; // offset to entry point -- from original optional header + UINT32 BaseOfCode; // from original image -- required for ITP debug + UINT64 ImageBase; // from original file header + EFI_IMAGE_DATA_DIRECTORY DataDirectory[2]; // only base relocation and debug directory +} EFI_TE_IMAGE_HEADER; + +#define EFI_TE_IMAGE_HEADER_SIGNATURE 0x5A56 // "VZ" + +// +// Data directory indexes in our TE image header +// +#define EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC 0 +#define EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG 1 + + +/// +/// Union of PE32, PE32+, and TE headers +/// +typedef union { + EFI_IMAGE_NT_HEADERS32 Pe32; + EFI_IMAGE_NT_HEADERS64 Pe32Plus; + EFI_TE_IMAGE_HEADER Te; +} EFI_IMAGE_OPTIONAL_HEADER_UNION; + +typedef union { + EFI_IMAGE_NT_HEADERS32 *Pe32; + EFI_IMAGE_NT_HEADERS64 *Pe32Plus; + EFI_TE_IMAGE_HEADER *Te; + EFI_IMAGE_OPTIONAL_HEADER_UNION *Union; +} EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION; + +#endif diff --git a/gpxe/src/include/gpxe/efi/LICENCE b/gpxe/src/include/gpxe/efi/LICENCE new file mode 100644 index 00000000..6aa2b2ff --- /dev/null +++ b/gpxe/src/include/gpxe/efi/LICENCE @@ -0,0 +1,40 @@ +The EFI headers contained herein are copied from the EFI Development +Kit, available from http://www.tianocore.org and published under the +following licence: + + BSD License from Intel + Copyright (c) 2004, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + +This licence applies only to files that are part of the EFI +Development Kit. Other files may contain their own licence terms, or +may fall under the standard gPXE GPL licence. diff --git a/gpxe/src/include/gpxe/efi/Pi/PiBootMode.h b/gpxe/src/include/gpxe/efi/Pi/PiBootMode.h new file mode 100644 index 00000000..bea69ff1 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Pi/PiBootMode.h @@ -0,0 +1,43 @@ +/** @file + Present the boot mode values in PI. + + Copyright (c) 2006 - 2007, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + Version 1.0. + +**/ + +#ifndef __PI_BOOT_MODE_H__ +#define __PI_BOOT_MODE_H__ + +#include + +/// +/// EFI boot mode +/// +typedef UINT32 EFI_BOOT_MODE; + +// +// 0x21 - 0xf..f are reserved. +// +#define BOOT_WITH_FULL_CONFIGURATION 0x00 +#define BOOT_WITH_MINIMAL_CONFIGURATION 0x01 +#define BOOT_ASSUMING_NO_CONFIGURATION_CHANGES 0x02 +#define BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS 0x03 +#define BOOT_WITH_DEFAULT_SETTINGS 0x04 +#define BOOT_ON_S4_RESUME 0x05 +#define BOOT_ON_S5_RESUME 0x06 +#define BOOT_ON_S2_RESUME 0x10 +#define BOOT_ON_S3_RESUME 0x11 +#define BOOT_ON_FLASH_UPDATE 0x12 +#define BOOT_IN_RECOVERY_MODE 0x20 + +#endif diff --git a/gpxe/src/include/gpxe/efi/Pi/PiDependency.h b/gpxe/src/include/gpxe/efi/Pi/PiDependency.h new file mode 100644 index 00000000..1f96154d --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Pi/PiDependency.h @@ -0,0 +1,47 @@ +/** @file + Present the dependency expression values in PI. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + Version 1.0. + +**/ +#ifndef __PI_DEPENDENCY_H__ +#define __PI_DEPENDENCY_H__ + +/// +/// If present, this must be the first and only opcode, +/// EFI_DEP_BEFORE is only used by DXE driver. +/// +#define EFI_DEP_BEFORE 0x00 + +/// +/// If present, this must be the first and only opcode, +/// EFI_DEP_AFTER is only used by DXE driver. +/// +#define EFI_DEP_AFTER 0x01 + +#define EFI_DEP_PUSH 0x02 +#define EFI_DEP_AND 0x03 +#define EFI_DEP_OR 0x04 +#define EFI_DEP_NOT 0x05 +#define EFI_DEP_TRUE 0x06 +#define EFI_DEP_FALSE 0x07 +#define EFI_DEP_END 0x08 + + +/// +/// If present, this must be the first opcode, +/// EFI_DEP_SOR is only used by DXE driver. +/// +#define EFI_DEP_SOR 0x09 + +#endif diff --git a/gpxe/src/include/gpxe/efi/Pi/PiDxeCis.h b/gpxe/src/include/gpxe/efi/Pi/PiDxeCis.h new file mode 100644 index 00000000..b57f89d8 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Pi/PiDxeCis.h @@ -0,0 +1,642 @@ +/** @file + Include file matches things in PI. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + Version 1.0. + +**/ + +#ifndef __PI_DXECIS_H__ +#define __PI_DXECIS_H__ + +#include + +/// +/// Global Coherencey Domain types - Memory type +/// +typedef enum { + EfiGcdMemoryTypeNonExistent, + EfiGcdMemoryTypeReserved, + EfiGcdMemoryTypeSystemMemory, + EfiGcdMemoryTypeMemoryMappedIo, + EfiGcdMemoryTypeMaximum +} EFI_GCD_MEMORY_TYPE; + +/// +/// Global Coherencey Domain types - IO type +/// +typedef enum { + EfiGcdIoTypeNonExistent, + EfiGcdIoTypeReserved, + EfiGcdIoTypeIo, + EfiGcdIoTypeMaximum +} EFI_GCD_IO_TYPE; + +/// +/// The type of allocation to perform. +/// +typedef enum { + EfiGcdAllocateAnySearchBottomUp, + EfiGcdAllocateMaxAddressSearchBottomUp, + EfiGcdAllocateAddress, + EfiGcdAllocateAnySearchTopDown, + EfiGcdAllocateMaxAddressSearchTopDown, + EfiGcdMaxAllocateType +} EFI_GCD_ALLOCATE_TYPE; + +/// +/// EFI_GCD_MEMORY_SPACE_DESCRIPTOR +/// +typedef struct { + /// + /// The physical address of the first byte in the memory region. Type + /// EFI_PHYSICAL_ADDRESS is defined in the AllocatePages() function + /// description in the UEFI 2.0 specification + /// + EFI_PHYSICAL_ADDRESS BaseAddress; + + /// + /// The number of bytes in the memory region. + /// + UINT64 Length; + + /// + /// The bit mask of attributes that the memory region is capable of supporting. The bit + /// mask of available attributes is defined in the GetMemoryMap() function description + /// in the UEFI 2.0 specification. + /// + UINT64 Capabilities; + /// + /// The bit mask of attributes that the memory region is currently using. The bit mask of + /// available attributes is defined in GetMemoryMap(). + /// + UINT64 Attributes; + /// + /// Type of the memory region. Type EFI_GCD_MEMORY_TYPE is defined in the + /// AddMemorySpace() function description + /// + EFI_GCD_MEMORY_TYPE GcdMemoryType; + + /// + /// The image handle of the agent that allocated the memory resource described by + /// PhysicalStart and NumberOfBytes. If this field is NULL, then the memory + /// resource is not currently allocated. Type EFI_HANDLE is defined in + /// InstallProtocolInterface() in the UEFI 2.0 specification. + /// + EFI_HANDLE ImageHandle; + + /// + /// The device handle for which the memory resource has been allocated. If + /// ImageHandle is NULL, then the memory resource is not currently allocated. If this + /// field is NULL, then the memory resource is not associated with a device that is + /// described by a device handle. Type EFI_HANDLE is defined in + /// InstallProtocolInterface() in the UEFI 2.0 specification. + /// + EFI_HANDLE DeviceHandle; +} EFI_GCD_MEMORY_SPACE_DESCRIPTOR; + +/// +/// EFI_GCD_IO_SPACE_DESCRIPTOR +/// +typedef struct { + /// + /// Physical address of the first byte in the I/O region. Type + /// EFI_PHYSICAL_ADDRESS is defined in the AllocatePages() function + /// description in the UEFI 2.0 specification. + /// + EFI_PHYSICAL_ADDRESS BaseAddress; + + /// + /// Number of bytes in the I/O region. + /// + UINT64 Length; + + /// + /// Type of the I/O region. Type EFI_GCD_IO_TYPE is defined in the + /// AddIoSpace() function description. + /// + EFI_GCD_IO_TYPE GcdIoType; + + /// + /// The image handle of the agent that allocated the I/O resource described by + /// PhysicalStart and NumberOfBytes. If this field is NULL, then the I/O + /// resource is not currently allocated. Type EFI_HANDLE is defined in + /// InstallProtocolInterface() in the UEFI 2.0 specification. + /// + EFI_HANDLE ImageHandle; + + /// + /// The device handle for which the I/O resource has been allocated. If ImageHandle + /// is NULL, then the I/O resource is not currently allocated. If this field is NULL, then + /// the I/O resource is not associated with a device that is described by a device handle. + /// Type EFI_HANDLE is defined in InstallProtocolInterface() in the UEFI + /// 2.0 specification. + /// + EFI_HANDLE DeviceHandle; +} EFI_GCD_IO_SPACE_DESCRIPTOR; + + +/** + Adds reserved memory, system memory, or memory-mapped I/O resources to the + global coherency domain of the processor. + + @param GcdMemoryType The type of memory resource being added. + @param BaseAddress The physical address that is the start address + of the memory resource being added. + @param Length The size, in bytes, of the memory resource that + is being added. + @param Capabilities The bit mask of attributes that the memory + resource region supports. + + @retval EFI_SUCCESS The memory resource was added to the global + coherency domain of the processor. + @retval EFI_INVALID_PARAMETER GcdMemoryType is invalid. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to add + the memory resource to the global coherency + domain of the processor. + @retval EFI_UNSUPPORTED The processor does not support one or more bytes + of the memory resource range specified by + BaseAddress and Length. + @retval EFI_ACCESS_DENIED One or more bytes of the memory resource range + specified by BaseAddress and Length conflicts + with a memory resource range that was previously + added to the global coherency domain of the processor. + @retval EFI_ACCESS_DENIED One or more bytes of the memory resource range + specified by BaseAddress and Length was allocated + in a prior call to AllocateMemorySpace().. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ADD_MEMORY_SPACE)( + IN EFI_GCD_MEMORY_TYPE GcdMemoryType, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Capabilities + ); + +/** + Allocates nonexistent memory, reserved memory, system memory, or memorymapped + I/O resources from the global coherency domain of the processor. + + @param GcdAllocateType The type of allocation to perform. + @param GcdMemoryType The type of memory resource being allocated. + @param Alignment The log base 2 of the boundary that BaseAddress must + be aligned on output. Align with 2^Alignment. + @param Length The size in bytes of the memory resource range that + is being allocated. + @param BaseAddress A pointer to a physical address to allocate. + @param Imagehandle The image handle of the agent that is allocating + the memory resource. + @param DeviceHandle The device handle for which the memory resource + is being allocated. + + @retval EFI_INVALID_PARAMETER GcdAllocateType is invalid. + @retval EFI_INVALID_PARAMETER GcdMemoryType is invalid. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_INVALID_PARAMETER BaseAddress is NULL. + @retval EFI_INVALID_PARAMETER ImageHandle is NULL. + @retval EFI_NOT_FOUND The memory resource request could not be satisfied. + No descriptor contains the desired space. + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to allocate the memory + resource from the global coherency domain of the processor. + @retval EFI_SUCCESS The memory resource was allocated from the global coherency + domain of the processor. + + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ALLOCATE_MEMORY_SPACE)( + IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType, + IN EFI_GCD_MEMORY_TYPE GcdMemoryType, + IN UINTN Alignment, + IN UINT64 Length, + IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE DeviceHandle OPTIONAL + ); + +/** + Frees nonexistent memory, reserved memory, system memory, or memory-mapped + I/O resources from the global coherency domain of the processor. + + @param BaseAddress The physical address that is the start address of the memory resource being freed. + @param Length The size in bytes of the memory resource range that is being freed. + + @retval EFI_SUCCESS The memory resource was freed from the global coherency domain of + the processor. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory + resource range specified by BaseAddress and Length. + @retval EFI_NOT_FOUND The memory resource range specified by BaseAddress and + Length was not allocated with previous calls to AllocateMemorySpace(). + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to free the memory resource + from the global coherency domain of the processor. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FREE_MEMORY_SPACE)( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +/** + Removes reserved memory, system memory, or memory-mapped I/O resources from + the global coherency domain of the processor. + + @param BaseAddress The physical address that is the start address of the memory resource being removed. + @param Length The size in bytes of the memory resource that is being removed. + + @retval EFI_SUCCESS The memory resource was removed from the global coherency + domain of the processor. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory + resource range specified by BaseAddress and Length. + @retval EFI_NOT_FOUND One or more bytes of the memory resource range specified by + BaseAddress and Length was not added with previous calls to + AddMemorySpace(). + @retval EFI_ACCESS_DEFINED One or more bytes of the memory resource range specified by + BaseAddress and Length has been allocated with AllocateMemorySpace(). + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to remove the memory + resource from the global coherency domain of the processor. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_REMOVE_MEMORY_SPACE)( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +/** + Retrieves the descriptor for a memory region containing a specified address. + + @param BaseAddress The physical address that is the start address of a memory region. + @param Descriptor A pointer to a caller allocated descriptor. + + @retval EFI_SUCCESS The descriptor for the memory resource region containing + BaseAddress was returned in Descriptor. + @retval EFI_INVALID_PARAMETER Descriptor is NULL. + @retval EFI_NOT_FOUND A memory resource range containing BaseAddress was not found. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_MEMORY_SPACE_DESCRIPTOR)( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor + ); + +/** + Modifies the attributes for a memory region in the global coherency domain of the + processor. + + @param BaseAddress The physical address that is the start address of a memory region. + @param Length The size in bytes of the memory region. + @param Attributes The bit mask of attributes to set for the memory region. + + @retval EFI_SUCCESS The attributes were set for the memory region. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory + resource range specified by BaseAddress and Length. + @retval EFI_UNSUPPORTED The bit mask of attributes is not support for the memory resource + range specified by BaseAddress and Length. + @retval EFI_ACCESS_DEFINED The attributes for the memory resource range specified by + BaseAddress and Length cannot be modified. + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of + the memory resource range. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SET_MEMORY_SPACE_ATTRIBUTES)( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ); + +/** + Returns a map of the memory resources in the global coherency domain of the + processor. + + @param NumberOfDescriptors A pointer to number of descriptors returned in the MemorySpaceMap buffer. + @param MemorySpaceMap A pointer to the array of EFI_GCD_MEMORY_SPACE_DESCRIPTORs. + + @retval EFI_SUCCESS The memory space map was returned in the MemorySpaceMap + buffer, and the number of descriptors in MemorySpaceMap was + returned in NumberOfDescriptors. + @retval EFI_INVALID_PARAMETER NumberOfDescriptors is NULL. + @retval EFI_INVALID_PARAMETER MemorySpaceMap is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate MemorySpaceMap. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_MEMORY_SPACE_MAP)( + OUT UINTN *NumberOfDescriptors, + OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap + ); + +/** + Adds reserved I/O or I/O resources to the global coherency domain of the processor. + + @param GcdIoType The type of I/O resource being added. + @param BaseAddress The physical address that is the start address of the I/O resource being added. + @param Length The size in bytes of the I/O resource that is being added. + + @retval EFI_SUCCESS The I/O resource was added to the global coherency domain of + the processor. + @retval EFI_INVALID_PARAMETER GcdIoType is invalid. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to add the I/O resource to + the global coherency domain of the processor. + @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the I/O + resource range specified by BaseAddress and Length. + @retval EFI_ACCESS_DENIED One or more bytes of the I/O resource range specified by + BaseAddress and Length conflicts with an I/O resource + range that was previously added to the global coherency domain + of the processor. + @retval EFI_ACCESS_DENIED One or more bytes of the I/O resource range specified by + BaseAddress and Length was allocated in a prior call to + AllocateIoSpace(). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ADD_IO_SPACE)( + IN EFI_GCD_IO_TYPE GcdIoType, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +/** + Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency + domain of the processor. + + @param GcdAllocateType The type of allocation to perform. + @param GcdIoType The type of I/O resource being allocated. + @param Alignment The log base 2 of the boundary that BaseAddress must be aligned on output. + @param Length The size in bytes of the I/O resource range that is being allocated. + @param BaseAddress A pointer to a physical address. + @param Imagehandle The image handle of the agent that is allocating the I/O resource. + @param DeviceHandle The device handle for which the I/O resource is being allocated. + + @retval EFI_SUCCESS The I/O resource was allocated from the global coherency domain + of the processor. + @retval EFI_INVALID_PARAMETER GcdAllocateType is invalid. + @retval EFI_INVALID_PARAMETER GcdIoType is invalid. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_INVALID_PARAMETER BaseAddress is NULL. + @retval EFI_INVALID_PARAMETER ImageHandle is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to allocate the I/O + resource from the global coherency domain of the processor. + @retval EFI_NOT_FOUND The I/O resource request could not be satisfied. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ALLOCATE_IO_SPACE)( + IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType, + IN EFI_GCD_IO_TYPE GcdIoType, + IN UINTN Alignment, + IN UINT64 Length, + IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE DeviceHandle OPTIONAL + ); + +/** + Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency + domain of the processor. + + @param BaseAddress The physical address that is the start address of the I/O resource being freed. + @param Length The size in bytes of the I/O resource range that is being freed. + + @retval EFI_SUCCESS The I/O resource was freed from the global coherency domain of the + processor. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the I/O resource + range specified by BaseAddress and Length. + @retval EFI_NOT_FOUND The I/O resource range specified by BaseAddress and Length + was not allocated with previous calls to AllocateIoSpace(). + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to free the I/O resource from + the global coherency domain of the processor. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FREE_IO_SPACE)( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +/** + Removes reserved I/O or I/O resources from the global coherency domain of the + processor. + + @param BaseAddress A pointer to a physical address that is the start address of the I/O resource being + removed. + @param Length The size in bytes of the I/O resource that is being removed. + + @retval EFI_SUCCESS The I/O resource was removed from the global coherency domain + of the processor. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the I/O + resource range specified by BaseAddress and Length. + @retval EFI_NOT_FOUND One or more bytes of the I/O resource range specified by + BaseAddress and Length was not added with previous + calls to AddIoSpace(). + @retval EFI_ACCESS_DENIED One or more bytes of the I/O resource range specified by + BaseAddress and Length has been allocated with + AllocateIoSpace(). + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to remove the I/O + resource from the global coherency domain of the processor. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_REMOVE_IO_SPACE)( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +/** + Retrieves the descriptor for an I/O region containing a specified address. + + @param BaseAddress The physical address that is the start address of an I/O region. + @param Descriptor A pointer to a caller allocated descriptor. + + @retval EFI_SUCCESS The descriptor for the I/O resource region containing + BaseAddress was returned in Descriptor. + @retval EFI_INVALID_PARAMETER Descriptor is NULL. + @retval EFI_NOT_FOUND An I/O resource range containing BaseAddress was not found. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_IO_SPACE_DESCRIPTOR)( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + OUT EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor + ); + +/** + Returns a map of the I/O resources in the global coherency domain of the processor. + + @param NumberOfDescriptors A pointer to number of descriptors returned in the IoSpaceMap buffer. + @param MemorySpaceMap A pointer to the array of EFI_GCD_IO_SPACE_DESCRIPTORs. + + @retval EFI_SUCCESS The I/O space map was returned in the IoSpaceMap buffer, and + the number of descriptors in IoSpaceMap was returned in + NumberOfDescriptors. + @retval EFI_INVALID_PARAMETER NumberOfDescriptors is NULL. + @retval EFI_INVALID_PARAMETER IoSpaceMap is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate IoSpaceMap. + + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_IO_SPACE_MAP)( + OUT UINTN *NumberOfDescriptors, + OUT EFI_GCD_IO_SPACE_DESCRIPTOR **IoSpaceMap + ); + + + +/** + Loads and executed DXE drivers from firmware volumes. + + The Dispatch() function searches for DXE drivers in firmware volumes that have been + installed since the last time the Dispatch() service was called. It then evaluates + the dependency expressions of all the DXE drivers and loads and executes those DXE + drivers whose dependency expression evaluate to TRUE. This service must interact with + the Security Architectural Protocol to authenticate DXE drivers before they are executed. + This process is continued until no more DXE drivers can be executed. + + @retval EFI_SUCCESS One or more DXE driver were dispatched. + @retval EFI_NOT_FOUND No DXE drivers were dispatched. + @retval EFI_ALREADY_STARTED An attempt is being made to start the DXE Dispatcher recursively. + Thus no action was taken. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DISPATCH)( + VOID + ); + +/** + Clears the Schedule on Request (SOR) flag for a component that is stored in a firmware volume. + + @param FirmwareVolumeHandle The handle of the firmware volume that contains the file specified by FileName. + @param FileName A pointer to the name of the file in a firmware volume. + + @retval EFI_SUCCESS The DXE driver was found and its SOR bit was cleared. + @retval EFI_NOT_FOUND The DXE driver does not exist, or the DXE driver exists and its SOR + bit is not set. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SCHEDULE)( + IN EFI_HANDLE FirmwareVolumeHandle, + IN CONST EFI_GUID *FileName + ); + +/** + Promotes a file stored in a firmware volume from the untrusted to the trusted state. + + @param FirmwareVolumeHandle The handle of the firmware volume that contains the file specified by FileName. + @param DriverName A pointer to the name of the file in a firmware volume. + + @return Status of promoting FFS from untrusted to trusted + state. + @retval EFI_NOT_FOUND The file was not found in the untrusted state. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TRUST)( + IN EFI_HANDLE FirmwareVolumeHandle, + IN CONST EFI_GUID *FileName + ); + +/** + Creates a firmware volume handle for a firmware volume that is present in system memory. + + @param FirmwareVolumeHeader A pointer to the header of the firmware volume. + @param Size The size, in bytes, of the firmware volume. + @param FirmwareVolumeHandle On output, a pointer to the created handle. + + @retval EFI_SUCCESS The EFI_FIRMWARE_VOLUME_PROTOCOL and + EFI_DEVICE_PATH_PROTOCOL were installed onto + FirmwareVolumeHandle for the firmware volume described + by FirmwareVolumeHeader and Size. + @retval EFI_VOLUME_CORRUPTED The firmware volume described by FirmwareVolumeHeader + and Size is corrupted. + @retval EFI_OUT_OF_RESOURCES There are not enough system resources available to produce the + EFI_FIRMWARE_VOLUME_PROTOCOL and EFI_DEVICE_PATH_PROTOCOL + for the firmware volume described by FirmwareVolumeHeader and Size. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PROCESS_FIRMWARE_VOLUME)( + IN CONST VOID *FirmwareVolumeHeader, + IN UINTN Size, + OUT EFI_HANDLE *FirmwareVolumeHandle + ); + +// +// DXE Services Table +// +#define DXE_SERVICES_SIGNATURE 0x565245535f455844ULL +#define DXE_SERVICES_REVISION ((1<<16) | (00)) + +typedef struct { + EFI_TABLE_HEADER Hdr; + + // + // Global Coherency Domain Services + // + EFI_ADD_MEMORY_SPACE AddMemorySpace; + EFI_ALLOCATE_MEMORY_SPACE AllocateMemorySpace; + EFI_FREE_MEMORY_SPACE FreeMemorySpace; + EFI_REMOVE_MEMORY_SPACE RemoveMemorySpace; + EFI_GET_MEMORY_SPACE_DESCRIPTOR GetMemorySpaceDescriptor; + EFI_SET_MEMORY_SPACE_ATTRIBUTES SetMemorySpaceAttributes; + EFI_GET_MEMORY_SPACE_MAP GetMemorySpaceMap; + EFI_ADD_IO_SPACE AddIoSpace; + EFI_ALLOCATE_IO_SPACE AllocateIoSpace; + EFI_FREE_IO_SPACE FreeIoSpace; + EFI_REMOVE_IO_SPACE RemoveIoSpace; + EFI_GET_IO_SPACE_DESCRIPTOR GetIoSpaceDescriptor; + EFI_GET_IO_SPACE_MAP GetIoSpaceMap; + + // + // Dispatcher Services + // + EFI_DISPATCH Dispatch; + EFI_SCHEDULE Schedule; + EFI_TRUST Trust; + // + // Service to process a single firmware volume found in a capsule + // + EFI_PROCESS_FIRMWARE_VOLUME ProcessFirmwareVolume; +} DXE_SERVICES; + +typedef DXE_SERVICES EFI_DXE_SERVICES; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Pi/PiFirmwareFile.h b/gpxe/src/include/gpxe/efi/Pi/PiFirmwareFile.h new file mode 100644 index 00000000..a25e98c5 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Pi/PiFirmwareFile.h @@ -0,0 +1,242 @@ +/** @file + The firmware file related definitions in PI. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + Version 1.0. + +**/ + + +#ifndef __PI_FIRMWARE_FILE_H__ +#define __PI_FIRMWARE_FILE_H__ + +#include + +#pragma pack(1) +/// +/// Used to verify the integrity of the file. +/// +typedef union { + struct { + UINT8 Header; + UINT8 File; + } Checksum; + UINT16 Checksum16; +} EFI_FFS_INTEGRITY_CHECK; + +typedef UINT8 EFI_FV_FILETYPE; +typedef UINT8 EFI_FFS_FILE_ATTRIBUTES; +typedef UINT8 EFI_FFS_FILE_STATE; + +/// +/// File Types Definitions +/// +#define EFI_FV_FILETYPE_ALL 0x00 +#define EFI_FV_FILETYPE_RAW 0x01 +#define EFI_FV_FILETYPE_FREEFORM 0x02 +#define EFI_FV_FILETYPE_SECURITY_CORE 0x03 +#define EFI_FV_FILETYPE_PEI_CORE 0x04 +#define EFI_FV_FILETYPE_DXE_CORE 0x05 +#define EFI_FV_FILETYPE_PEIM 0x06 +#define EFI_FV_FILETYPE_DRIVER 0x07 +#define EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER 0x08 +#define EFI_FV_FILETYPE_APPLICATION 0x09 +#define EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE 0x0B +#define EFI_FV_FILETYPE_OEM_MIN 0xc0 +#define EFI_FV_FILETYPE_OEM_MAX 0xdf +#define EFI_FV_FILETYPE_DEBUG_MIN 0xe0 +#define EFI_FV_FILETYPE_DEBUG_MAX 0xef +#define EFI_FV_FILETYPE_FFS_MIN 0xf0 +#define EFI_FV_FILETYPE_FFS_MAX 0xff +#define EFI_FV_FILETYPE_FFS_PAD 0xf0 +/// +/// FFS File Attributes. +/// +#define FFS_ATTRIB_FIXED 0x04 +#define FFS_ATTRIB_DATA_ALIGNMENT 0x38 +#define FFS_ATTRIB_CHECKSUM 0x40 + +/// +/// FFS File State Bits. +/// +#define EFI_FILE_HEADER_CONSTRUCTION 0x01 +#define EFI_FILE_HEADER_VALID 0x02 +#define EFI_FILE_DATA_VALID 0x04 +#define EFI_FILE_MARKED_FOR_UPDATE 0x08 +#define EFI_FILE_DELETED 0x10 +#define EFI_FILE_HEADER_INVALID 0x20 + + +/// +/// Each file begins with the header that describe the +/// contents and state of the files. +/// +typedef struct { + EFI_GUID Name; + EFI_FFS_INTEGRITY_CHECK IntegrityCheck; + EFI_FV_FILETYPE Type; + EFI_FFS_FILE_ATTRIBUTES Attributes; + UINT8 Size[3]; + EFI_FFS_FILE_STATE State; +} EFI_FFS_FILE_HEADER; + + +typedef UINT8 EFI_SECTION_TYPE; + +/// +/// Pseudo type. It is +/// used as a wild card when retrieving sections. The section +/// type EFI_SECTION_ALL matches all section types. +/// +#define EFI_SECTION_ALL 0x00 + +/// +/// Encapsulation section Type values +/// +#define EFI_SECTION_COMPRESSION 0x01 + +#define EFI_SECTION_GUID_DEFINED 0x02 + +/// +/// Leaf section Type values +/// +#define EFI_SECTION_PE32 0x10 +#define EFI_SECTION_PIC 0x11 +#define EFI_SECTION_TE 0x12 +#define EFI_SECTION_DXE_DEPEX 0x13 +#define EFI_SECTION_VERSION 0x14 +#define EFI_SECTION_USER_INTERFACE 0x15 +#define EFI_SECTION_COMPATIBILITY16 0x16 +#define EFI_SECTION_FIRMWARE_VOLUME_IMAGE 0x17 +#define EFI_SECTION_FREEFORM_SUBTYPE_GUID 0x18 +#define EFI_SECTION_RAW 0x19 +#define EFI_SECTION_PEI_DEPEX 0x1B + +/// +/// Common section header +/// +typedef struct { + UINT8 Size[3]; + EFI_SECTION_TYPE Type; +} EFI_COMMON_SECTION_HEADER; + +/// +/// Leaf section type that contains an +/// IA-32 16-bit executable image. +/// +typedef EFI_COMMON_SECTION_HEADER EFI_COMPATIBILITY16_SECTION; + +/// +/// CompressionType of EFI_COMPRESSION_SECTION. +/// +#define EFI_NOT_COMPRESSED 0x00 +#define EFI_STANDARD_COMPRESSION 0x01 +/// +/// An encapsulation section type in which the +/// section data is compressed. +/// +typedef struct { + EFI_COMMON_SECTION_HEADER CommonHeader; + UINT32 UncompressedLength; + UINT8 CompressionType; +} EFI_COMPRESSION_SECTION; + +/// +/// Leaf section which could be used to determine the dispatch order of DXEs. +/// +typedef EFI_COMMON_SECTION_HEADER EFI_DXE_DEPEX_SECTION; + +/// +/// Leaf section witch contains a PI FV. +/// +typedef EFI_COMMON_SECTION_HEADER EFI_FIRMWARE_VOLUME_IMAGE_SECTION; + +/// +/// Leaf section which contains a single GUID. +/// +typedef struct { + EFI_COMMON_SECTION_HEADER CommonHeader; + EFI_GUID SubTypeGuid; +} EFI_FREEFORM_SUBTYPE_GUID_SECTION; + +/// +/// Attributes of EFI_GUID_DEFINED_SECTION +/// +#define EFI_GUIDED_SECTION_PROCESSING_REQUIRED 0x01 +#define EFI_GUIDED_SECTION_AUTH_STATUS_VALID 0x02 +/// +/// Leaf section which is encapsulation defined by specific GUID +/// +typedef struct { + EFI_COMMON_SECTION_HEADER CommonHeader; + EFI_GUID SectionDefinitionGuid; + UINT16 DataOffset; + UINT16 Attributes; +} EFI_GUID_DEFINED_SECTION; + +/// +/// Leaf section which contains PE32+ image. +/// +typedef EFI_COMMON_SECTION_HEADER EFI_PE32_SECTION; + + +/// +/// Leaf section which used to determine the dispatch order of PEIMs. +/// +typedef EFI_COMMON_SECTION_HEADER EFI_PEI_DEPEX_SECTION; + +/// +/// Leaf section which constains the position-independent-code image. +/// +typedef EFI_COMMON_SECTION_HEADER EFI_TE_SECTION; + +/// +/// Leaf section which contains an array of zero or more bytes. +/// +typedef EFI_COMMON_SECTION_HEADER EFI_RAW_SECTION; + +/// +/// Leaf section which contains a unicode string that +/// is human readable file name. +/// +typedef struct { + EFI_COMMON_SECTION_HEADER CommonHeader; + + /// + /// Array of unicode string. + /// + CHAR16 FileNameString[1]; +} EFI_USER_INTERFACE_SECTION; + + +/// +/// Leaf section which contains a numeric build number and +/// an optional unicode string that represent the file revision. +/// +typedef struct { + EFI_COMMON_SECTION_HEADER CommonHeader; + UINT16 BuildNumber; + + /// + /// Array of unicode string. + /// + CHAR16 VersionString[1]; +} EFI_VERSION_SECTION; + + +#define SECTION_SIZE(SectionHeaderPtr) \ + ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) SectionHeaderPtr)->Size) & 0x00ffffff)) + +#pragma pack() + +#endif + diff --git a/gpxe/src/include/gpxe/efi/Pi/PiFirmwareVolume.h b/gpxe/src/include/gpxe/efi/Pi/PiFirmwareVolume.h new file mode 100644 index 00000000..39c81b19 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Pi/PiFirmwareVolume.h @@ -0,0 +1,154 @@ +/** @file + The firmware volume related definitions in PI. + + Copyright (c) 2006 - 2007, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + Version 1.0. + +**/ + +#ifndef __PI_FIRMWAREVOLUME_H__ +#define __PI_FIRMWAREVOLUME_H__ + +#include + +/// +/// EFI_FV_FILE_ATTRIBUTES +/// +typedef UINT32 EFI_FV_FILE_ATTRIBUTES; + +// +// Value of EFI_FV_FILE_ATTRIBUTES. +// +#define EFI_FV_FILE_ATTRIB_ALIGNMENT 0x0000001F +#define EFI_FV_FILE_ATTRIB_FIXED 0x00000100 +#define EFI_FV_FILE_ATTRIB_MEMORY_MAPPED 0x00000200 + +/// +/// type of EFI FVB attribute +/// +typedef UINT32 EFI_FVB_ATTRIBUTES_2; + +// +// Attributes bit definitions +// +#define EFI_FVB2_READ_DISABLED_CAP 0x00000001 +#define EFI_FVB2_READ_ENABLED_CAP 0x00000002 +#define EFI_FVB2_READ_STATUS 0x00000004 +#define EFI_FVB2_WRITE_DISABLED_CAP 0x00000008 +#define EFI_FVB2_WRITE_ENABLED_CAP 0x00000010 +#define EFI_FVB2_WRITE_STATUS 0x00000020 +#define EFI_FVB2_LOCK_CAP 0x00000040 +#define EFI_FVB2_LOCK_STATUS 0x00000080 +#define EFI_FVB2_STICKY_WRITE 0x00000200 +#define EFI_FVB2_MEMORY_MAPPED 0x00000400 +#define EFI_FVB2_ERASE_POLARITY 0x00000800 +#define EFI_FVB2_READ_LOCK_CAP 0x00001000 +#define EFI_FVB2_READ_LOCK_STATUS 0x00002000 +#define EFI_FVB2_WRITE_LOCK_CAP 0x00004000 +#define EFI_FVB2_WRITE_LOCK_STATUS 0x00008000 +#define EFI_FVB2_ALIGNMENT 0x001F0000 +#define EFI_FVB2_ALIGNMENT_1 0x00000000 +#define EFI_FVB2_ALIGNMENT_2 0x00010000 +#define EFI_FVB2_ALIGNMENT_4 0x00020000 +#define EFI_FVB2_ALIGNMENT_8 0x00030000 +#define EFI_FVB2_ALIGNMENT_16 0x00040000 +#define EFI_FVB2_ALIGNMENT_32 0x00050000 +#define EFI_FVB2_ALIGNMENT_64 0x00060000 +#define EFI_FVB2_ALIGNMENT_128 0x00070000 +#define EFI_FVB2_ALIGNMENT_256 0x00080000 +#define EFI_FVB2_ALIGNMENT_512 0x00090000 +#define EFI_FVB2_ALIGNMENT_1K 0x000A0000 +#define EFI_FVB2_ALIGNMENT_2K 0x000B0000 +#define EFI_FVB2_ALIGNMENT_4K 0x000C0000 +#define EFI_FVB2_ALIGNMENT_8K 0x000D0000 +#define EFI_FVB2_ALIGNMENT_16K 0x000E0000 +#define EFI_FVB2_ALIGNMENT_32K 0x000F0000 +#define EFI_FVB2_ALIGNMENT_64K 0x00100000 +#define EFI_FVB2_ALIGNMENT_128K 0x00110000 +#define EFI_FVB2_ALIGNMENT_256K 0x00120000 +#define EFI_FVB2_ALIGNMNET_512K 0x00130000 +#define EFI_FVB2_ALIGNMENT_1M 0x00140000 +#define EFI_FVB2_ALIGNMENT_2M 0x00150000 +#define EFI_FVB2_ALIGNMENT_4M 0x00160000 +#define EFI_FVB2_ALIGNMENT_8M 0x00170000 +#define EFI_FVB2_ALIGNMENT_16M 0x00180000 +#define EFI_FVB2_ALIGNMENT_32M 0x00190000 +#define EFI_FVB2_ALIGNMENT_64M 0x001A0000 +#define EFI_FVB2_ALIGNMENT_128M 0x001B0000 +#define EFI_FVB2_ALIGNMENT_256M 0x001C0000 +#define EFI_FVB2_ALIGNMENT_512M 0x001D0000 +#define EFI_FVB2_ALIGNMENT_1G 0x001E0000 +#define EFI_FVB2_ALIGNMENT_2G 0x001F0000 + + +typedef struct { + UINT32 NumBlocks; + UINT32 Length; +} EFI_FV_BLOCK_MAP_ENTRY; + +/// +/// Describes the features and layout of the firmware volume. +/// +typedef struct { + UINT8 ZeroVector[16]; + EFI_GUID FileSystemGuid; + UINT64 FvLength; + UINT32 Signature; + EFI_FVB_ATTRIBUTES_2 Attributes; + UINT16 HeaderLength; + UINT16 Checksum; + UINT16 ExtHeaderOffset; + UINT8 Reserved[1]; + UINT8 Revision; + EFI_FV_BLOCK_MAP_ENTRY BlockMap[1]; +} EFI_FIRMWARE_VOLUME_HEADER; + +#define EFI_FVH_SIGNATURE EFI_SIGNATURE_32 ('_', 'F', 'V', 'H') + +/// +/// Firmware Volume Header Revision definition +/// +#define EFI_FVH_REVISION 0x02 + +/// +/// Extension header pointed by ExtHeaderOffset of volume header. +/// +typedef struct { + EFI_GUID FvName; + UINT32 ExtHeaderSize; +} EFI_FIRMWARE_VOLUME_EXT_HEADER; + +/// +/// Entry struture for describing FV extension header +/// +typedef struct { + UINT16 ExtEntrySize; + UINT16 ExtEntryType; +} EFI_FIRMWARE_VOLUME_EXT_ENTRY; + +#define EFI_FV_EXT_TYPE_OEM_TYPE 0x01 +/// +/// This extension header provides a mapping between a GUID and an OEM file type. +/// +typedef struct { + EFI_FIRMWARE_VOLUME_EXT_ENTRY Hdr; + UINT32 TypeMask; + + // + // Array of GUIDs. + // Each GUID represents an OEM file type. + // + EFI_GUID Types[1]; +} EFI_FIRMWARE_VOLUME_EXT_ENTRY_OEM_TYPE; + + +#endif diff --git a/gpxe/src/include/gpxe/efi/Pi/PiHob.h b/gpxe/src/include/gpxe/efi/Pi/PiHob.h new file mode 100644 index 00000000..1a695d7e --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Pi/PiHob.h @@ -0,0 +1,293 @@ +/** @file + HOB related definitions in PI. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + Version 1.0. + +**/ + +#ifndef __PI_HOB_H__ +#define __PI_HOB_H__ + +#include +#include +#include +#include + +// +// HobType of EFI_HOB_GENERIC_HEADER. +// +#define EFI_HOB_TYPE_HANDOFF 0x0001 +#define EFI_HOB_TYPE_MEMORY_ALLOCATION 0x0002 +#define EFI_HOB_TYPE_RESOURCE_DESCRIPTOR 0x0003 +#define EFI_HOB_TYPE_GUID_EXTENSION 0x0004 +#define EFI_HOB_TYPE_FV 0x0005 +#define EFI_HOB_TYPE_CPU 0x0006 +#define EFI_HOB_TYPE_MEMORY_POOL 0x0007 +#define EFI_HOB_TYPE_FV2 0x0009 +#define EFI_HOB_TYPE_LOAD_PEIM 0x000A +#define EFI_HOB_TYPE_UNUSED 0xFFFE +#define EFI_HOB_TYPE_END_OF_HOB_LIST 0xFFFF + +/// +/// Describes the format and size of the data inside the HOB. +/// All HOBs must contain this generic HOB header. +/// +typedef struct { + UINT16 HobType; + UINT16 HobLength; + UINT32 Reserved; +} EFI_HOB_GENERIC_HEADER; + + +/// +/// Value of version ofinEFI_HOB_HANDOFF_INFO_TABLE. +/// +#define EFI_HOB_HANDOFF_TABLE_VERSION 0x0009 + +/// +/// Contains general state information used by the HOB producer phase. +/// This HOB must be the first one in the HOB list. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + UINT32 Version; + EFI_BOOT_MODE BootMode; + EFI_PHYSICAL_ADDRESS EfiMemoryTop; + EFI_PHYSICAL_ADDRESS EfiMemoryBottom; + EFI_PHYSICAL_ADDRESS EfiFreeMemoryTop; + EFI_PHYSICAL_ADDRESS EfiFreeMemoryBottom; + EFI_PHYSICAL_ADDRESS EfiEndOfHobList; +} EFI_HOB_HANDOFF_INFO_TABLE; + +/// +/// EFI_HOB_MEMORY_ALLOCATION_HEADER describes the +/// various attributes of the logical memory allocation. The type field will be used for +/// subsequent inclusion in the UEFI memory map. +/// +typedef struct { + /// + /// A GUID that defines the memory allocation region¡¯s type and purpose, as well as + /// other fields within the memory allocation HOB. This GUID is used to define the + /// additional data within the HOB that may be present for the memory allocation HOB. + /// Type EFI_GUID is defined in InstallProtocolInterface() in the UEFI 2.0 + /// specification. + /// + EFI_GUID Name; + + /// The base address of memory allocated by this HOB. Type + /// EFI_PHYSICAL_ADDRESS is defined in AllocatePages() in the UEFI 2.0 + /// specification. + EFI_PHYSICAL_ADDRESS MemoryBaseAddress; + + /// + /// The length in bytes of memory allocated by this HOB. + /// + UINT64 MemoryLength; + + /// + /// Defines the type of memory allocated by this HOB. The memory type definition + /// follows the EFI_MEMORY_TYPE definition. Type EFI_MEMORY_TYPE is defined + /// in AllocatePages() in the UEFI 2.0 specification. + /// + EFI_MEMORY_TYPE MemoryType; + + /// + /// Padding for Itanium processor family + /// + UINT8 Reserved[4]; +} EFI_HOB_MEMORY_ALLOCATION_HEADER; + +/// +/// Describes all memory ranges used during the HOB producer +/// phase that exist outside the HOB list. This HOB type +/// describes how memory is used, +/// not the physical attributes of memory. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_HOB_MEMORY_ALLOCATION_HEADER AllocDescriptor; + // + // Additional data pertaining to the "Name" Guid memory + // may go here. + // +} EFI_HOB_MEMORY_ALLOCATION; + + +/// +/// Describes the memory stack that is produced by the HOB producer +/// phase and upon which all postmemory-installed executable +/// content in the HOB producer phase is executing. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_HOB_MEMORY_ALLOCATION_HEADER AllocDescriptor; +} EFI_HOB_MEMORY_ALLOCATION_STACK; + +/// +/// Defines the location of the boot-strap +/// processor (BSP) BSPStore ("Backing Store Pointer Store"). +/// This HOB is valid for the Itanium processor family only +/// register overflow store. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_HOB_MEMORY_ALLOCATION_HEADER AllocDescriptor; +} EFI_HOB_MEMORY_ALLOCATION_BSP_STORE; + +/// +/// Defines the location and entry point of the HOB consumer phase. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_HOB_MEMORY_ALLOCATION_HEADER MemoryAllocationHeader; + EFI_GUID ModuleName; + EFI_PHYSICAL_ADDRESS EntryPoint; +} EFI_HOB_MEMORY_ALLOCATION_MODULE; + +/// +/// type of Recount type +/// +typedef UINT32 EFI_RESOURCE_TYPE; + +// +// Value of ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR. +// +#define EFI_RESOURCE_SYSTEM_MEMORY 0x00000000 +#define EFI_RESOURCE_MEMORY_MAPPED_IO 0x00000001 +#define EFI_RESOURCE_IO 0x00000002 +#define EFI_RESOURCE_FIRMWARE_DEVICE 0x00000003 +#define EFI_RESOURCE_MEMORY_MAPPED_IO_PORT 0x00000004 +#define EFI_RESOURCE_MEMORY_RESERVED 0x00000005 +#define EFI_RESOURCE_IO_RESERVED 0x00000006 +#define EFI_RESOURCE_MAX_MEMORY_TYPE 0x00000007 + +/// +/// type of recount attribute type +/// +typedef UINT32 EFI_RESOURCE_ATTRIBUTE_TYPE; + +// +// These types can be ORed together as needed. +// +// The first three enumerations describe settings +// +#define EFI_RESOURCE_ATTRIBUTE_PRESENT 0x00000001 +#define EFI_RESOURCE_ATTRIBUTE_INITIALIZED 0x00000002 +#define EFI_RESOURCE_ATTRIBUTE_TESTED 0x00000004 +// +// The rest of the settings describe capabilities +// +#define EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC 0x00000008 +#define EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC 0x00000010 +#define EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1 0x00000020 +#define EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2 0x00000040 +#define EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED 0x00000080 +#define EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED 0x00000100 +#define EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED 0x00000200 +#define EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE 0x00000400 +#define EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE 0x00000800 +#define EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE 0x00001000 +#define EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE 0x00002000 +#define EFI_RESOURCE_ATTRIBUTE_16_BIT_IO 0x00004000 +#define EFI_RESOURCE_ATTRIBUTE_32_BIT_IO 0x00008000 +#define EFI_RESOURCE_ATTRIBUTE_64_BIT_IO 0x00010000 +#define EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED 0x00020000 + +/// +/// Describes the resource properties of all fixed, +/// nonrelocatable resource ranges found on the processor +/// host bus during the HOB producer phase. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_GUID Owner; + EFI_RESOURCE_TYPE ResourceType; + EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute; + EFI_PHYSICAL_ADDRESS PhysicalStart; + UINT64 ResourceLength; +} EFI_HOB_RESOURCE_DESCRIPTOR; + +/// +/// Allows writers of executable content in the HOB producer phase to +/// maintain and manage HOBs with specific GUID. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_GUID Name; + + /// + /// Guid specific data goes here + /// +} EFI_HOB_GUID_TYPE; + +/// +/// Details the location of firmware volumes that contain firmware files. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_PHYSICAL_ADDRESS BaseAddress; + UINT64 Length; +} EFI_HOB_FIRMWARE_VOLUME; + +/// +/// Details the location of a firmware volume which was extracted +/// from a file within another firmware volume. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_PHYSICAL_ADDRESS BaseAddress; + UINT64 Length; + EFI_GUID FvName; + EFI_GUID FileName; +} EFI_HOB_FIRMWARE_VOLUME2; + + +/// +/// Describes processor information, such as address space and I/O space capabilities. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + UINT8 SizeOfMemorySpace; + UINT8 SizeOfIoSpace; + UINT8 Reserved[6]; +} EFI_HOB_CPU; + + +/// +/// Describes pool memory allocations. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; +} EFI_HOB_MEMORY_POOL; + +/// +/// Union of all the possible HOB Types +/// +typedef union { + EFI_HOB_GENERIC_HEADER *Header; + EFI_HOB_HANDOFF_INFO_TABLE *HandoffInformationTable; + EFI_HOB_MEMORY_ALLOCATION *MemoryAllocation; + EFI_HOB_MEMORY_ALLOCATION_BSP_STORE *MemoryAllocationBspStore; + EFI_HOB_MEMORY_ALLOCATION_STACK *MemoryAllocationStack; + EFI_HOB_MEMORY_ALLOCATION_MODULE *MemoryAllocationModule; + EFI_HOB_RESOURCE_DESCRIPTOR *ResourceDescriptor; + EFI_HOB_GUID_TYPE *Guid; + EFI_HOB_FIRMWARE_VOLUME *FirmwareVolume; + EFI_HOB_FIRMWARE_VOLUME2 *FirmwareVolume2; + EFI_HOB_CPU *Cpu; + EFI_HOB_MEMORY_POOL *Pool; + UINT8 *Raw; +} EFI_PEI_HOB_POINTERS; + + +#endif diff --git a/gpxe/src/include/gpxe/efi/Pi/PiMultiPhase.h b/gpxe/src/include/gpxe/efi/Pi/PiMultiPhase.h new file mode 100644 index 00000000..9ec013be --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Pi/PiMultiPhase.h @@ -0,0 +1,104 @@ +/** @file + Include file matches things in PI for multiple module types. + + Copyright (c) 2006 - 2007, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + Version 1.0. + +**/ + +#ifndef __PI_MULTIPHASE_H__ +#define __PI_MULTIPHASE_H__ + +#include + +#include +#include +#include + +#include +#include + + +#define EFI_NOT_AVAILABLE_YET EFIERR (32) + +/// +/// Status Code Type Definition +/// +typedef UINT32 EFI_STATUS_CODE_TYPE; + +// +// A Status Code Type is made up of the code type and severity +// All values masked by EFI_STATUS_CODE_RESERVED_MASK are +// reserved for use by this specification. +// +#define EFI_STATUS_CODE_TYPE_MASK 0x000000FF +#define EFI_STATUS_CODE_SEVERITY_MASK 0xFF000000 +#define EFI_STATUS_CODE_RESERVED_MASK 0x00FFFF00 + +// +// Definition of code types, all other values masked by +// EFI_STATUS_CODE_TYPE_MASK are reserved for use by +// this specification. +// +#define EFI_PROGRESS_CODE 0x00000001 +#define EFI_ERROR_CODE 0x00000002 +#define EFI_DEBUG_CODE 0x00000003 + +// +// Definitions of severities, all other values masked by +// EFI_STATUS_CODE_SEVERITY_MASK are reserved for use by +// this specification. +// Uncontained errors are major errors that could not contained +// to the specific component that is reporting the error +// For example, if a memory error was not detected early enough, +// the bad data could be consumed by other drivers. +// +#define EFI_ERROR_MINOR 0x40000000 +#define EFI_ERROR_MAJOR 0x80000000 +#define EFI_ERROR_UNRECOVERED 0x90000000 +#define EFI_ERROR_UNCONTAINED 0xa0000000 + +/// +/// Status Code Value Definition +/// +typedef UINT32 EFI_STATUS_CODE_VALUE; + +// +// A Status Code Value is made up of the class, subclass, and +// an operation. +// +#define EFI_STATUS_CODE_CLASS_MASK 0xFF000000 +#define EFI_STATUS_CODE_SUBCLASS_MASK 0x00FF0000 +#define EFI_STATUS_CODE_OPERATION_MASK 0x0000FFFF + +/// +/// Definition of Status Code extended data header. +/// The data will follow HeaderSize bytes from the beginning of +/// the structure and is Size bytes long. +/// +typedef struct { + UINT16 HeaderSize; + UINT16 Size; + EFI_GUID Type; +} EFI_STATUS_CODE_DATA; + + +// +// Bit values for AuthenticationStatus +// +#define EFI_AUTH_STATUS_PLATFORM_OVERRIDE 0x01 +#define EFI_AUTH_STATUS_IMAGE_SIGNED 0x02 +#define EFI_AUTH_STATUS_NOT_TESTED 0x04 +#define EFI_AUTH_STATUS_TEST_FAILED 0x08 +#define EFI_AUTH_STATUS_ALL 0x0f + +#endif diff --git a/gpxe/src/include/gpxe/efi/PiDxe.h b/gpxe/src/include/gpxe/efi/PiDxe.h new file mode 100644 index 00000000..c3263029 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/PiDxe.h @@ -0,0 +1,25 @@ +/** @file + + Root include file for Mde Package DXE_CORE, DXE, SMM, SAL type modules. + +Copyright (c) 2006 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __PI_DXE_H__ +#define __PI_DXE_H__ + +#include +#include + +#include + +#endif + diff --git a/gpxe/src/include/gpxe/efi/ProcessorBind.h b/gpxe/src/include/gpxe/efi/ProcessorBind.h new file mode 100644 index 00000000..cc5a9852 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/ProcessorBind.h @@ -0,0 +1,10 @@ +/* + * EFI header files rely on having the CPU architecture directory + * present in the search path in order to pick up ProcessorBind.h. We + * use this header file as a quick indirection layer. + * - mcb30 + */ + +#if __i386__ +#include +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/Cpu.h b/gpxe/src/include/gpxe/efi/Protocol/Cpu.h new file mode 100644 index 00000000..6052a34f --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/Cpu.h @@ -0,0 +1,326 @@ +/** @file + CPU Architectural Protocol as defined in PI spec Volume 2 DXE + + This code abstracts the DXE core from processor implementation details. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __ARCH_PROTOCOL_CPU_H__ +#define __ARCH_PROTOCOL_CPU_H__ + +#include + +#define EFI_CPU_ARCH_PROTOCOL_GUID \ + { 0x26baccb1, 0x6f42, 0x11d4, {0xbc, 0xe7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } } + +typedef struct _EFI_CPU_ARCH_PROTOCOL EFI_CPU_ARCH_PROTOCOL; + +typedef enum { + EfiCpuFlushTypeWriteBackInvalidate, + EfiCpuFlushTypeWriteBack, + EfiCpuFlushTypeInvalidate, + EfiCpuMaxFlushType +} EFI_CPU_FLUSH_TYPE; + +typedef enum { + EfiCpuInit, + EfiCpuMaxInitType +} EFI_CPU_INIT_TYPE; + +/** + EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs. + + @param InterruptType Defines the type of interrupt or exception that + occurred on the processor.This parameter is processor architecture specific. + @param SystemContext A pointer to the processor context when + the interrupt occurred on the processor. + + @return None + +**/ +typedef +VOID +(EFIAPI *EFI_CPU_INTERRUPT_HANDLER)( + IN CONST EFI_EXCEPTION_TYPE InterruptType, + IN CONST EFI_SYSTEM_CONTEXT SystemContext + ); + +/** + This function flushes the range of addresses from Start to Start+Length + from the processor's data cache. If Start is not aligned to a cache line + boundary, then the bytes before Start to the preceding cache line boundary + are also flushed. If Start+Length is not aligned to a cache line boundary, + then the bytes past Start+Length to the end of the next cache line boundary + are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be + supported. If the data cache is fully coherent with all DMA operations, then + this function can just return EFI_SUCCESS. If the processor does not support + flushing a range of the data cache, then the entire data cache can be flushed. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + @param Start The beginning physical address to flush from the processor's data + cache. + @param Length The number of bytes to flush from the processor's data cache. This + function may flush more bytes than Length specifies depending upon + the granularity of the flush operation that the processor supports. + @param FlushType Specifies the type of flush operation to perform. + + @retval EFI_SUCCESS The address range from Start to Start+Length was flushed from + the processor's data cache. + @retval EFI_UNSUPPORTEDT The processor does not support the cache flush type specified + by FlushType. + @retval EFI_DEVICE_ERROR The address range from Start to Start+Length could not be flushed + from the processor's data cache. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_FLUSH_DATA_CACHE)( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length, + IN EFI_CPU_FLUSH_TYPE FlushType + ); + + +/** + This function enables interrupt processing by the processor. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + + @retval EFI_SUCCESS Interrupts are enabled on the processor. + @retval EFI_DEVICE_ERROR Interrupts could not be enabled on the processor. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_ENABLE_INTERRUPT)( + IN EFI_CPU_ARCH_PROTOCOL *This + ); + + +/** + This function disables interrupt processing by the processor. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + + @retval EFI_SUCCESS Interrupts are disabled on the processor. + @retval EFI_DEVICE_ERROR Interrupts could not be disabled on the processor. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_DISABLE_INTERRUPT)( + IN EFI_CPU_ARCH_PROTOCOL *This + ); + + +/** + This function retrieves the processor's current interrupt state a returns it in + State. If interrupts are currently enabled, then TRUE is returned. If interrupts + are currently disabled, then FALSE is returned. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + @param State A pointer to the processor's current interrupt state. Set to TRUE if + interrupts are enabled and FALSE if interrupts are disabled. + + @retval EFI_SUCCESS The processor's current interrupt state was returned in State. + @retval EFI_INVALID_PARAMETER State is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_GET_INTERRUPT_STATE)( + IN EFI_CPU_ARCH_PROTOCOL *This, + OUT BOOLEAN *State + ); + + +/** + This function generates an INIT on the processor. If this function succeeds, then the + processor will be reset, and control will not be returned to the caller. If InitType is + not supported by this processor, or the processor cannot programmatically generate an + INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error + occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + @param InitType The type of processor INIT to perform. + + @retval EFI_SUCCESS The processor INIT was performed. This return code should never be seen. + @retval EFI_UNSUPPORTED The processor INIT operation specified by InitType is not supported + by this processor. + @retval EFI_DEVICE_ERROR The processor INIT failed. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_INIT)( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_CPU_INIT_TYPE InitType + ); + + +/** + This function registers and enables the handler specified by InterruptHandler for a processor + interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the + handler for the processor interrupt or exception type specified by InterruptType is uninstalled. + The installed handler is called once for each processor interrupt or exception. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts + are enabled and FALSE if interrupts are disabled. + @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called + when a processor interrupt occurs. If this parameter is NULL, then the handler + will be uninstalled. + + @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was + previously installed. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not + previously installed. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_REGISTER_INTERRUPT_HANDLER)( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ); + + +/** + This function reads the processor timer specified by TimerIndex and returns it in TimerValue. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + @param TimerIndex Specifies which processor timer is to be returned in TimerValue. This parameter + must be between 0 and NumberOfTimers-1. + @param TimerValue Pointer to the returned timer value. + @param TimerPeriod A pointer to the amount of time that passes in femtoseconds for each increment + of TimerValue. + + @retval EFI_SUCCESS The processor timer value specified by TimerIndex was returned in TimerValue. + @retval EFI_DEVICE_ERROR An error occurred attempting to read one of the processor's timers. + @retval EFI_INVALID_PARAMETER TimerValue is NULL or TimerIndex is not valid. + @retval EFI_UNSUPPORTED The processor does not have any readable timers. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_GET_TIMER_VALUE)( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN UINT32 TimerIndex, + OUT UINT64 *TimerValue, + OUT UINT64 *TimerPeriod OPTIONAL + ); + + +/** + This function modifies the attributes for the memory region specified by BaseAddress and + Length from their current attributes to the attributes specified by Attributes. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + @param BaseAddress The physical address that is the start address of a memory region. + @param Length The size in bytes of the memory region. + @param Attributes The bit mask of attributes to set for the memory region. + + @retval EFI_SUCCESS The attributes were set for the memory region. + @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by + BaseAddress and Length cannot be modified. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of + the memory resource range. + @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory + resource range specified by BaseAddress and Length. + The bit mask of attributes is not support for the memory resource + range specified by BaseAddress and Length. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_SET_MEMORY_ATTRIBUTES)( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ); + + +/** + @par Protocol Description: + The EFI_CPU_ARCH_PROTOCOL is used to abstract processor-specific functions from the DXE + Foundation. This includes flushing caches, enabling and disabling interrupts, hooking interrupt + vectors and exception vectors, reading internal processor timers, resetting the processor, and + determining the processor frequency. + + @param FlushDataCache + Flushes a range of the processor's data cache. If the processor does + not contain a data cache, or the data cache is fully coherent, then this + function can just return EFI_SUCCESS. If the processor does not support + flushing a range of addresses from the data cache, then the entire data + cache must be flushed. + + @param EnableInterrupt + Enables interrupt processing by the processor. + + @param DisableInterrupt + Disables interrupt processing by the processor. + + @param GetInterruptState + Retrieves the processor's current interrupt state. + + @param Init + Generates an INIT on the processor. If a processor cannot programmatically + generate an INIT without help from external hardware, then this function + returns EFI_UNSUPPORTED. + + @param RegisterInterruptHandler + Associates an interrupt service routine with one of the processor's interrupt + vectors. This function is typically used by the EFI_TIMER_ARCH_PROTOCOL to + hook the timer interrupt in a system. It can also be used by the debugger to + hook exception vectors. + + @param GetTimerValue + Returns the value of one of the processor's internal timers. + + @param SetMemoryAttributes + Attempts to set the attributes of a memory region. + + @param NumberOfTimers + The number of timers that are available in a processor. The value in this + field is a constant that must not be modified after the CPU Architectural + Protocol is installed. All consumers must treat this as a read-only field. + + @param DmaBufferAlignment + The size, in bytes, of the alignment required for DMA buffer allocations. + This is typically the size of the largest data cache line in the platform. + The value in this field is a constant that must not be modified after the + CPU Architectural Protocol is installed. All consumers must treat this as + a read-only field. + +**/ +struct _EFI_CPU_ARCH_PROTOCOL { + EFI_CPU_FLUSH_DATA_CACHE FlushDataCache; + EFI_CPU_ENABLE_INTERRUPT EnableInterrupt; + EFI_CPU_DISABLE_INTERRUPT DisableInterrupt; + EFI_CPU_GET_INTERRUPT_STATE GetInterruptState; + EFI_CPU_INIT Init; + EFI_CPU_REGISTER_INTERRUPT_HANDLER RegisterInterruptHandler; + EFI_CPU_GET_TIMER_VALUE GetTimerValue; + EFI_CPU_SET_MEMORY_ATTRIBUTES SetMemoryAttributes; + UINT32 NumberOfTimers; + UINT32 DmaBufferAlignment; +}; + +extern EFI_GUID gEfiCpuArchProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/CpuIo.h b/gpxe/src/include/gpxe/efi/Protocol/CpuIo.h new file mode 100644 index 00000000..8d35c6cd --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/CpuIo.h @@ -0,0 +1,128 @@ +/** @file + This code abstracts the CPU IO Protocol which installed by some platform or chipset-specific + PEIM that abstracts the processor-visible I/O operations. + + Copyright (c) 2007, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: CpuIO.h + + @par Revision Reference: + CPU IO Protocol is defined in Framework of EFI CPU IO Protocol Spec + Version 0.9 + +**/ + +#ifndef _CPUIO_H_ +#define _CPUIO_H_ + +#include + +#define EFI_CPU_IO_PROTOCOL_GUID \ + { \ + 0xB0732526, 0x38C8, 0x4b40, {0x88, 0x77, 0x61, 0xC7, 0xB0, 0x6A, 0xAC, 0x45 } \ + } + +typedef struct _EFI_CPU_IO_PROTOCOL EFI_CPU_IO_PROTOCOL; + +// +// ******************************************************* +// EFI_CPU_IO_PROTOCOL_WIDTH +// ******************************************************* +// +typedef enum { + EfiCpuIoWidthUint8, + EfiCpuIoWidthUint16, + EfiCpuIoWidthUint32, + EfiCpuIoWidthUint64, + EfiCpuIoWidthFifoUint8, + EfiCpuIoWidthFifoUint16, + EfiCpuIoWidthFifoUint32, + EfiCpuIoWidthFifoUint64, + EfiCpuIoWidthFillUint8, + EfiCpuIoWidthFillUint16, + EfiCpuIoWidthFillUint32, + EfiCpuIoWidthFillUint64, + EfiCpuIoWidthMaximum +} EFI_CPU_IO_PROTOCOL_WIDTH; + +// +// ******************************************************* +// EFI_CPU_IO_PROTOCOL_IO_MEM +// ******************************************************* +// +/** + Enables a driver to access memory-mapped registers in the EFI system memory space. + Or, Enables a driver to access registers in the EFI CPU I/O space. + + @param This A pointer to the EFI_CPU_IO_PROTOCOL instance. + @param Width Signifies the width of the I/O or Memory operation. + @param Address The base address of the I/O or Memoryoperation. + @param Count The number of I/O or Memory operations to perform. + The number of bytes moved is Width size * Count, starting at Address. + @param Buffer For read operations, the destination buffer to store the results. + For write operations, the source buffer from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the EFI system. + @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system.Or Buffer is NULL. + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. + Or,The address range specified by Address, Width, and Count is not valid for this EFI system. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_IO_PROTOCOL_IO_MEM)( + IN EFI_CPU_IO_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +// +// ******************************************************* +// EFI_CPU_IO_PROTOCOL_ACCESS +// ******************************************************* +// +typedef struct { + EFI_CPU_IO_PROTOCOL_IO_MEM Read; + EFI_CPU_IO_PROTOCOL_IO_MEM Write; +} EFI_CPU_IO_PROTOCOL_ACCESS; + +// +// ******************************************************* +// EFI_CPU_IO_PROTOCOL +// ******************************************************* +// +/** + @par Protocol Description: + Provides the basic memory and I/O interfaces that are used to abstract + accesses to devices in a system. + + @param Mem.Read + Allows reads from memory-mapped I/O space. + + @param Mem.Write + Allows writes to memory-mapped I/O space. + + @param Io.Read + Allows reads from I/O space. + + @param Io.Write + Allows writes to I/O space. + +**/ +struct _EFI_CPU_IO_PROTOCOL { + EFI_CPU_IO_PROTOCOL_ACCESS Mem; + EFI_CPU_IO_PROTOCOL_ACCESS Io; +}; + +extern EFI_GUID gEfiCpuIoProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/DebugSupport.h b/gpxe/src/include/gpxe/efi/Protocol/DebugSupport.h new file mode 100644 index 00000000..6f785a17 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/DebugSupport.h @@ -0,0 +1,656 @@ +/** @file + DebugSupport protocol and supporting definitions as defined in the UEFI2.0 + specification. + + The DebugSupport protocol is used by source level debuggers to abstract the + processor and handle context save and restore operations. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __DEBUG_SUPPORT_H__ +#define __DEBUG_SUPPORT_H__ + +#include +#include + +typedef struct _EFI_DEBUG_SUPPORT_PROTOCOL EFI_DEBUG_SUPPORT_PROTOCOL; + +/// +/// Debug Support protocol {2755590C-6F3C-42FA-9EA4-A3BA543CDA25} +/// +#define EFI_DEBUG_SUPPORT_PROTOCOL_GUID \ + { \ + 0x2755590C, 0x6F3C, 0x42FA, {0x9E, 0xA4, 0xA3, 0xBA, 0x54, 0x3C, 0xDA, 0x25 } \ + } + +/// +/// Debug Support definitions +/// +typedef INTN EFI_EXCEPTION_TYPE; + +// +// IA-32 processor exception types +// +#define EXCEPT_IA32_DIVIDE_ERROR 0 +#define EXCEPT_IA32_DEBUG 1 +#define EXCEPT_IA32_NMI 2 +#define EXCEPT_IA32_BREAKPOINT 3 +#define EXCEPT_IA32_OVERFLOW 4 +#define EXCEPT_IA32_BOUND 5 +#define EXCEPT_IA32_INVALID_OPCODE 6 +#define EXCEPT_IA32_DOUBLE_FAULT 8 +#define EXCEPT_IA32_INVALID_TSS 10 +#define EXCEPT_IA32_SEG_NOT_PRESENT 11 +#define EXCEPT_IA32_STACK_FAULT 12 +#define EXCEPT_IA32_GP_FAULT 13 +#define EXCEPT_IA32_PAGE_FAULT 14 +#define EXCEPT_IA32_FP_ERROR 16 +#define EXCEPT_IA32_ALIGNMENT_CHECK 17 +#define EXCEPT_IA32_MACHINE_CHECK 18 +#define EXCEPT_IA32_SIMD 19 + +// +// IA-32 processor context definition +// +// +// FXSAVE_STATE +// FP / MMX / XMM registers (see fxrstor instruction definition) +// +typedef struct { + UINT16 Fcw; + UINT16 Fsw; + UINT16 Ftw; + UINT16 Opcode; + UINT32 Eip; + UINT16 Cs; + UINT16 Reserved1; + UINT32 DataOffset; + UINT16 Ds; + UINT8 Reserved2[10]; + UINT8 St0Mm0[10], Reserved3[6]; + UINT8 St1Mm1[10], Reserved4[6]; + UINT8 St2Mm2[10], Reserved5[6]; + UINT8 St3Mm3[10], Reserved6[6]; + UINT8 St4Mm4[10], Reserved7[6]; + UINT8 St5Mm5[10], Reserved8[6]; + UINT8 St6Mm6[10], Reserved9[6]; + UINT8 St7Mm7[10], Reserved10[6]; + UINT8 Xmm0[16]; + UINT8 Xmm1[16]; + UINT8 Xmm2[16]; + UINT8 Xmm3[16]; + UINT8 Xmm4[16]; + UINT8 Xmm5[16]; + UINT8 Xmm6[16]; + UINT8 Xmm7[16]; + UINT8 Reserved11[14 * 16]; +} EFI_FX_SAVE_STATE_IA32; + +typedef struct { + UINT32 ExceptionData; + EFI_FX_SAVE_STATE_IA32 FxSaveState; + UINT32 Dr0; + UINT32 Dr1; + UINT32 Dr2; + UINT32 Dr3; + UINT32 Dr6; + UINT32 Dr7; + UINT32 Cr0; + UINT32 Cr1; /* Reserved */ + UINT32 Cr2; + UINT32 Cr3; + UINT32 Cr4; + UINT32 Eflags; + UINT32 Ldtr; + UINT32 Tr; + UINT32 Gdtr[2]; + UINT32 Idtr[2]; + UINT32 Eip; + UINT32 Gs; + UINT32 Fs; + UINT32 Es; + UINT32 Ds; + UINT32 Cs; + UINT32 Ss; + UINT32 Edi; + UINT32 Esi; + UINT32 Ebp; + UINT32 Esp; + UINT32 Ebx; + UINT32 Edx; + UINT32 Ecx; + UINT32 Eax; +} EFI_SYSTEM_CONTEXT_IA32; + +// +// X64 processor exception types +// +#define EXCEPT_X64_DIVIDE_ERROR 0 +#define EXCEPT_X64_DEBUG 1 +#define EXCEPT_X64_NMI 2 +#define EXCEPT_X64_BREAKPOINT 3 +#define EXCEPT_X64_OVERFLOW 4 +#define EXCEPT_X64_BOUND 5 +#define EXCEPT_X64_INVALID_OPCODE 6 +#define EXCEPT_X64_DOUBLE_FAULT 8 +#define EXCEPT_X64_INVALID_TSS 10 +#define EXCEPT_X64_SEG_NOT_PRESENT 11 +#define EXCEPT_X64_STACK_FAULT 12 +#define EXCEPT_X64_GP_FAULT 13 +#define EXCEPT_X64_PAGE_FAULT 14 +#define EXCEPT_X64_FP_ERROR 16 +#define EXCEPT_X64_ALIGNMENT_CHECK 17 +#define EXCEPT_X64_MACHINE_CHECK 18 +#define EXCEPT_X64_SIMD 19 + +// +// X64 processor context definition +// +// FXSAVE_STATE +// FP / MMX / XMM registers (see fxrstor instruction definition) +// +typedef struct { + UINT16 Fcw; + UINT16 Fsw; + UINT16 Ftw; + UINT16 Opcode; + UINT64 Rip; + UINT64 DataOffset; + UINT8 Reserved1[8]; + UINT8 St0Mm0[10], Reserved2[6]; + UINT8 St1Mm1[10], Reserved3[6]; + UINT8 St2Mm2[10], Reserved4[6]; + UINT8 St3Mm3[10], Reserved5[6]; + UINT8 St4Mm4[10], Reserved6[6]; + UINT8 St5Mm5[10], Reserved7[6]; + UINT8 St6Mm6[10], Reserved8[6]; + UINT8 St7Mm7[10], Reserved9[6]; + UINT8 Xmm0[16]; + UINT8 Xmm1[16]; + UINT8 Xmm2[16]; + UINT8 Xmm3[16]; + UINT8 Xmm4[16]; + UINT8 Xmm5[16]; + UINT8 Xmm6[16]; + UINT8 Xmm7[16]; + // + // NOTE: UEFI 2.0 spec definition as follows. + // + UINT8 Reserved11[14 * 16]; +} EFI_FX_SAVE_STATE_X64; + +typedef struct { + UINT64 ExceptionData; + EFI_FX_SAVE_STATE_X64 FxSaveState; + UINT64 Dr0; + UINT64 Dr1; + UINT64 Dr2; + UINT64 Dr3; + UINT64 Dr6; + UINT64 Dr7; + UINT64 Cr0; + UINT64 Cr1; /* Reserved */ + UINT64 Cr2; + UINT64 Cr3; + UINT64 Cr4; + UINT64 Cr8; + UINT64 Rflags; + UINT64 Ldtr; + UINT64 Tr; + UINT64 Gdtr[2]; + UINT64 Idtr[2]; + UINT64 Rip; + UINT64 Gs; + UINT64 Fs; + UINT64 Es; + UINT64 Ds; + UINT64 Cs; + UINT64 Ss; + UINT64 Rdi; + UINT64 Rsi; + UINT64 Rbp; + UINT64 Rsp; + UINT64 Rbx; + UINT64 Rdx; + UINT64 Rcx; + UINT64 Rax; + UINT64 R8; + UINT64 R9; + UINT64 R10; + UINT64 R11; + UINT64 R12; + UINT64 R13; + UINT64 R14; + UINT64 R15; +} EFI_SYSTEM_CONTEXT_X64; + +// +// IPF processor exception types +// +#define EXCEPT_IPF_VHTP_TRANSLATION 0 +#define EXCEPT_IPF_INSTRUCTION_TLB 1 +#define EXCEPT_IPF_DATA_TLB 2 +#define EXCEPT_IPF_ALT_INSTRUCTION_TLB 3 +#define EXCEPT_IPF_ALT_DATA_TLB 4 +#define EXCEPT_IPF_DATA_NESTED_TLB 5 +#define EXCEPT_IPF_INSTRUCTION_KEY_MISSED 6 +#define EXCEPT_IPF_DATA_KEY_MISSED 7 +#define EXCEPT_IPF_DIRTY_BIT 8 +#define EXCEPT_IPF_INSTRUCTION_ACCESS_BIT 9 +#define EXCEPT_IPF_DATA_ACCESS_BIT 10 +#define EXCEPT_IPF_BREAKPOINT 11 +#define EXCEPT_IPF_EXTERNAL_INTERRUPT 12 +// +// 13 - 19 reserved +// +#define EXCEPT_IPF_PAGE_NOT_PRESENT 20 +#define EXCEPT_IPF_KEY_PERMISSION 21 +#define EXCEPT_IPF_INSTRUCTION_ACCESS_RIGHTS 22 +#define EXCEPT_IPF_DATA_ACCESS_RIGHTS 23 +#define EXCEPT_IPF_GENERAL_EXCEPTION 24 +#define EXCEPT_IPF_DISABLED_FP_REGISTER 25 +#define EXCEPT_IPF_NAT_CONSUMPTION 26 +#define EXCEPT_IPF_SPECULATION 27 +// +// 28 reserved +// +#define EXCEPT_IPF_DEBUG 29 +#define EXCEPT_IPF_UNALIGNED_REFERENCE 30 +#define EXCEPT_IPF_UNSUPPORTED_DATA_REFERENCE 31 +#define EXCEPT_IPF_FP_FAULT 32 +#define EXCEPT_IPF_FP_TRAP 33 +#define EXCEPT_IPF_LOWER_PRIVILEGE_TRANSFER_TRAP 34 +#define EXCEPT_IPF_TAKEN_BRANCH 35 +#define EXCEPT_IPF_SINGLE_STEP 36 +// +// 37 - 44 reserved +// +#define EXCEPT_IPF_IA32_EXCEPTION 45 +#define EXCEPT_IPF_IA32_INTERCEPT 46 +#define EXCEPT_IPF_IA32_INTERRUPT 47 + +// +// IPF processor context definition +// +typedef struct { + // + // The first reserved field is necessary to preserve alignment for the correct + // bits in UNAT and to insure F2 is 16 byte aligned.. + // + UINT64 Reserved; + UINT64 R1; + UINT64 R2; + UINT64 R3; + UINT64 R4; + UINT64 R5; + UINT64 R6; + UINT64 R7; + UINT64 R8; + UINT64 R9; + UINT64 R10; + UINT64 R11; + UINT64 R12; + UINT64 R13; + UINT64 R14; + UINT64 R15; + UINT64 R16; + UINT64 R17; + UINT64 R18; + UINT64 R19; + UINT64 R20; + UINT64 R21; + UINT64 R22; + UINT64 R23; + UINT64 R24; + UINT64 R25; + UINT64 R26; + UINT64 R27; + UINT64 R28; + UINT64 R29; + UINT64 R30; + UINT64 R31; + + UINT64 F2[2]; + UINT64 F3[2]; + UINT64 F4[2]; + UINT64 F5[2]; + UINT64 F6[2]; + UINT64 F7[2]; + UINT64 F8[2]; + UINT64 F9[2]; + UINT64 F10[2]; + UINT64 F11[2]; + UINT64 F12[2]; + UINT64 F13[2]; + UINT64 F14[2]; + UINT64 F15[2]; + UINT64 F16[2]; + UINT64 F17[2]; + UINT64 F18[2]; + UINT64 F19[2]; + UINT64 F20[2]; + UINT64 F21[2]; + UINT64 F22[2]; + UINT64 F23[2]; + UINT64 F24[2]; + UINT64 F25[2]; + UINT64 F26[2]; + UINT64 F27[2]; + UINT64 F28[2]; + UINT64 F29[2]; + UINT64 F30[2]; + UINT64 F31[2]; + + UINT64 Pr; + + UINT64 B0; + UINT64 B1; + UINT64 B2; + UINT64 B3; + UINT64 B4; + UINT64 B5; + UINT64 B6; + UINT64 B7; + + // + // application registers + // + UINT64 ArRsc; + UINT64 ArBsp; + UINT64 ArBspstore; + UINT64 ArRnat; + + UINT64 ArFcr; + + UINT64 ArEflag; + UINT64 ArCsd; + UINT64 ArSsd; + UINT64 ArCflg; + UINT64 ArFsr; + UINT64 ArFir; + UINT64 ArFdr; + + UINT64 ArCcv; + + UINT64 ArUnat; + + UINT64 ArFpsr; + + UINT64 ArPfs; + UINT64 ArLc; + UINT64 ArEc; + + // + // control registers + // + UINT64 CrDcr; + UINT64 CrItm; + UINT64 CrIva; + UINT64 CrPta; + UINT64 CrIpsr; + UINT64 CrIsr; + UINT64 CrIip; + UINT64 CrIfa; + UINT64 CrItir; + UINT64 CrIipa; + UINT64 CrIfs; + UINT64 CrIim; + UINT64 CrIha; + + // + // debug registers + // + UINT64 Dbr0; + UINT64 Dbr1; + UINT64 Dbr2; + UINT64 Dbr3; + UINT64 Dbr4; + UINT64 Dbr5; + UINT64 Dbr6; + UINT64 Dbr7; + + UINT64 Ibr0; + UINT64 Ibr1; + UINT64 Ibr2; + UINT64 Ibr3; + UINT64 Ibr4; + UINT64 Ibr5; + UINT64 Ibr6; + UINT64 Ibr7; + + // + // virtual registers - nat bits for R1-R31 + // + UINT64 IntNat; + +} EFI_SYSTEM_CONTEXT_IPF; + +// +// EBC processor exception types +// +#define EXCEPT_EBC_UNDEFINED 0 +#define EXCEPT_EBC_DIVIDE_ERROR 1 +#define EXCEPT_EBC_DEBUG 2 +#define EXCEPT_EBC_BREAKPOINT 3 +#define EXCEPT_EBC_OVERFLOW 4 +#define EXCEPT_EBC_INVALID_OPCODE 5 // opcode out of range +#define EXCEPT_EBC_STACK_FAULT 6 +#define EXCEPT_EBC_ALIGNMENT_CHECK 7 +#define EXCEPT_EBC_INSTRUCTION_ENCODING 8 // malformed instruction +#define EXCEPT_EBC_BAD_BREAK 9 // BREAK 0 or undefined BREAK +#define EXCEPT_EBC_STEP 10 // to support debug stepping +/// +/// For coding convenience, define the maximum valid EBC exception. +/// +#define MAX_EBC_EXCEPTION EXCEPT_EBC_STEP + +/// +/// EBC processor context definition +/// +typedef struct { + UINT64 R0; + UINT64 R1; + UINT64 R2; + UINT64 R3; + UINT64 R4; + UINT64 R5; + UINT64 R6; + UINT64 R7; + UINT64 Flags; + UINT64 ControlFlags; + UINT64 Ip; +} EFI_SYSTEM_CONTEXT_EBC; + +/// +/// Universal EFI_SYSTEM_CONTEXT definition +/// +typedef union { + EFI_SYSTEM_CONTEXT_EBC *SystemContextEbc; + EFI_SYSTEM_CONTEXT_IA32 *SystemContextIa32; + EFI_SYSTEM_CONTEXT_X64 *SystemContextX64; + EFI_SYSTEM_CONTEXT_IPF *SystemContextIpf; +} EFI_SYSTEM_CONTEXT; + +// +// DebugSupport callback function prototypes +// + +/** + Registers and enables an exception callback function for the specified exception. + + @param ExceptionType Exception types in EBC, IA-32, X64, or IPF + @param SystemContext Exception content. + +**/ +typedef +VOID +(*EFI_EXCEPTION_CALLBACK)( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ); + +/** + Registers and enables the on-target debug agent's periodic entry point. + + @param SystemContext Exception content. + +**/ +typedef +VOID +(*EFI_PERIODIC_CALLBACK)( + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ); + +// +// Machine type definition +// +typedef enum { + IsaIa32 = IMAGE_FILE_MACHINE_I386, // 0x014C + IsaX64 = IMAGE_FILE_MACHINE_X64, // 0x8664 + IsaIpf = IMAGE_FILE_MACHINE_IA64, // 0x0200 + IsaEbc = IMAGE_FILE_MACHINE_EBC // 0x0EBC +} EFI_INSTRUCTION_SET_ARCHITECTURE; + + +// +// DebugSupport member function definitions +// + +/** + Returns the maximum value that may be used for the ProcessorIndex parameter in + RegisterPeriodicCallback() and RegisterExceptionCallback(). + + @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance. + @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the maximum supported + processor index is returned. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_MAXIMUM_PROCESSOR_INDEX)( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + OUT UINTN *MaxProcessorIndex + ); + +/** + Registers a function to be called back periodically in interrupt context. + + @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance. + @param ProcessorIndex Specifies which processor the callback function applies to. + @param PeriodicCallback A pointer to a function of type PERIODIC_CALLBACK that is the main + periodic entry point of the debug agent. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback + function was previously registered. + @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback + function. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_REGISTER_PERIODIC_CALLBACK)( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_PERIODIC_CALLBACK PeriodicCallback + ); + +/** + Registers a function to be called when a given processor exception occurs. + + @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance. + @param ProcessorIndex Specifies which processor the callback function applies to. + @param PeriodicCallback A pointer to a function of type EXCEPTION_CALLBACK that is called + when the processor exception specified by ExceptionType occurs. + @param ExceptionType Specifies which processor exception to hook. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback + function was previously registered. + @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback + function. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_REGISTER_EXCEPTION_CALLBACK)( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_EXCEPTION_CALLBACK ExceptionCallback, + IN EFI_EXCEPTION_TYPE ExceptionType + ); + +/** + Invalidates processor instruction cache for a memory range. Subsequent execution in this range + causes a fresh memory fetch to retrieve code to be executed. + + @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance. + @param ProcessorIndex Specifies which processor's instruction cache is to be invalidated. + @param Start Specifies the physical base of the memory range to be invalidated. + @param Length Specifies the minimum number of bytes in the processor's instruction + cache to invalidate. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_INVALIDATE_INSTRUCTION_CACHE)( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN VOID *Start, + IN UINT64 Length + ); + +// +// DebugSupport protocol definition +// +/** + @par Protocol Description: + This protocol provides the services to allow the debug agent to register + callback functions that are called either periodically or when specific + processor exceptions occur. + + @param Isa + Declares the processor architecture for this instance of the EFI + Debug Support protocol. + + @param GetMaximumProcessorIndex + Returns the maximum processor index value that may be used. + + @param RegisterPeriodicCallback + Registers a callback function that will be invoked periodically + and asynchronously to the execution of EFI. + + @param RegisterExceptionCallback + Registers a callback function that will be called each time the + specified processor exception occurs. + + @param InvalidateInstructionCache + Invalidate the instruction cache of the processor. This is required + by processor architectures where instruction and data caches are + not coherent when instructions in the code under debug has been + modified by the debug agent. +**/ +struct _EFI_DEBUG_SUPPORT_PROTOCOL { + EFI_INSTRUCTION_SET_ARCHITECTURE Isa; + EFI_GET_MAXIMUM_PROCESSOR_INDEX GetMaximumProcessorIndex; + EFI_REGISTER_PERIODIC_CALLBACK RegisterPeriodicCallback; + EFI_REGISTER_EXCEPTION_CALLBACK RegisterExceptionCallback; + EFI_INVALIDATE_INSTRUCTION_CACHE InvalidateInstructionCache; +}; + +extern EFI_GUID gEfiDebugSupportProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/DevicePath.h b/gpxe/src/include/gpxe/efi/Protocol/DevicePath.h new file mode 100644 index 00000000..5fb7bf66 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/DevicePath.h @@ -0,0 +1,560 @@ +/** @file + The device path protocol as defined in UEFI 2.0. + + The device path represents a programatic path to a device. It's the view + from a software point of view. It also must persist from boot to boot, so + it can not contain things like PCI bus numbers that change from boot to boot. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EFI_DEVICE_PATH_PROTOCOL_H__ +#define __EFI_DEVICE_PATH_PROTOCOL_H__ + +#include + +/// +/// Device Path protocol +/// +#define EFI_DEVICE_PATH_PROTOCOL_GUID \ + { \ + 0x9576e91, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +// +// Protocol GUID defined in EFI1.1. +// + +/// +/// Device Path information +/// +#define DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH_PROTOCOL_GUID + +#pragma pack(1) + +typedef struct { + UINT8 Type; + UINT8 SubType; + UINT8 Length[2]; +} EFI_DEVICE_PATH_PROTOCOL; + +/// +/// For backward-compatible with EFI1.1. +/// +typedef EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH; + +/// +/// Hardware Device Paths +/// +#define HARDWARE_DEVICE_PATH 0x01 + +#define HW_PCI_DP 0x01 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT8 Function; + UINT8 Device; +} PCI_DEVICE_PATH; + +#define HW_PCCARD_DP 0x02 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT8 FunctionNumber; +} PCCARD_DEVICE_PATH; + +#define HW_MEMMAP_DP 0x03 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 MemoryType; + EFI_PHYSICAL_ADDRESS StartingAddress; + EFI_PHYSICAL_ADDRESS EndingAddress; +} MEMMAP_DEVICE_PATH; + +#define HW_VENDOR_DP 0x04 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + EFI_GUID Guid; +} VENDOR_DEVICE_PATH; + +#define HW_CONTROLLER_DP 0x05 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 ControllerNumber; +} CONTROLLER_DEVICE_PATH; + +/// +/// ACPI Device Paths +/// +#define ACPI_DEVICE_PATH 0x02 + +#define ACPI_DP 0x01 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 HID; + UINT32 UID; +} ACPI_HID_DEVICE_PATH; + +#define ACPI_EXTENDED_DP 0x02 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 HID; + UINT32 UID; + UINT32 CID; + /// + /// Optional variable length _HIDSTR + /// Optional variable length _UIDSTR + /// +} ACPI_EXTENDED_HID_DEVICE_PATH; + +// +// EISA ID Macro +// EISA ID Definition 32-bits +// bits[15:0] - three character compressed ASCII EISA ID. +// bits[31:16] - binary number +// Compressed ASCII is 5 bits per character 0b00001 = 'A' 0b11010 = 'Z' +// +#define PNP_EISA_ID_CONST 0x41d0 +#define EISA_ID(_Name, _Num) ((UINT32)((_Name) | (_Num) << 16)) +#define EISA_PNP_ID(_PNPId) (EISA_ID(PNP_EISA_ID_CONST, (_PNPId))) +#define EFI_PNP_ID(_PNPId) (EISA_ID(PNP_EISA_ID_CONST, (_PNPId))) + +#define PNP_EISA_ID_MASK 0xffff +#define EISA_ID_TO_NUM(_Id) ((_Id) >> 16) + + +#define ACPI_ADR_DP 0x03 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 ADR; +} ACPI_ADR_DEVICE_PATH; + +#define ACPI_ADR_DISPLAY_TYPE_OTHER 0 +#define ACPI_ADR_DISPLAY_TYPE_VGA 1 +#define ACPI_ADR_DISPLAY_TYPE_TV 2 +#define ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL 3 +#define ACPI_ADR_DISPLAY_TYPE_INTERNAL_DIGITAL 4 + +#define ACPI_DISPLAY_ADR(_DeviceIdScheme, _HeadId, _NonVgaOutput, _BiosCanDetect, _VendorInfo, _Type, _Port, _Index) \ + ((UINT32)( (((_DeviceIdScheme) & 0x1) << 31) | \ + (((_HeadId) & 0x7) << 18) | \ + (((_NonVgaOutput) & 0x1) << 17) | \ + (((_BiosCanDetect) & 0x1) << 16) | \ + (((_VendorInfo) & 0xf) << 12) | \ + (((_Type) & 0xf) << 8) | \ + (((_Port) & 0xf) << 4) | \ + ((_Index) & 0xf) )) + +/// +/// Messaging Device Paths +/// +#define MESSAGING_DEVICE_PATH 0x03 + +#define MSG_ATAPI_DP 0x01 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT8 PrimarySecondary; + UINT8 SlaveMaster; + UINT16 Lun; +} ATAPI_DEVICE_PATH; + +#define MSG_SCSI_DP 0x02 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT16 Pun; + UINT16 Lun; +} SCSI_DEVICE_PATH; + +#define MSG_FIBRECHANNEL_DP 0x03 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 Reserved; + UINT64 WWN; + UINT64 Lun; +} FIBRECHANNEL_DEVICE_PATH; + +#define MSG_1394_DP 0x04 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 Reserved; + UINT64 Guid; +} F1394_DEVICE_PATH; + +#define MSG_USB_DP 0x05 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT8 ParentPortNumber; + UINT8 InterfaceNumber; +} USB_DEVICE_PATH; + +#define MSG_USB_CLASS_DP 0x0f +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT16 VendorId; + UINT16 ProductId; + UINT8 DeviceClass; + UINT8 DeviceSubClass; + UINT8 DeviceProtocol; +} USB_CLASS_DEVICE_PATH; + +#define MSG_USB_WWID_DP 0x10 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT16 InterfaceNumber; + UINT16 VendorId; + UINT16 ProductId; + // CHAR16 SerialNumber[...]; +} USB_WWID_DEVICE_PATH; + + +#define MSG_DEVICE_LOGICAL_UNIT_DP 0x11 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT8 Lun; +} DEVICE_LOGICAL_UNIT_DEVICE_PATH; + +#define MSG_SATA_DP 0x12 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT16 HBAPortNumber; + UINT16 PortMultiplierPortNumber; + UINT16 Lun; +} SATA_DEVICE_PATH; + +#define MSG_I2O_DP 0x06 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 Tid; +} I2O_DEVICE_PATH; + +#define MSG_MAC_ADDR_DP 0x0b +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + EFI_MAC_ADDRESS MacAddress; + UINT8 IfType; +} MAC_ADDR_DEVICE_PATH; + +#define MSG_IPv4_DP 0x0c +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + EFI_IPv4_ADDRESS LocalIpAddress; + EFI_IPv4_ADDRESS RemoteIpAddress; + UINT16 LocalPort; + UINT16 RemotePort; + UINT16 Protocol; + BOOLEAN StaticIpAddress; +} IPv4_DEVICE_PATH; + +#define MSG_IPv6_DP 0x0d +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + EFI_IPv6_ADDRESS LocalIpAddress; + EFI_IPv6_ADDRESS RemoteIpAddress; + UINT16 LocalPort; + UINT16 RemotePort; + UINT16 Protocol; + BOOLEAN StaticIpAddress; +} IPv6_DEVICE_PATH; + +#define MSG_INFINIBAND_DP 0x09 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 ResourceFlags; + UINT8 PortGid[16]; + UINT64 ServiceId; + UINT64 TargetPortId; + UINT64 DeviceId; +} INFINIBAND_DEVICE_PATH; + +#define INFINIBAND_RESOURCE_FLAG_IOC_SERVICE 0x01 +#define INFINIBAND_RESOURCE_FLAG_EXTENDED_BOOT_ENVIRONMENT 0x02 +#define INFINIBAND_RESOURCE_FLAG_CONSOLE_PROTOCOL 0x04 +#define INFINIBAND_RESOURCE_FLAG_STORAGE_PROTOCOL 0x08 +#define INFINIBAND_RESOURCE_FLAG_NETWORK_PROTOCOL 0x10 + +#define MSG_UART_DP 0x0e +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 Reserved; + UINT64 BaudRate; + UINT8 DataBits; + UINT8 Parity; + UINT8 StopBits; +} UART_DEVICE_PATH; + +// +// Use VENDOR_DEVICE_PATH struct +// +#define MSG_VENDOR_DP 0x0a +typedef VENDOR_DEVICE_PATH VENDOR_DEFINED_DEVICE_PATH; + +#define DEVICE_PATH_MESSAGING_PC_ANSI EFI_PC_ANSI_GUID +#define DEVICE_PATH_MESSAGING_VT_100 EFI_VT_100_GUID +#define DEVICE_PATH_MESSAGING_VT_100_PLUS EFI_VT_100_PLUS_GUID +#define DEVICE_PATH_MESSAGING_VT_UTF8 EFI_VT_UTF8_GUID + +#define DEVICE_PATH_MESSAGING_UART_FLOW_CONTROL EFI_UART_DEVICE_PATH_GUID + +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + EFI_GUID Guid; + UINT32 FlowControlMap; +} UART_FLOW_CONTROL_DEVICE_PATH; + +#define DEVICE_PATH_MESSAGING_SAS EFI_SAS_DEVICE_PATH_GUID + +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + EFI_GUID Guid; + UINT32 Reserved; + UINT64 SasAddress; + UINT64 Lun; + UINT16 DeviceTopology; + UINT16 RelativeTargetPort; +} SAS_DEVICE_PATH; + +#define MSG_ISCSI_DP 0x13 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT16 NetworkProtocol; + UINT16 LoginOption; + UINT64 Lun; + UINT16 TargetPortalGroupTag; + // CHAR8 iSCSI Target Name +} ISCSI_DEVICE_PATH; + +#define ISCSI_LOGIN_OPTION_NO_HEADER_DIGEST 0x0000 +#define ISCSI_LOGIN_OPTION_HEADER_DIGEST_USING_CRC32C 0x0002 +#define ISCSI_LOGIN_OPTION_NO_DATA_DIGEST 0x0000 +#define ISCSI_LOGIN_OPTION_DATA_DIGEST_USING_CRC32C 0x0008 +#define ISCSI_LOGIN_OPTION_AUTHMETHOD_CHAP 0x0000 +#define ISCSI_LOGIN_OPTION_AUTHMETHOD_NON 0x1000 +#define ISCSI_LOGIN_OPTION_CHAP_BI 0x0000 +#define ISCSI_LOGIN_OPTION_CHAP_UNI 0x2000 + +// +// Media Device Path +// +#define MEDIA_DEVICE_PATH 0x04 + +#define MEDIA_HARDDRIVE_DP 0x01 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 PartitionNumber; + UINT64 PartitionStart; + UINT64 PartitionSize; + UINT8 Signature[16]; + UINT8 MBRType; + UINT8 SignatureType; +} HARDDRIVE_DEVICE_PATH; + +#define MBR_TYPE_PCAT 0x01 +#define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02 + +#define SIGNATURE_TYPE_MBR 0x01 +#define SIGNATURE_TYPE_GUID 0x02 + +#define MEDIA_CDROM_DP 0x02 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 BootEntry; + UINT64 PartitionStart; + UINT64 PartitionSize; +} CDROM_DEVICE_PATH; + +// +// Use VENDOR_DEVICE_PATH struct +// +#define MEDIA_VENDOR_DP 0x03 + +#define MEDIA_FILEPATH_DP 0x04 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + CHAR16 PathName[1]; +} FILEPATH_DEVICE_PATH; + +#define SIZE_OF_FILEPATH_DEVICE_PATH EFI_FIELD_OFFSET(FILEPATH_DEVICE_PATH,PathName) + +#define MEDIA_PROTOCOL_DP 0x05 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + EFI_GUID Protocol; +} MEDIA_PROTOCOL_DEVICE_PATH; + + +#define MEDIA_PIWG_FW_VOL_DP 0x7 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + EFI_GUID FvName; +} MEDIA_FW_VOL_DEVICE_PATH; + + +#define MEDIA_PIWG_FW_FILE_DP 0x6 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + EFI_GUID FvFileName; +} MEDIA_FW_VOL_FILEPATH_DEVICE_PATH; + +// +// BBS Device Path +// +#define BBS_DEVICE_PATH 0x05 +#define BBS_BBS_DP 0x01 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT16 DeviceType; + UINT16 StatusFlag; + CHAR8 String[1]; +} BBS_BBS_DEVICE_PATH; + +// +// DeviceType definitions - from BBS specification +// +#define BBS_TYPE_FLOPPY 0x01 +#define BBS_TYPE_HARDDRIVE 0x02 +#define BBS_TYPE_CDROM 0x03 +#define BBS_TYPE_PCMCIA 0x04 +#define BBS_TYPE_USB 0x05 +#define BBS_TYPE_EMBEDDED_NETWORK 0x06 +#define BBS_TYPE_BEV 0x80 +#define BBS_TYPE_UNKNOWN 0xFF + + +/// +/// Union of all possible Device Paths and pointers to Device Paths +/// + +typedef union { + EFI_DEVICE_PATH_PROTOCOL DevPath; + PCI_DEVICE_PATH Pci; + PCCARD_DEVICE_PATH PcCard; + MEMMAP_DEVICE_PATH MemMap; + VENDOR_DEVICE_PATH Vendor; + + CONTROLLER_DEVICE_PATH Controller; + ACPI_HID_DEVICE_PATH Acpi; + + ATAPI_DEVICE_PATH Atapi; + SCSI_DEVICE_PATH Scsi; + ISCSI_DEVICE_PATH Iscsi; + FIBRECHANNEL_DEVICE_PATH FibreChannel; + + F1394_DEVICE_PATH F1394; + USB_DEVICE_PATH Usb; + SATA_DEVICE_PATH Sata; + USB_CLASS_DEVICE_PATH UsbClass; + I2O_DEVICE_PATH I2O; + MAC_ADDR_DEVICE_PATH MacAddr; + IPv4_DEVICE_PATH Ipv4; + IPv6_DEVICE_PATH Ipv6; + INFINIBAND_DEVICE_PATH InfiniBand; + UART_DEVICE_PATH Uart; + + HARDDRIVE_DEVICE_PATH HardDrive; + CDROM_DEVICE_PATH CD; + + FILEPATH_DEVICE_PATH FilePath; + MEDIA_PROTOCOL_DEVICE_PATH MediaProtocol; + + BBS_BBS_DEVICE_PATH Bbs; +} EFI_DEV_PATH; + + + +typedef union { + EFI_DEVICE_PATH_PROTOCOL *DevPath; + PCI_DEVICE_PATH *Pci; + PCCARD_DEVICE_PATH *PcCard; + MEMMAP_DEVICE_PATH *MemMap; + VENDOR_DEVICE_PATH *Vendor; + + CONTROLLER_DEVICE_PATH *Controller; + ACPI_HID_DEVICE_PATH *Acpi; + ACPI_EXTENDED_HID_DEVICE_PATH *ExtendedAcpi; + + ATAPI_DEVICE_PATH *Atapi; + SCSI_DEVICE_PATH *Scsi; + FIBRECHANNEL_DEVICE_PATH *FibreChannel; + + F1394_DEVICE_PATH *F1394; + USB_DEVICE_PATH *Usb; + SATA_DEVICE_PATH *Sata; + USB_CLASS_DEVICE_PATH *UsbClass; + I2O_DEVICE_PATH *I2O; + MAC_ADDR_DEVICE_PATH *MacAddr; + IPv4_DEVICE_PATH *Ipv4; + IPv6_DEVICE_PATH *Ipv6; + INFINIBAND_DEVICE_PATH *InfiniBand; + UART_DEVICE_PATH *Uart; + + HARDDRIVE_DEVICE_PATH *HardDrive; + CDROM_DEVICE_PATH *CD; + + FILEPATH_DEVICE_PATH *FilePath; + MEDIA_PROTOCOL_DEVICE_PATH *MediaProtocol; + + BBS_BBS_DEVICE_PATH *Bbs; + UINT8 *Raw; +} EFI_DEV_PATH_PTR; + +#pragma pack() + +#define EFI_DP_TYPE_MASK 0x7F +#define EFI_DP_TYPE_UNPACKED 0x80 +#define END_DEVICE_PATH_TYPE 0x7f + +#define EFI_END_ENTIRE_DEVICE_PATH 0xff +#define EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff +#define EFI_END_INSTANCE_DEVICE_PATH 0x01 +#define END_ENTIRE_DEVICE_PATH_SUBTYPE EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE +#define END_INSTANCE_DEVICE_PATH_SUBTYPE EFI_END_INSTANCE_DEVICE_PATH + +#define EFI_END_DEVICE_PATH_LENGTH (sizeof (EFI_DEVICE_PATH_PROTOCOL)) +#define END_DEVICE_PATH_LENGTH EFI_END_DEVICE_PATH_LENGTH + +#define DP_IS_END_TYPE(a) +#define DP_IS_END_SUBTYPE(a) (((a)->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE) +#define DevicePathSubType(a) ((a)->SubType) +#define IsDevicePathUnpacked(a) ((a)->Type & EFI_DP_TYPE_UNPACKED) + +#define EfiDevicePathNodeLength(a) (((a)->Length[0]) | ((a)->Length[1] << 8)) +#define DevicePathNodeLength(a) (EfiDevicePathNodeLength(a)) +#define EfiNextDevicePathNode(a) ((EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *) (a)) + EfiDevicePathNodeLength (a))) +#define NextDevicePathNode(a) (EfiNextDevicePathNode(a)) + +#define EfiDevicePathType(a) (((a)->Type) & EFI_DP_TYPE_MASK) +#define DevicePathType(a) (EfiDevicePathType(a)) +#define EfiIsDevicePathEndType(a) (EfiDevicePathType (a) == END_DEVICE_PATH_TYPE) +#define IsDevicePathEndType(a) (EfiIsDevicePathEndType(a)) + + +#define EfiIsDevicePathEndSubType(a) ((a)->SubType == EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE) +#define IsDevicePathEndSubType(a) (EfiIsDevicePathEndSubType(a)) +#define EfiIsDevicePathEndInstanceSubType(a) ((a)->SubType == EFI_END_INSTANCE_DEVICE_PATH) + +#define EfiIsDevicePathEnd(a) (EfiIsDevicePathEndType (a) && EfiIsDevicePathEndSubType (a)) +#define IsDevicePathEnd(a) (EfiIsDevicePathEnd(a)) +#define EfiIsDevicePathEndInstance(a) (EfiIsDevicePathEndType (a) && EfiIsDevicePathEndInstanceSubType (a)) + + +#define SetDevicePathNodeLength(a,l) { \ + (a)->Length[0] = (UINT8) (l); \ + (a)->Length[1] = (UINT8) ((l) >> 8); \ + } + +#define SetDevicePathEndNode(a) { \ + (a)->Type = END_DEVICE_PATH_TYPE; \ + (a)->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; \ + (a)->Length[0] = sizeof(EFI_DEVICE_PATH_PROTOCOL); \ + (a)->Length[1] = 0; \ + } + +extern EFI_GUID gEfiDevicePathProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/DriverBinding.h b/gpxe/src/include/gpxe/efi/Protocol/DriverBinding.h new file mode 100644 index 00000000..9072a288 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/DriverBinding.h @@ -0,0 +1,166 @@ +/** @file + UEFI DriverBinding Protocol is defined in UEFI specification. + + This protocol is produced by every driver that follows the UEFI Driver Model, + and it is the central component that allows drivers and controllers to be managed. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EFI_DRIVER_BINDING_H__ +#define __EFI_DRIVER_BINDING_H__ + +#include +#include +/// +/// Global ID for the ControllerHandle Driver Protocol +/// +#define EFI_DRIVER_BINDING_PROTOCOL_GUID \ + { \ + 0x18a031ab, 0xb443, 0x4d1a, {0xa5, 0xc0, 0xc, 0x9, 0x26, 0x1e, 0x9f, 0x71 } \ + } + +typedef struct _EFI_DRIVER_BINDING_PROTOCOL EFI_DRIVER_BINDING_PROTOCOL; + +/** + Test to see if this driver supports ControllerHandle. + + @param This Protocol instance pointer. + @param ControllerHandle Handle of device to test + @param RemainingDevicePath Optional parameter use to pick a specific child + device to start. + + @retval EFI_SUCCESS This driver supports this device + @retval EFI_ALREADY_STARTED This driver is already running on this device + @retval other This driver does not support this device + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DRIVER_BINDING_SUPPORTED)( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Start this driver on ControllerHandle. + + @param This Protocol instance pointer. + @param ControllerHandle Handle of device to bind driver to + @param RemainingDevicePath Optional parameter use to pick a specific child + device to start. + + @retval EFI_SUCCESS This driver is added to ControllerHandle + @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle + @retval other This driver does not support this device + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DRIVER_BINDING_START)( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Stop this driver on ControllerHandle. + + @param This Protocol instance pointer. + @param ControllerHandle Handle of device to stop driver on + @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of + children is zero stop the entire bus driver. + @param ChildHandleBuffer List of Child Handles to Stop. + + @retval EFI_SUCCESS This driver is removed ControllerHandle + @retval other This driver was not removed from this device + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DRIVER_BINDING_STOP)( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ); + +// +// Interface structure for the ControllerHandle Driver Protocol +// +/** + @par Protocol Description: + This protocol provides the services required to determine if a driver supports a given controller. + If a controller is supported, then it also provides routines to start and stop the controller. + + @param Supported + Tests to see if this driver supports a given controller. This service + is called by the EFI boot service ConnectController(). In + order to make drivers as small as possible, there are a few calling + restrictions for this service. ConnectController() must + follow these calling restrictions. If any other agent wishes to call + Supported() it must also follow these calling restrictions. + + + @param Start + Starts a controller using this driver. This service is called by the + EFI boot service ConnectController(). In order to make + drivers as small as possible, there are a few calling restrictions for + this service. ConnectController() must follow these + calling restrictions. If any other agent wishes to call Start() it + must also follow these calling restrictions. + + @param Stop + Stops a controller using this driver. This service is called by the + EFI boot service DisconnectController(). In order to + make drivers as small as possible, there are a few calling + restrictions for this service. DisconnectController() + must follow these calling restrictions. If any other agent wishes + to call Stop() it must also follow these calling restrictions. + + @param Version + The version number of the UEFI driver that produced the + EFI_DRIVER_BINDING_PROTOCOL. This field is used by + the EFI boot service ConnectController() to determine + the order that driver's Supported() service will be used when + a controller needs to be started. EFI Driver Binding Protocol + instances with higher Version values will be used before ones + with lower Version values. The Version values of 0x0- + 0x0f and 0xfffffff0-0xffffffff are reserved for + platform/OEM specific drivers. The Version values of 0x10- + 0xffffffef are reserved for IHV-developed drivers. + + @param ImageHandle + The image handle of the UEFI driver that produced this instance + of the EFI_DRIVER_BINDING_PROTOCOL. + + @param DriverBindingHandle + The handle on which this instance of the + EFI_DRIVER_BINDING_PROTOCOL is installed. In most + cases, this is the same handle as ImageHandle. However, for + UEFI drivers that produce more than one instance of the + EFI_DRIVER_BINDING_PROTOCOL, this value may not be + the same as ImageHandle. + +**/ +struct _EFI_DRIVER_BINDING_PROTOCOL { + EFI_DRIVER_BINDING_SUPPORTED Supported; + EFI_DRIVER_BINDING_START Start; + EFI_DRIVER_BINDING_STOP Stop; + UINT32 Version; + EFI_HANDLE ImageHandle; + EFI_HANDLE DriverBindingHandle; +}; + +extern EFI_GUID gEfiDriverBindingProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/PciIo.h b/gpxe/src/include/gpxe/efi/Protocol/PciIo.h new file mode 100644 index 00000000..5a241ffc --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/PciIo.h @@ -0,0 +1,577 @@ +/** @file + EFI PCI I/O Protocol provides the basic Memory, I/O, PCI configuration, + and DMA interfaces that a driver uses to access its PCI controller. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __PCI_IO_H__ +#define __PCI_IO_H__ + +/// +/// Global ID for the PCI I/O Protocol +/// +#define EFI_PCI_IO_PROTOCOL_GUID \ + { \ + 0x4cf5b200, 0x68b8, 0x4ca5, {0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x2, 0x9a } \ + } + +typedef struct _EFI_PCI_IO_PROTOCOL EFI_PCI_IO_PROTOCOL; + +/// +/// Prototypes for the PCI I/O Protocol +/// +typedef enum { + EfiPciIoWidthUint8 = 0, + EfiPciIoWidthUint16, + EfiPciIoWidthUint32, + EfiPciIoWidthUint64, + EfiPciIoWidthFifoUint8, + EfiPciIoWidthFifoUint16, + EfiPciIoWidthFifoUint32, + EfiPciIoWidthFifoUint64, + EfiPciIoWidthFillUint8, + EfiPciIoWidthFillUint16, + EfiPciIoWidthFillUint32, + EfiPciIoWidthFillUint64, + EfiPciIoWidthMaximum +} EFI_PCI_IO_PROTOCOL_WIDTH; + +// +// Complete PCI address generater +// +#define EFI_PCI_IO_PASS_THROUGH_BAR 0xff // Special BAR that passes a memory or I/O cycle through unchanged +#define EFI_PCI_IO_ATTRIBUTE_MASK 0x077f // All the following I/O and Memory cycles +#define EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001 // I/O cycles 0x0000-0x00FF (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_ISA_IO 0x0002 // I/O cycles 0x0100-0x03FF or greater (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO 0x0004 // I/O cycles 0x3C6, 0x3C8, 0x3C9 (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY 0x0008 // MEM cycles 0xA0000-0xBFFFF (24 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_IO 0x0010 // I/O cycles 0x3B0-0x3BB and 0x3C0-0x3DF (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO 0x0020 // I/O cycles 0x1F0-0x1F7, 0x3F6, 0x3F7 (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO 0x0040 // I/O cycles 0x170-0x177, 0x376, 0x377 (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080 // Map a memory range so write are combined +#define EFI_PCI_IO_ATTRIBUTE_IO 0x0100 // Enable the I/O decode bit in the PCI Config Header +#define EFI_PCI_IO_ATTRIBUTE_MEMORY 0x0200 // Enable the Memory decode bit in the PCI Config Header +#define EFI_PCI_IO_ATTRIBUTE_BUS_MASTER 0x0400 // Enable the DMA bit in the PCI Config Header +#define EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED 0x0800 // Map a memory range so all r/w accesses are cached +#define EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE 0x1000 // Disable a memory range +#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE 0x2000 // Clear for an add-in PCI Device +#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM 0x4000 // Clear for a physical PCI Option ROM accessed through ROM BAR +#define EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000 // Clear for PCI controllers that can not genrate a DAC +#define EFI_PCI_IO_ATTRIBUTE_ISA_IO_16 0x10000 // I/O cycles 0x0100-0x03FF or greater (16 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000 // I/O cycles 0x3C6, 0x3C8, 0x3C9 (16 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 0x30000 // I/O cycles 0x3B0-0x3BB and 0x3C0-0x3DF (16 bit decode) + +#define EFI_PCI_DEVICE_ENABLE (EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) +#define EFI_VGA_DEVICE_ENABLE (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_IO) + +/// +/// ******************************************************* +/// EFI_PCI_IO_PROTOCOL_OPERATION +/// ******************************************************* +/// +typedef enum { + EfiPciIoOperationBusMasterRead, + EfiPciIoOperationBusMasterWrite, + EfiPciIoOperationBusMasterCommonBuffer, + EfiPciIoOperationMaximum +} EFI_PCI_IO_PROTOCOL_OPERATION; + +/// +/// ******************************************************* +/// EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION +/// ******************************************************* +/// +typedef enum { + EfiPciIoAttributeOperationGet, + EfiPciIoAttributeOperationSet, + EfiPciIoAttributeOperationEnable, + EfiPciIoAttributeOperationDisable, + EfiPciIoAttributeOperationSupported, + EfiPciIoAttributeOperationMaximum +} EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION; + +/** + Reads from the memory space of a PCI controller. Returns when either the polling exit criteria is + satisfied or after a defined duration. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Width Signifies the width of the memory or I/O operations. + @param BarIndex The BAR index of the standard PCI Configuration header to use as the + base address for the memory operation to perform. + @param Offset The offset within the selected BAR to start the memory operation. + @param Mask Mask used for the polling criteria. + @param Value The comparison value used for the polling exit criteria. + @param Delay The number of 100 ns units to poll. + @param Result Pointer to the last value read from the memory location. + + @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria. + @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. + @retval EFI_UNSUPPORTED Offset is not valid for the BarIndex of this PCI controller. + @retval EFI_TIMEOUT Delay expired before a match occurred. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_POLL_IO_MEM)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +/** + Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Width Signifies the width of the memory or I/O operations. + @param BarIndex The BAR index of the standard PCI Configuration header to use as the + base address for the memory or I/O operation to perform. + @param Offset The offset within the selected BAR to start the memory or I/O operation. + @param Count The number of memory or I/O operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI controller. + @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. + @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not + valid for the PCI BAR specified by BarIndex. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_IO_MEM)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +typedef struct { + EFI_PCI_IO_PROTOCOL_IO_MEM Read; + EFI_PCI_IO_PROTOCOL_IO_MEM Write; +} EFI_PCI_IO_PROTOCOL_ACCESS; + +/** + Enable a PCI driver to access PCI controller registers in PCI configuration space. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Width Signifies the width of the memory operations. + @param Offset The offset within the PCI configuration space for the PCI controller. + @param Count The number of PCI configuration operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + + @retval EFI_SUCCESS The data was read from or written to the PCI controller. + @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not + valid for the PCI configuration header of the PCI controller. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_CONFIG)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +typedef struct { + EFI_PCI_IO_PROTOCOL_CONFIG Read; + EFI_PCI_IO_PROTOCOL_CONFIG Write; +} EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS; + +/** + Enables a PCI driver to copy one region of PCI memory space to another region of PCI + memory space. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Width Signifies the width of the memory operations. + @param DestBarIndex The BAR index in the standard PCI Configuration header to use as the + base address for the memory operation to perform. + @param DestOffset The destination offset within the BAR specified by DestBarIndex to + start the memory writes for the copy operation. + @param SrcBarIndex The BAR index in the standard PCI Configuration header to use as the + base address for the memory operation to perform. + @param SrcOffset The source offset within the BAR specified by SrcBarIndex to start + the memory reads for the copy operation. + @param Count The number of memory operations to perform. Bytes moved is Width + size * Count, starting at DestOffset and SrcOffset. + + @retval EFI_SUCCESS The data was copied from one memory region to another memory region. + @retval EFI_UNSUPPORTED DestBarIndex not valid for this PCI controller. + @retval EFI_UNSUPPORTED SrcBarIndex not valid for this PCI controller. + @retval EFI_UNSUPPORTED The address range specified by DestOffset, Width, and Count + is not valid for the PCI BAR specified by DestBarIndex. + @retval EFI_UNSUPPORTED The address range specified by SrcOffset, Width, and Count is + not valid for the PCI BAR specified by SrcBarIndex. + @retval EFI_INVALID_PARAMETER Width is invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_COPY_MEM)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 DestBarIndex, + IN UINT64 DestOffset, + IN UINT8 SrcBarIndex, + IN UINT64 SrcOffset, + IN UINTN Count + ); + +/** + Provides the PCI controller-Cspecific addresses needed to access system memory. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Operation Indicates if the bus master is going to read or write to system memory. + @param HostAddress The system memory address to map to the PCI controller. + @param NumberOfBytes On input the number of bytes to map. On output the number of bytes + that were mapped. + @param DeviceAddress The resulting map address for the bus master PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_MAP)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +/** + Completes the Map() operation and releases any corresponding resources. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_UNMAP)( + IN EFI_PCI_IO_PROTOCOL *This, + IN VOID *Mapping + ); + +/** + Allocates pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer + mapping. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Type This parameter is not used and must be ignored. + @param MemoryType The type of memory to allocate, EfiBootServicesData or + EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory address of the + allocated range. + @param Attributes The requested bit mask of attributes for the allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ); + +/** + Frees memory that was allocated with AllocateBuffer(). + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated range. + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages + was not allocated with AllocateBuffer(). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_FREE_BUFFER)( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINTN Pages, + IN VOID *HostAddress + ); + +/** + Flushes all PCI posted write transactions from a PCI host bridge to system memory. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + + @retval EFI_SUCCESS The PCI posted write transactions were flushed from the PCI host + bridge to system memory. + @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed from the PCI + host bridge due to a hardware error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_FLUSH)( + IN EFI_PCI_IO_PROTOCOL *This + ); + +/** + Retrieves this PCI controller's current PCI bus number, device number, and function number. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param SegmentNumber The PCI controller's current PCI segment number. + @param BusNumber The PCI controller's current PCI bus number. + @param DeviceNumber The PCI controller's current PCI device number. + @param FunctionNumber The PCI controller's current PCI function number. + + @retval EFI_SUCCESS The PCI controller location was returned. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_GET_LOCATION)( + IN EFI_PCI_IO_PROTOCOL *This, + OUT UINTN *SegmentNumber, + OUT UINTN *BusNumber, + OUT UINTN *DeviceNumber, + OUT UINTN *FunctionNumber + ); + +/** + Performs an operation on the attributes that this PCI controller supports. The operations include + getting the set of supported attributes, retrieving the current attributes, setting the current + attributes, enabling attributes, and disabling attributes. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Operation The operation to perform on the attributes for this PCI controller. + @param Attributes The mask of attributes that are used for Set, Enable, and Disable + operations. + @param Result A pointer to the result mask of attributes that are returned for the Get + and Supported operations. + + @retval EFI_SUCCESS The operation on the PCI controller's attributes was completed. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_UNSUPPORTED one or more of the bits set in + Attributes are not supported by this PCI controller or one of + its parent bridges when Operation is Set, Enable or Disable. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_ATTRIBUTES)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation, + IN UINT64 Attributes, + OUT UINT64 *Result OPTIONAL + ); + +/** + Gets the attributes that this PCI controller supports setting on a BAR using + SetBarAttributes(), and retrieves the list of resource descriptors for a BAR. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param BarIndex The BAR index of the standard PCI Configuration header to use as the + base address for resource range. The legal range for this field is 0..5. + @param Supports A pointer to the mask of attributes that this PCI controller supports + setting for this BAR with SetBarAttributes(). + @param Resources A pointer to the ACPI 2.0 resource descriptors that describe the current + configuration of this BAR of the PCI controller. + + @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI + controller supports are returned in Supports. If Resources + is not NULL, then the ACPI 2.0 resource descriptors that the PCI + controller is currently using are returned in Resources. + @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL. + @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate + Resources. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES)( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT8 BarIndex, + OUT UINT64 *Supports, OPTIONAL + OUT VOID **Resources OPTIONAL + ); + +/** + Sets the attributes for a range of a BAR on a PCI controller. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Attributes The mask of attributes to set for the resource range specified by + BarIndex, Offset, and Length. + @param BarIndex The BAR index of the standard PCI Configuration header to use as the + base address for resource range. The legal range for this field is 0..5. + @param Offset A pointer to the BAR relative base address of the resource range to be + modified by the attributes specified by Attributes. + @param Length A pointer to the length of the resource range to be modified by the + attributes specified by Attributes. + + @retval EFI_SUCCESS The set of attributes specified by Attributes for the resource + range specified by BarIndex, Offset, and Length were + set on the PCI controller, and the actual resource range is returned + in Offset and Length. + @retval EFI_INVALID_PARAMETER Offset or Length is NULL. + @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. + @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the attributes on the + resource range specified by BarIndex, Offset, and + Length. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES)( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN UINT8 BarIndex, + IN OUT UINT64 *Offset, + IN OUT UINT64 *Length + ); + +/** + @par Protocol Description: + The EFI_PCI_IO_PROTOCOL provides the basic Memory, I/O, PCI configuration, + and DMA interfaces that are used to abstract accesses to PCI controllers. + There is one EFI_PCI_IO_PROTOCOL instance for each PCI controller on a PCI bus. + A device driver that wishes to manage a PCI controller in a system will have to + retrieve the EFI_PCI_IO_PROTOCOL instance that is associated with the PCI controller. + + @param PollMem + Polls an address in PCI memory space until an exit condition is met, or a timeout occurs. + + @param PollIo + Polls an address in PCI I/O space until an exit condition is met, or a timeout occurs. + + @param Mem.Read + Allows BAR relative reads to PCI memory space. + + @param Mem.Write + Allows BAR relative writes to PCI memory space. + + @param Io.Read + Allows BAR relative reads to PCI I/O space. + + @param Io.Write + Allows BAR relative writes to PCI I/O space. + + @param Pci.Read + Allows PCI controller relative reads to PCI configuration space. + + @param Pci.Write + Allows PCI controller relative writes to PCI configuration space. + + @param CopyMem + Allows one region of PCI memory space to be copied to another region of PCI memory space. + + @param Map + Provides the PCI controller's specific address needed to access system memory for DMA. + + @param Unmap + Releases any resources allocated by Map(). + + @param AllocateBuffer + Allocates pages that are suitable for a common buffer mapping. + + @param FreeBuffer + Frees pages that were allocated with AllocateBuffer(). + + @param Flush + Flushes all PCI posted write transactions to system memory. + + @param GetLocation + Retrieves this PCI controller's current PCI bus number, device number, and function number. + + @param Attributes + Performs an operation on the attributes that this PCI controller supports. + The operations include getting the set of supported attributes, retrieving + the current attributes, setting the current + attributes, enabling attributes, and disabling attributes. + + @param GetBarAttributes + Gets the attributes that this PCI controller supports setting on a BAR using + SetBarAttributes(), and retrieves the list of resource descriptors for a BAR. + + @param SetBarAttributes + Sets the attributes for a range of a BAR on a PCI controller. + + @param RomSize + The size, in bytes, of the ROM image. + + @param RomImage + A pointer to the in memory copy of the ROM image. The PCI Bus Driver is responsible + for allocating memory for the ROM image, and copying the contents of the ROM to memory. + The contents of this buffer are either from the PCI option ROM that can be accessed + through the ROM BAR of the PCI controller, or it is from a platform-specific location. + The Attributes() function can be used to determine from which of these two sources + the RomImage buffer was initialized. + +**/ +struct _EFI_PCI_IO_PROTOCOL { + EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollMem; + EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollIo; + EFI_PCI_IO_PROTOCOL_ACCESS Mem; + EFI_PCI_IO_PROTOCOL_ACCESS Io; + EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS Pci; + EFI_PCI_IO_PROTOCOL_COPY_MEM CopyMem; + EFI_PCI_IO_PROTOCOL_MAP Map; + EFI_PCI_IO_PROTOCOL_UNMAP Unmap; + EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer; + EFI_PCI_IO_PROTOCOL_FREE_BUFFER FreeBuffer; + EFI_PCI_IO_PROTOCOL_FLUSH Flush; + EFI_PCI_IO_PROTOCOL_GET_LOCATION GetLocation; + EFI_PCI_IO_PROTOCOL_ATTRIBUTES Attributes; + EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES GetBarAttributes; + EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES SetBarAttributes; + UINT64 RomSize; + VOID *RomImage; +}; + +extern EFI_GUID gEfiPciIoProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/PciRootBridgeIo.h b/gpxe/src/include/gpxe/efi/Protocol/PciRootBridgeIo.h new file mode 100644 index 00000000..c15c72f7 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/PciRootBridgeIo.h @@ -0,0 +1,450 @@ +/** @file + PCI Root Bridge I/O protocol as defined in the UEFI 2.0 specification. + + PCI Root Bridge I/O protocol is used by PCI Bus Driver to perform PCI Memory, PCI I/O, + and PCI Configuration cycles on a PCI Root Bridge. It also provides services to perform + defferent types of bus mastering DMA + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __PCI_ROOT_BRIDGE_IO_H__ +#define __PCI_ROOT_BRIDGE_IO_H__ + +#include + +#define EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID \ + { \ + 0x2f707ebb, 0x4a1a, 0x11d4, {0x9a, 0x38, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +typedef struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL; + +typedef enum { + EfiPciWidthUint8, + EfiPciWidthUint16, + EfiPciWidthUint32, + EfiPciWidthUint64, + EfiPciWidthFifoUint8, + EfiPciWidthFifoUint16, + EfiPciWidthFifoUint32, + EfiPciWidthFifoUint64, + EfiPciWidthFillUint8, + EfiPciWidthFillUint16, + EfiPciWidthFillUint32, + EfiPciWidthFillUint64, + EfiPciWidthMaximum +} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH; + +typedef enum { + EfiPciOperationBusMasterRead, + EfiPciOperationBusMasterWrite, + EfiPciOperationBusMasterCommonBuffer, + EfiPciOperationBusMasterRead64, + EfiPciOperationBusMasterWrite64, + EfiPciOperationBusMasterCommonBuffer64, + EfiPciOperationMaximum +} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION; + +#define EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001 +#define EFI_PCI_ATTRIBUTE_ISA_IO 0x0002 +#define EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO 0x0004 +#define EFI_PCI_ATTRIBUTE_VGA_MEMORY 0x0008 +#define EFI_PCI_ATTRIBUTE_VGA_IO 0x0010 +#define EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO 0x0020 +#define EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO 0x0040 +#define EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080 +#define EFI_PCI_ATTRIBUTE_MEMORY_CACHED 0x0800 +#define EFI_PCI_ATTRIBUTE_MEMORY_DISABLE 0x1000 +#define EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000 + +#define EFI_PCI_ATTRIBUTE_VALID_FOR_ALLOCATE_BUFFER (EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED | EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE) + +#define EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER (~EFI_PCI_ATTRIBUTE_VALID_FOR_ALLOCATE_BUFFER) + +#define EFI_PCI_ADDRESS(bus, dev, func, reg) \ + ((UINT64) ((((UINTN) bus) << 24) + (((UINTN) dev) << 16) + (((UINTN) func) << 8) + ((UINTN) reg))) + +typedef struct { + UINT8 Register; + UINT8 Function; + UINT8 Device; + UINT8 Bus; + UINT32 ExtendedRegister; +} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS; + +/** + Reads from the I/O space of a PCI Root Bridge. Returns when either the polling exit criteria is + satisfied or after a defined duration. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Width Signifies the width of the memory or I/O operations. + @param Address The base address of the memory or I/O operations. + @param Mask Mask used for the polling criteria. + @param Value The comparison value used for the polling exit criteria. + @param Delay The number of 100 ns units to poll. + @param Result Pointer to the last value read from the memory location. + + @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria. + @retval EFI_TIMEOUT Delay expired before a match occurred. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Width Signifies the width of the memory operations. + @param Address The base address of the memory operations. + @param Count The number of memory operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +typedef struct { + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM Read; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM Write; +} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS; + +/** + Enables a PCI driver to copy one region of PCI root bridge memory space to another region of PCI + root bridge memory space. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance. + @param Width Signifies the width of the memory operations. + @param DestAddress The destination address of the memory operation. + @param SrcAddress The source address of the memory operation. + @param Count The number of memory operations to perform. + + @retval EFI_SUCCESS The data was copied from one memory region to another memory region. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_COPY_MEM)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 DestAddress, + IN UINT64 SrcAddress, + IN UINTN Count + ); + +/** + Provides the PCI controller-Cspecific addresses required to access system memory from a + DMA bus master. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Operation Indicates if the bus master is going to read or write to system memory. + @param HostAddress The system memory address to map to the PCI controller. + @param NumberOfBytes On input the number of bytes to map. On output the number of bytes + that were mapped. + @param DeviceAddress The resulting map address for the bus master PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_MAP)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +/** + Completes the Map() operation and releases any corresponding resources. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map(). + @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_UNMAP)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN VOID *Mapping + ); + +/** + Allocates pages that are suitable for an EfiPciOperationBusMasterCommonBuffer or + EfiPciOperationBusMasterCommonBuffer64 mapping. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Type This parameter is not used and must be ignored. + @param MemoryType The type of memory to allocate, EfiBootServicesData or + EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory address of the + allocated range. + @param Attributes The requested bit mask of attributes for the allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ALLOCATE_BUFFER)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN OUT VOID **HostAddress, + IN UINT64 Attributes + ); + +/** + Frees memory that was allocated with AllocateBuffer(). + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated range. + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages + was not allocated with AllocateBuffer(). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FREE_BUFFER)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINTN Pages, + IN VOID *HostAddress + ); + +/** + Flushes all PCI posted write transactions from a PCI host bridge to system memory. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + + @retval EFI_SUCCESS The PCI posted write transactions were flushed from the PCI host + bridge to system memory. + @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed from the PCI + host bridge due to a hardware error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FLUSH)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This + ); + +/** + Gets the attributes that a PCI root bridge supports setting with SetAttributes(), and the + attributes that a PCI root bridge is currently using. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Supports A pointer to the mask of attributes that this PCI root bridge supports + setting with SetAttributes(). + @param Attributes A pointer to the mask of attributes that this PCI root bridge is currently + using. + + @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI root + bridge supports is returned in Supports. If Attributes is + not NULL, then the attributes that the PCI root bridge is currently + using is returned in Attributes. + @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL. + + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GET_ATTRIBUTES)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT UINT64 *Supports, + OUT UINT64 *Attributes + ); + +/** + Sets attributes for a resource range on a PCI root bridge. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Attributes The mask of attributes to set. + @param ResourceBase A pointer to the base address of the resource range to be modified by the + attributes specified by Attributes. + @param ResourceLength A pointer to the length of the resource range to be modified by the + attributes specified by Attributes. + + @retval EFI_SUCCESS The set of attributes specified by Attributes for the resource + range specified by ResourceBase and ResourceLength + were set on the PCI root bridge, and the actual resource range is + returned in ResuourceBase and ResourceLength. + @retval EFI_UNSUPPORTED A bit is set in Attributes that is not supported by the PCI Root + Bridge. + @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the attributes on the + resource range specified by BaseAddress and Length. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_SET_ATTRIBUTES)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN OUT UINT64 *ResourceBase, + IN OUT UINT64 *ResourceLength + ); + +/** + Retrieves the current resource settings of this PCI root bridge in the form of a set of ACPI 2.0 + resource descriptors. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Resources A pointer to the ACPI 2.0 resource descriptors that describe the current + configuration of this PCI root bridge. + + @retval EFI_SUCCESS The current configuration of this PCI root bridge was returned in + Resources. + @retval EFI_UNSUPPORTED The current configuration of this PCI root bridge could not be + retrieved. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_CONFIGURATION)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT VOID **Resources + ); + +/** + @par Protocol Description: + Provides the basic Memory, I/O, PCI configuration, and DMA interfaces that are + used to abstract accesses to PCI controllers behind a PCI Root Bridge Controller. + + @param ParentHandle + The EFI_HANDLE of the PCI Host Bridge of which this PCI Root Bridge is a member. + + @param PollMem + Polls an address in memory mapped I/O space until an exit condition is met, + or a timeout occurs. + + @param PollIo + Polls an address in I/O space until an exit condition is met, or a timeout occurs. + + @param Mem.Read + Allows reads from memory mapped I/O space. + + @param Mem.Write + Allows writes to memory mapped I/O space. + + @param Io.Read + Allows reads from I/O space. + + @param Io.Write + Allows writes to I/O space. + + @param Pci.Read + Allows reads from PCI configuration space. + + @param Pci.Write + Allows writes to PCI configuration space. + + @param CopyMem + Allows one region of PCI root bridge memory space to be copied to another + region of PCI root bridge memory space. + + @param Map + Provides the PCI controller's specific addresses needed to access system memory for DMA. + + @param Unmap + Releases any resources allocated by Map(). + + @param AllocateBuffer + Allocates pages that are suitable for a common buffer mapping. + + @param FreeBuffer + Free pages that were allocated with AllocateBuffer(). + + @param Flush + Flushes all PCI posted write transactions to system memory. + + @param GetAttributes + Gets the attributes that a PCI root bridge supports setting with SetAttributes(), + and the attributes that a PCI root bridge is currently using. + + @param SetAttributes + Sets attributes for a resource range on a PCI root bridge. + + @param Configuration + Gets the current resource settings for this PCI root bridge. + + @param SegmentNumber + The segment number that this PCI root bridge resides. + +**/ +struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL { + EFI_HANDLE ParentHandle; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM PollMem; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM PollIo; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Mem; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Io; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Pci; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_COPY_MEM CopyMem; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_MAP Map; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_UNMAP Unmap; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FREE_BUFFER FreeBuffer; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FLUSH Flush; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GET_ATTRIBUTES GetAttributes; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_SET_ATTRIBUTES SetAttributes; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_CONFIGURATION Configuration; + UINT32 SegmentNumber; +}; + +extern EFI_GUID gEfiPciRootBridgeIoProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/SimpleNetwork.h b/gpxe/src/include/gpxe/efi/Protocol/SimpleNetwork.h new file mode 100644 index 00000000..ed8c8ce6 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/SimpleNetwork.h @@ -0,0 +1,645 @@ +/** @file + Simple Network protocol as defined in the UEFI 2.0 specification. + + Basic network device abstraction. + + Rx - Received + Tx - Transmit + MCast - MultiCast + ... + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __SIMPLE_NETWORK_H__ +#define __SIMPLE_NETWORK_H__ + +#define EFI_SIMPLE_NETWORK_PROTOCOL_GUID \ + { \ + 0xA19832B9, 0xAC25, 0x11D3, {0x9A, 0x2D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } \ + } + +typedef struct _EFI_SIMPLE_NETWORK_PROTOCOL EFI_SIMPLE_NETWORK_PROTOCOL; + + +/// +/// Protocol defined in EFI1.1. +/// +typedef EFI_SIMPLE_NETWORK_PROTOCOL EFI_SIMPLE_NETWORK; + +/// +/// Simple Network Protocol data structures +/// +typedef struct { + /// + /// Total number of frames received. Includes frames with errors and + /// dropped frames. + /// + UINT64 RxTotalFrames; + + /// + /// Number of valid frames received and copied into receive buffers. + /// + UINT64 RxGoodFrames; + + /// + /// Number of frames below the minimum length for the media. + /// This would be <64 for ethernet. + /// + UINT64 RxUndersizeFrames; + + /// + /// Number of frames longer than the maxminum length for the + /// media. This would be >1500 for ethernet. + /// + UINT64 RxOversizeFrames; + + /// + /// Valid frames that were dropped because receive buffers were full. + /// + UINT64 RxDroppedFrames; + + /// + /// Number of valid unicast frames received and not dropped. + /// + UINT64 RxUnicastFrames; + + /// + /// Number of valid broadcast frames received and not dropped. + /// + UINT64 RxBroadcastFrames; + + /// + /// Number of valid mutlicast frames received and not dropped. + /// + UINT64 RxMulticastFrames; + + /// + /// Number of frames w/ CRC or alignment errors. + /// + UINT64 RxCrcErrorFrames; + + /// + /// Total number of bytes received. Includes frames with errors + /// and dropped frames. + // + UINT64 RxTotalBytes; + + /// + /// Transmit statistics. + /// + UINT64 TxTotalFrames; + UINT64 TxGoodFrames; + UINT64 TxUndersizeFrames; + UINT64 TxOversizeFrames; + UINT64 TxDroppedFrames; + UINT64 TxUnicastFrames; + UINT64 TxBroadcastFrames; + UINT64 TxMulticastFrames; + UINT64 TxCrcErrorFrames; + UINT64 TxTotalBytes; + + /// + /// Number of collisions detection on this subnet. + /// + UINT64 Collisions; + + /// + /// Number of frames destined for unsupported protocol. + /// + UINT64 UnsupportedProtocol; + +} EFI_NETWORK_STATISTICS; + +typedef enum { + EfiSimpleNetworkStopped, + EfiSimpleNetworkStarted, + EfiSimpleNetworkInitialized, + EfiSimpleNetworkMaxState +} EFI_SIMPLE_NETWORK_STATE; + +#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST 0x01 +#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST 0x02 +#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST 0x04 +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS 0x08 +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10 + +#define EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT 0x01 +#define EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT 0x02 +#define EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT 0x04 +#define EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT 0x08 + +#define MAX_MCAST_FILTER_CNT 16 +typedef struct { + UINT32 State; + UINT32 HwAddressSize; + UINT32 MediaHeaderSize; + UINT32 MaxPacketSize; + UINT32 NvRamSize; + UINT32 NvRamAccessSize; + UINT32 ReceiveFilterMask; + UINT32 ReceiveFilterSetting; + UINT32 MaxMCastFilterCount; + UINT32 MCastFilterCount; + EFI_MAC_ADDRESS MCastFilter[MAX_MCAST_FILTER_CNT]; + EFI_MAC_ADDRESS CurrentAddress; + EFI_MAC_ADDRESS BroadcastAddress; + EFI_MAC_ADDRESS PermanentAddress; + UINT8 IfType; + BOOLEAN MacAddressChangeable; + BOOLEAN MultipleTxSupported; + BOOLEAN MediaPresentSupported; + BOOLEAN MediaPresent; +} EFI_SIMPLE_NETWORK_MODE; + +// +// Protocol Member Functions +// +/** + Changes the state of a network interface from "stopped" to "started". + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The network interface was started. + @retval EFI_ALREADY_STARTED The network interface is already in the started state. + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_START)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This + ); + +/** + Changes the state of a network interface from "started" to "stopped". + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The network interface was stopped. + @retval EFI_ALREADY_STARTED The network interface is already in the stopped state. + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_STOP)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This + ); + +/** + Resets a network adapter and allocates the transmit and receive buffers + required by the network interface; optionally, also requests allocation + of additional transmit and receive buffers. + + @param This Protocol instance pointer. + @param ExtraRxBufferSize The size, in bytes, of the extra receive buffer space + that the driver should allocate for the network interface. + Some network interfaces will not be able to use the extra + buffer, and the caller will not know if it is actually + being used. + @param ExtraTxBufferSize The size, in bytes, of the extra transmit buffer space + that the driver should allocate for the network interface. + Some network interfaces will not be able to use the extra + buffer, and the caller will not know if it is actually + being used. + + @retval EFI_SUCCESS The network interface was initialized. + @retval EFI_NOT_STARTED The network interface has not been started + @retval EFI_OUT_OF_RESOURCES There was not enough memory for the transmit and + receive buffers. . + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_INITIALIZE)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN UINTN ExtraRxBufferSize OPTIONAL, + IN UINTN ExtraTxBufferSize OPTIONAL + ); + +/** + Resets a network adapter and re-initializes it with the parameters that were + provided in the previous call to Initialize(). + + @param This Protocol instance pointer. + @param ExtendedVerification Indicates that the driver may perform a more + exhaustive verification operation of the device + during reset. + + @retval EFI_SUCCESS The network interface was reset. + @retval EFI_NOT_STARTED The network interface has not been started + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_RESET)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +/** + Resets a network adapter and leaves it in a state that is safe for + another driver to initialize. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The network interface was shutdown. + @retval EFI_NOT_STARTED The network interface has not been started + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_SHUTDOWN)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This + ); + +/** + Manages the multicast receive filters of a network interface. + + @param This Protocol instance pointer. + @param Enable A bit mask of receive filters to enable on the network interface. + @param Disable A bit mask of receive filters to disable on the network interface. + @param ResetMCastFilter Set to TRUE to reset the contents of the multicast receive + filters on the network interface to their default values. + @param McastFilterCnt Number of multicast HW MAC addresses in the new + MCastFilter list. This value must be less than or equal to + the MCastFilterCnt field of EFI_SIMPLE_NETWORK_MODE. This + field is optional if ResetMCastFilter is TRUE. + @param MCastFilter A pointer to a list of new multicast receive filter HW MAC + addresses. This list will replace any existing multicast + HW MAC address list. This field is optional if + ResetMCastFilter is TRUE. + + @retval EFI_SUCCESS The multicast receive filter list was updated. + @retval EFI_NOT_STARTED The network interface has not been started + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_RECEIVE_FILTERS)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN UINT32 Enable, + IN UINT32 Disable, + IN BOOLEAN ResetMCastFilter, + IN UINTN MCastFilterCnt OPTIONAL, + IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL + ); + +/** + Modifies or resets the current station address, if supported. + + @param This Protocol instance pointer. + @param Reset Flag used to reset the station address to the network interfaces + permanent address. + @param New New station address to be used for the network interface. + + @retval EFI_SUCCESS The network interfaces station address was updated. + @retval EFI_NOT_STARTED The network interface has not been started + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_STATION_ADDRESS)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN Reset, + IN EFI_MAC_ADDRESS *New OPTIONAL + ); + +/** + Resets or collects the statistics on a network interface. + + @param This Protocol instance pointer. + @param Reset Set to TRUE to reset the statistics for the network interface. + @param StatisticsSize On input the size, in bytes, of StatisticsTable. On + output the size, in bytes, of the resulting table of + statistics. + @param StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that + contains the statistics. + + @retval EFI_SUCCESS The statistics were collected from the network interface. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The current buffer + size needed to hold the statistics is returned in + StatisticsSize. + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_STATISTICS)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN Reset, + IN OUT UINTN *StatisticsSize OPTIONAL, + OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL + ); + +/** + Converts a multicast IP address to a multicast HW MAC address. + + @param This Protocol instance pointer. + @param IPv6 Set to TRUE if the multicast IP address is IPv6 [RFC 2460]. Set + to FALSE if the multicast IP address is IPv4 [RFC 791]. + @param IP The multicast IP address that is to be converted to a multicast + HW MAC address. + @param MAC The multicast HW MAC address that is to be generated from IP. + + @retval EFI_SUCCESS The multicast IP address was mapped to the multicast + HW MAC address. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The current buffer + size needed to hold the statistics is returned in + StatisticsSize. + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN IPv6, + IN EFI_IP_ADDRESS *IP, + OUT EFI_MAC_ADDRESS *MAC + ); + +/** + Performs read and write operations on the NVRAM device attached to a + network interface. + + @param This Protocol instance pointer. + @param ReadWrite TRUE for read operations, FALSE for write operations. + @param Offset Byte offset in the NVRAM device at which to start the read or + write operation. This must be a multiple of NvRamAccessSize and + less than NvRamSize. + @param BufferSize The number of bytes to read or write from the NVRAM device. + This must also be a multiple of NvramAccessSize. + @param Buffer A pointer to the data buffer. + + @retval EFI_SUCCESS The NVRAM access was performed. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_NVDATA)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN ReadWrite, + IN UINTN Offset, + IN UINTN BufferSize, + IN OUT VOID *Buffer + ); + +/** + Reads the current interrupt status and recycled transmit buffer status from + a network interface. + + @param This Protocol instance pointer. + @param InterruptStatus A pointer to the bit mask of the currently active interrupts + If this is NULL, the interrupt status will not be read from + the device. If this is not NULL, the interrupt status will + be read from the device. When the interrupt status is read, + it will also be cleared. Clearing the transmit interrupt + does not empty the recycled transmit buffer array. + @param TxBuf Recycled transmit buffer address. The network interface will + not transmit if its internal recycled transmit buffer array + is full. Reading the transmit buffer does not clear the + transmit interrupt. If this is NULL, then the transmit buffer + status will not be read. If there are no transmit buffers to + recycle and TxBuf is not NULL, * TxBuf will be set to NULL. + + @retval EFI_SUCCESS The status of the network interface was retrieved. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_GET_STATUS)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + OUT UINT32 *InterruptStatus OPTIONAL, + OUT VOID **TxBuf OPTIONAL + ); + +/** + Places a packet in the transmit queue of a network interface. + + @param This Protocol instance pointer. + @param HeaderSize The size, in bytes, of the media header to be filled in by + the Transmit() function. If HeaderSize is non-zero, then it + must be equal to This->Mode->MediaHeaderSize and the DestAddr + and Protocol parameters must not be NULL. + @param BufferSize The size, in bytes, of the entire packet (media header and + data) to be transmitted through the network interface. + @param Buffer A pointer to the packet (media header followed by data) to be + transmitted. This parameter cannot be NULL. If HeaderSize is zero, + then the media header in Buffer must already be filled in by the + caller. If HeaderSize is non-zero, then the media header will be + filled in by the Transmit() function. + @param SrcAddr The source HW MAC address. If HeaderSize is zero, then this parameter + is ignored. If HeaderSize is non-zero and SrcAddr is NULL, then + This->Mode->CurrentAddress is used for the source HW MAC address. + @param DsetAddr The destination HW MAC address. If HeaderSize is zero, then this + parameter is ignored. + @param Protocol The type of header to build. If HeaderSize is zero, then this + parameter is ignored. See RFC 1700, section "Ether Types", for + examples. + + @retval EFI_SUCCESS The packet was placed on the transmit queue. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_NOT_READY The network interface is too busy to accept this transmit request. + @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small. + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_TRANSMIT)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN UINTN HeaderSize, + IN UINTN BufferSize, + IN VOID *Buffer, + IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + IN EFI_MAC_ADDRESS *DestAddr OPTIONAL, + IN UINT16 *Protocol OPTIONAL + ); + +/** + Receives a packet from a network interface. + + @param This Protocol instance pointer. + @param HeaderSize The size, in bytes, of the media header received on the network + interface. If this parameter is NULL, then the media header size + will not be returned. + @param BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in + bytes, of the packet that was received on the network interface. + @param Buffer A pointer to the data buffer to receive both the media header and + the data. + @param SrcAddr The source HW MAC address. If this parameter is NULL, the + HW MAC source address will not be extracted from the media + header. + @param DsetAddr The destination HW MAC address. If this parameter is NULL, + the HW MAC destination address will not be extracted from the + media header. + @param Protocol The media header type. If this parameter is NULL, then the + protocol will not be extracted from the media header. See + RFC 1700 section "Ether Types" for examples. + + @retval EFI_SUCCESS The received data was stored in Buffer, and BufferSize has + been updated to the number of bytes received. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_NOT_READY The network interface is too busy to accept this transmit + request. + @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small. + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_RECEIVE)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + OUT UINTN *HeaderSize OPTIONAL, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer, + OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL, + OUT UINT16 *Protocol OPTIONAL + ); + +#define EFI_SIMPLE_NETWORK_PROTOCOL_REVISION 0x00010000 + +// +// Revision defined in EFI1.1 +// +#define EFI_SIMPLE_NETWORK_INTERFACE_REVISION EFI_SIMPLE_NETWORK_PROTOCOL_REVISION + +/** + @par Protocol Description: + The EFI_SIMPLE_NETWORK_PROTOCOL protocol is used to initialize access + to a network adapter. Once the network adapter initializes, + the EFI_SIMPLE_NETWORK_PROTOCOL protocol provides services that + allow packets to be transmitted and received. + + @param Revision + Revision of the EFI_SIMPLE_NETWORK_PROTOCOL. All future revisions must + be backwards compatible. If a future version is not backwards compatible + it is not the same GUID. + + @param Start + Prepares the network interface for further command operations. + No other EFI_SIMPLE_NETWORK_PROTOCOL interface functions will operate + until this call is made. + + @param Stop + Stops further network interface command processing. + No other EFI_SIMPLE_NETWORK_PROTOCOL interface functions will operate + after this call is made until another Start() call is made. + + @param Initialize + Resets the network adapter and allocates the transmit and receive buffers. + + @param Reset + Resets the network adapter and reinitializes it with the parameters + provided in the previous call to Initialize(). + + @param Shutdown + Resets the network adapter and leaves it in a state safe for another driver + to initialize. The memory buffers assigned in the Initialize() call are released. + After this call, only the Initialize() or Stop() calls may be used. + + @param ReceiveFilters + Enables and disables the receive filters for the network interface and, + if supported, manages the filtered multicast + HW MAC (Hardware Media Access Control) address list. + + @param StationAddress + Modifies or resets the current station address, if supported. + + @param Statistics + Collects statistics from the network interface and allows the statistics to be reset. + + @param MCastIpToMac + Maps a multicast IP address to a multicast HW MAC address. + + @param NvData + Reads and writes the contents of the NVRAM devices attached to the network interface. + + @param GetStatus + Reads the current interrupt status and the list of recycled transmit + buffers from the network interface. + + @param Transmit + Places a packet in the transmit queue. + + @param Receive + Retrieves a packet from the receive queue, along with the status + flags that describe the packet type. + + @param WaitForPacket + Event used with WaitForEvent() to wait for a packet to be received. + + @param Mode + Pointer to the EFI_SIMPLE_NETWORK_MODE data for the device. + +**/ +struct _EFI_SIMPLE_NETWORK_PROTOCOL { + UINT64 Revision; + EFI_SIMPLE_NETWORK_START Start; + EFI_SIMPLE_NETWORK_STOP Stop; + EFI_SIMPLE_NETWORK_INITIALIZE Initialize; + EFI_SIMPLE_NETWORK_RESET Reset; + EFI_SIMPLE_NETWORK_SHUTDOWN Shutdown; + EFI_SIMPLE_NETWORK_RECEIVE_FILTERS ReceiveFilters; + EFI_SIMPLE_NETWORK_STATION_ADDRESS StationAddress; + EFI_SIMPLE_NETWORK_STATISTICS Statistics; + EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC MCastIpToMac; + EFI_SIMPLE_NETWORK_NVDATA NvData; + EFI_SIMPLE_NETWORK_GET_STATUS GetStatus; + EFI_SIMPLE_NETWORK_TRANSMIT Transmit; + EFI_SIMPLE_NETWORK_RECEIVE Receive; + EFI_EVENT WaitForPacket; + EFI_SIMPLE_NETWORK_MODE *Mode; +}; + +extern EFI_GUID gEfiSimpleNetworkProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/SimpleTextIn.h b/gpxe/src/include/gpxe/efi/Protocol/SimpleTextIn.h new file mode 100644 index 00000000..ca747dde --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/SimpleTextIn.h @@ -0,0 +1,145 @@ +/** @file + Simple Text In protocol from the UEFI 2.0 specification. + + Abstraction of a very simple input device like a keyboard or serial + terminal. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __SIMPLE_TEXT_IN_PROTOCOL_H__ +#define __SIMPLE_TEXT_IN_PROTOCOL_H__ + +#include + +#define EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID \ + { \ + 0x387477c1, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +/// +/// Protocol GUID defined in EFI1.1. +/// +#define SIMPLE_INPUT_PROTOCOL EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID + +typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL EFI_SIMPLE_TEXT_INPUT_PROTOCOL; + +/// +/// Backward-compatible with EFI1.1. +/// +typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL SIMPLE_INPUT_INTERFACE; +// +// Data structures +// +typedef struct { + UINT16 ScanCode; + CHAR16 UnicodeChar; +} EFI_INPUT_KEY; + +// +// Required unicode control chars +// +#define CHAR_NULL 0x0000 +#define CHAR_BACKSPACE 0x0008 +#define CHAR_TAB 0x0009 +#define CHAR_LINEFEED 0x000A +#define CHAR_CARRIAGE_RETURN 0x000D + +// +// EFI Scan codes +// +#define SCAN_NULL 0x0000 +#define SCAN_UP 0x0001 +#define SCAN_DOWN 0x0002 +#define SCAN_RIGHT 0x0003 +#define SCAN_LEFT 0x0004 +#define SCAN_HOME 0x0005 +#define SCAN_END 0x0006 +#define SCAN_INSERT 0x0007 +#define SCAN_DELETE 0x0008 +#define SCAN_PAGE_UP 0x0009 +#define SCAN_PAGE_DOWN 0x000A +#define SCAN_F1 0x000B +#define SCAN_F2 0x000C +#define SCAN_F3 0x000D +#define SCAN_F4 0x000E +#define SCAN_F5 0x000F +#define SCAN_F6 0x0010 +#define SCAN_F7 0x0011 +#define SCAN_F8 0x0012 +#define SCAN_F9 0x0013 +#define SCAN_F10 0x0014 +#define SCAN_F11 0x0015 +#define SCAN_F12 0x0016 +#define SCAN_ESC 0x0017 + +/** + Reset the input device and optionaly run diagnostics + + @param This Protocol instance pointer. + @param ExtendedVerification Driver may perform diagnostics on reset. + + @retval EFI_SUCCESS The device was reset. + @retval EFI_DEVICE_ERROR The device is not functioning properly and could not be reset. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_INPUT_RESET)( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +/** + Reads the next keystroke from the input device. The WaitForKey Event can + be used to test for existance of a keystroke via WaitForEvent () call. + + @param This Protocol instance pointer. + @param Key Driver may perform diagnostics on reset. + + @retval EFI_SUCCESS The keystroke information was returned. + @retval EFI_NOT_READY There was no keystroke data availiable. + @retval EFI_DEVICE_ERROR The keydtroke information was not returned due to + hardware errors. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_INPUT_READ_KEY)( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ); + +/** + @par Protocol Description: + The EFI_SIMPLE_TEXT_INPUT_PROTOCOL is used on the ConsoleIn device. + It is the minimum required protocol for ConsoleIn. + + @param Reset + Reset the ConsoleIn device. + + @param ReadKeyStroke + Returns the next input character. + + @param WaitForKey + Event to use with WaitForEvent() to wait for a key to be available. + +**/ + +struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL { + EFI_INPUT_RESET Reset; + EFI_INPUT_READ_KEY ReadKeyStroke; + EFI_EVENT WaitForKey; +}; + +extern EFI_GUID gEfiSimpleTextInProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/SimpleTextOut.h b/gpxe/src/include/gpxe/efi/Protocol/SimpleTextOut.h new file mode 100644 index 00000000..cc772743 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/SimpleTextOut.h @@ -0,0 +1,437 @@ +/** @file + Simple Text Out protocol from the UEFI 2.0 specification. + + Abstraction of a very simple text based output device like VGA text mode or + a serial terminal. The Simple Text Out protocol instance can represent + a single hardware device or a virtual device that is an agregation + of multiple physical devices. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __SIMPLE_TEXT_OUT_H__ +#define __SIMPLE_TEXT_OUT_H__ + +#include + +#define EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID \ + { \ + 0x387477c2, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +/// +/// Protocol GUID defined in EFI1.1. +/// +#define SIMPLE_TEXT_OUTPUT_PROTOCOL EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID + +typedef struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL; + +/// +/// Backward-compatible with EFI1.1. +/// +typedef EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL SIMPLE_TEXT_OUTPUT_INTERFACE; + +// +// Define's for required EFI Unicode Box Draw characters +// +#define BOXDRAW_HORIZONTAL 0x2500 +#define BOXDRAW_VERTICAL 0x2502 +#define BOXDRAW_DOWN_RIGHT 0x250c +#define BOXDRAW_DOWN_LEFT 0x2510 +#define BOXDRAW_UP_RIGHT 0x2514 +#define BOXDRAW_UP_LEFT 0x2518 +#define BOXDRAW_VERTICAL_RIGHT 0x251c +#define BOXDRAW_VERTICAL_LEFT 0x2524 +#define BOXDRAW_DOWN_HORIZONTAL 0x252c +#define BOXDRAW_UP_HORIZONTAL 0x2534 +#define BOXDRAW_VERTICAL_HORIZONTAL 0x253c +#define BOXDRAW_DOUBLE_HORIZONTAL 0x2550 +#define BOXDRAW_DOUBLE_VERTICAL 0x2551 +#define BOXDRAW_DOWN_RIGHT_DOUBLE 0x2552 +#define BOXDRAW_DOWN_DOUBLE_RIGHT 0x2553 +#define BOXDRAW_DOUBLE_DOWN_RIGHT 0x2554 +#define BOXDRAW_DOWN_LEFT_DOUBLE 0x2555 +#define BOXDRAW_DOWN_DOUBLE_LEFT 0x2556 +#define BOXDRAW_DOUBLE_DOWN_LEFT 0x2557 +#define BOXDRAW_UP_RIGHT_DOUBLE 0x2558 +#define BOXDRAW_UP_DOUBLE_RIGHT 0x2559 +#define BOXDRAW_DOUBLE_UP_RIGHT 0x255a +#define BOXDRAW_UP_LEFT_DOUBLE 0x255b +#define BOXDRAW_UP_DOUBLE_LEFT 0x255c +#define BOXDRAW_DOUBLE_UP_LEFT 0x255d +#define BOXDRAW_VERTICAL_RIGHT_DOUBLE 0x255e +#define BOXDRAW_VERTICAL_DOUBLE_RIGHT 0x255f +#define BOXDRAW_DOUBLE_VERTICAL_RIGHT 0x2560 +#define BOXDRAW_VERTICAL_LEFT_DOUBLE 0x2561 +#define BOXDRAW_VERTICAL_DOUBLE_LEFT 0x2562 +#define BOXDRAW_DOUBLE_VERTICAL_LEFT 0x2563 +#define BOXDRAW_DOWN_HORIZONTAL_DOUBLE 0x2564 +#define BOXDRAW_DOWN_DOUBLE_HORIZONTAL 0x2565 +#define BOXDRAW_DOUBLE_DOWN_HORIZONTAL 0x2566 +#define BOXDRAW_UP_HORIZONTAL_DOUBLE 0x2567 +#define BOXDRAW_UP_DOUBLE_HORIZONTAL 0x2568 +#define BOXDRAW_DOUBLE_UP_HORIZONTAL 0x2569 +#define BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE 0x256a +#define BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL 0x256b +#define BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL 0x256c + +// +// EFI Required Block Elements Code Chart +// +#define BLOCKELEMENT_FULL_BLOCK 0x2588 +#define BLOCKELEMENT_LIGHT_SHADE 0x2591 + +// +// EFI Required Geometric Shapes Code Chart +// +#define GEOMETRICSHAPE_UP_TRIANGLE 0x25b2 +#define GEOMETRICSHAPE_RIGHT_TRIANGLE 0x25ba +#define GEOMETRICSHAPE_DOWN_TRIANGLE 0x25bc +#define GEOMETRICSHAPE_LEFT_TRIANGLE 0x25c4 + +// +// EFI Required Arrow shapes +// +#define ARROW_LEFT 0x2190 +#define ARROW_UP 0x2191 +#define ARROW_RIGHT 0x2192 +#define ARROW_DOWN 0x2193 + +// +// EFI Console Colours +// +#define EFI_BLACK 0x00 +#define EFI_BLUE 0x01 +#define EFI_GREEN 0x02 +#define EFI_CYAN (EFI_BLUE | EFI_GREEN) +#define EFI_RED 0x04 +#define EFI_MAGENTA (EFI_BLUE | EFI_RED) +#define EFI_BROWN (EFI_GREEN | EFI_RED) +#define EFI_LIGHTGRAY (EFI_BLUE | EFI_GREEN | EFI_RED) +#define EFI_BRIGHT 0x08 +#define EFI_DARKGRAY (EFI_BRIGHT) +#define EFI_LIGHTBLUE (EFI_BLUE | EFI_BRIGHT) +#define EFI_LIGHTGREEN (EFI_GREEN | EFI_BRIGHT) +#define EFI_LIGHTCYAN (EFI_CYAN | EFI_BRIGHT) +#define EFI_LIGHTRED (EFI_RED | EFI_BRIGHT) +#define EFI_LIGHTMAGENTA (EFI_MAGENTA | EFI_BRIGHT) +#define EFI_YELLOW (EFI_BROWN | EFI_BRIGHT) +#define EFI_WHITE (EFI_BLUE | EFI_GREEN | EFI_RED | EFI_BRIGHT) + +#define EFI_TEXT_ATTR(f, b) ((f) | ((b) << 4)) + +#define EFI_BACKGROUND_BLACK 0x00 +#define EFI_BACKGROUND_BLUE 0x10 +#define EFI_BACKGROUND_GREEN 0x20 +#define EFI_BACKGROUND_CYAN (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN) +#define EFI_BACKGROUND_RED 0x40 +#define EFI_BACKGROUND_MAGENTA (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_RED) +#define EFI_BACKGROUND_BROWN (EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED) +#define EFI_BACKGROUND_LIGHTGRAY (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED) + +// +// We currently define attributes from 0 - 7F for color manipulations +// To internally handle the local display characteristics for a particular character, we are defining +// Bit 7 to signify the local glyph representation for a character. If turned on, glyphs will be +// pulled from the wide glyph database and will display locally as a wide character (16 X 19 versus 8 X 19) +// If bit 7 is off, the narrow glyph database will be used. This does NOT affect information that is sent to +// non-local displays (e.g. serial or LAN consoles). +// +#define EFI_WIDE_ATTRIBUTE 0x80 + +/** + Reset the text output device hardware and optionaly run diagnostics + + @param This Protocol instance pointer. + @param ExtendedVerification Driver may perform more exhaustive verfication + operation of the device during reset. + + @retval EFI_SUCCESS The text output device was reset. + @retval EFI_DEVICE_ERROR The text output device is not functioning correctly and + could not be reset. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_RESET)( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +/** + Write a Unicode string to the output device. + + @param This Protocol instance pointer. + @param String The NULL-terminated Unicode string to be displayed on the output + device(s). All output devices must also support the Unicode + drawing defined in this file. + + @retval EFI_SUCCESS The string was output to the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to output + the text. + @retval EFI_UNSUPPORTED The output device's mode is not currently in a + defined text mode. + @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the + characters in the Unicode string could not be + rendered and were skipped. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_STRING)( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *String + ); + +/** + Verifies that all characters in a Unicode string can be output to the + target device. + + @param This Protocol instance pointer. + @param String The NULL-terminated Unicode string to be examined for the output + device(s). + + @retval EFI_SUCCESS The device(s) are capable of rendering the output string. + @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be + rendered by one or more of the output devices mapped + by the EFI handle. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_TEST_STRING)( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *String + ); + +/** + Returns information for an available text mode that the output device(s) + supports. + + @param This Protocol instance pointer. + @param ModeNumber The mode number to return information on. + @param Columns Returns the geometry of the text output device for the + requested ModeNumber. + @param Rows Returns the geometry of the text output device for the + requested ModeNumber. + + @retval EFI_SUCCESS The requested mode information was returned. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the request. + @retval EFI_UNSUPPORTED The mode number was not valid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_QUERY_MODE)( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ); + +/** + Sets the output device(s) to a specified mode. + + @param This Protocol instance pointer. + @param ModeNumber The mode number to set. + + @retval EFI_SUCCESS The requested text mode was set. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the request. + @retval EFI_UNSUPPORTED The mode number was not valid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_SET_MODE)( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber + ); + +/** + Sets the background and foreground colors for the OutputString () and + ClearScreen () functions. + + @param This Protocol instance pointer. + @param Attribute The attribute to set. Bits 0..3 are the foreground color, and + bits 4..6 are the background color. All other bits are undefined + and must be zero. The valid Attributes are defined in this file. + + @retval EFI_SUCCESS The attribute was set. + @retval EFI_DEVICE_ ERROR The device had an error and could not complete the request. + @retval EFI_UNSUPPORTED The attribute requested is not defined. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_SET_ATTRIBUTE)( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Attribute + ); + +/** + Clears the output device(s) display to the currently selected background + color. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the request. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_CLEAR_SCREEN)( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This + ); + +/** + Sets the current coordinates of the cursor position + + @param This Protocol instance pointer. + @param Column The position to set the cursor to. Must be greater than or + equal to zero and less than the number of columns and rows + by QueryMode (). + @param Row The position to set the cursor to. Must be greater than or + equal to zero and less than the number of columns and rows + by QueryMode (). + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the request. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode, or the + cursor position is invalid for the current mode. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_SET_CURSOR_POSITION)( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ); + +/** + Makes the cursor visible or invisible + + @param This Protocol instance pointer. + @param Visible If TRUE, the cursor is set to be visible. If FALSE, the cursor is + set to be invisible. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the + request, or the device does not support changing + the cursor mode. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_ENABLE_CURSOR)( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN Visible + ); + +/** + @par Data Structure Description: + Mode Structure pointed to by Simple Text Out protocol. + + @param MaxMode + The number of modes supported by QueryMode () and SetMode (). + + @param Mode + The text mode of the output device(s). + + @param Attribute + The current character output attribute + + @param CursorColumn + The cursor's column. + + @param CursorRow + The cursor's row. + + @param CursorVisible + The cursor is currently visbile or not. + +**/ +typedef struct { + INT32 MaxMode; + + // + // current settings + // + INT32 Mode; + INT32 Attribute; + INT32 CursorColumn; + INT32 CursorRow; + BOOLEAN CursorVisible; +} EFI_SIMPLE_TEXT_OUTPUT_MODE; + +/** + @par Protocol Description: + The SIMPLE_TEXT_OUTPUT protocol is used to control text-based output devices. + It is the minimum required protocol for any handle supplied as the ConsoleOut + or StandardError device. In addition, the minimum supported text mode of such + devices is at least 80 x 25 characters. + + @param Reset + Reset the ConsoleOut device. + + @param OutputString + Displays the Unicode string on the device at the current cursor location. + + @param TestString + Tests to see if the ConsoleOut device supports this Unicode string. + + @param QueryMode + Queries information concerning the output device's supported text mode. + + @param SetMode + Sets the current mode of the output device. + + @param SetAttribute + Sets the foreground and background color of the text that is output. + + @param ClearScreen + Clears the screen with the currently set background color. + + @param SetCursorPosition + Sets the current cursor position. + + @param EnableCursor + Turns the visibility of the cursor on/off. + + @param Mode + Pointer to SIMPLE_TEXT_OUTPUT_MODE data. +**/ +struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL { + EFI_TEXT_RESET Reset; + + EFI_TEXT_STRING OutputString; + EFI_TEXT_TEST_STRING TestString; + + EFI_TEXT_QUERY_MODE QueryMode; + EFI_TEXT_SET_MODE SetMode; + EFI_TEXT_SET_ATTRIBUTE SetAttribute; + + EFI_TEXT_CLEAR_SCREEN ClearScreen; + EFI_TEXT_SET_CURSOR_POSITION SetCursorPosition; + EFI_TEXT_ENABLE_CURSOR EnableCursor; + + // + // Current mode + // + EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode; +}; + +extern EFI_GUID gEfiSimpleTextOutProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Uefi.h b/gpxe/src/include/gpxe/efi/Uefi.h new file mode 100644 index 00000000..58ddb11f --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Uefi.h @@ -0,0 +1,27 @@ +/** @file + + Root include file for Mde Package UEFI, UEFI_APPLICATION type modules. + + This is the include file for any module of type UEFI and UEFI_APPLICATION. Uefi modules only use + types defined via this include file and can be ported easily to any + environment. + +Copyright (c) 2006 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __PI_UEFI_H__ +#define __PI_UEFI_H__ + +#include +#include + +#endif + diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiBaseType.h b/gpxe/src/include/gpxe/efi/Uefi/UefiBaseType.h new file mode 100644 index 00000000..1bda8982 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Uefi/UefiBaseType.h @@ -0,0 +1,174 @@ +/** @file + + Defines data types and constants introduced in UEFI. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __UEFI_BASETYPE_H__ +#define __UEFI_BASETYPE_H__ + +#include + +/// +/// Basical data type definitions introduced in UEFI. +/// +typedef GUID EFI_GUID; + +/// +/// Function return status for EFI API +/// +typedef RETURN_STATUS EFI_STATUS; +typedef VOID *EFI_HANDLE; + +typedef VOID *EFI_EVENT; + +typedef UINTN EFI_TPL; + + +typedef UINT64 EFI_LBA; + + +typedef UINT16 STRING_REF; + +typedef UINT64 EFI_PHYSICAL_ADDRESS; +typedef UINT64 EFI_VIRTUAL_ADDRESS; + +/// +/// EFI Time Abstraction: +/// Year: 2000 - 20XX +/// Month: 1 - 12 +/// Day: 1 - 31 +/// Hour: 0 - 23 +/// Minute: 0 - 59 +/// Second: 0 - 59 +/// Nanosecond: 0 - 999,999,999 +/// TimeZone: -1440 to 1440 or 2047 +/// +typedef struct { + UINT16 Year; + UINT8 Month; + UINT8 Day; + UINT8 Hour; + UINT8 Minute; + UINT8 Second; + UINT8 Pad1; + UINT32 Nanosecond; + INT16 TimeZone; + UINT8 Daylight; + UINT8 Pad2; +} EFI_TIME; + + +// +// Networking Definitions +// +typedef struct { + UINT8 Addr[4]; +} EFI_IPv4_ADDRESS; + +typedef struct { + UINT8 Addr[16]; +} EFI_IPv6_ADDRESS; + +typedef struct { + UINT8 Addr[32]; +} EFI_MAC_ADDRESS; + +typedef union { + UINT32 Addr[4]; + EFI_IPv4_ADDRESS v4; + EFI_IPv6_ADDRESS v6; +} EFI_IP_ADDRESS; + + +// +// Enumeration of EFI_STATUS. +// +#define EFI_SUCCESS RETURN_SUCCESS +#define EFI_LOAD_ERROR RETURN_LOAD_ERROR +#define EFI_INVALID_PARAMETER RETURN_INVALID_PARAMETER +#define EFI_UNSUPPORTED RETURN_UNSUPPORTED +#define EFI_BAD_BUFFER_SIZE RETURN_BAD_BUFFER_SIZE +#define EFI_BUFFER_TOO_SMALL RETURN_BUFFER_TOO_SMALL +#define EFI_NOT_READY RETURN_NOT_READY +#define EFI_DEVICE_ERROR RETURN_DEVICE_ERROR +#define EFI_WRITE_PROTECTED RETURN_WRITE_PROTECTED +#define EFI_OUT_OF_RESOURCES RETURN_OUT_OF_RESOURCES +#define EFI_VOLUME_CORRUPTED RETURN_VOLUME_CORRUPTED +#define EFI_VOLUME_FULL RETURN_VOLUME_FULL +#define EFI_NO_MEDIA RETURN_NO_MEDIA +#define EFI_MEDIA_CHANGED RETURN_MEDIA_CHANGED +#define EFI_NOT_FOUND RETURN_NOT_FOUND +#define EFI_ACCESS_DENIED RETURN_ACCESS_DENIED +#define EFI_NO_RESPONSE RETURN_NO_RESPONSE +#define EFI_NO_MAPPING RETURN_NO_MAPPING +#define EFI_TIMEOUT RETURN_TIMEOUT +#define EFI_NOT_STARTED RETURN_NOT_STARTED +#define EFI_ALREADY_STARTED RETURN_ALREADY_STARTED +#define EFI_ABORTED RETURN_ABORTED +#define EFI_ICMP_ERROR RETURN_ICMP_ERROR +#define EFI_TFTP_ERROR RETURN_TFTP_ERROR +#define EFI_PROTOCOL_ERROR RETURN_PROTOCOL_ERROR +#define EFI_INCOMPATIBLE_VERSION RETURN_INCOMPATIBLE_VERSION +#define EFI_SECURITY_VIOLATION RETURN_SECURITY_VIOLATION +#define EFI_CRC_ERROR RETURN_CRC_ERROR +#define EFI_END_OF_MEDIA RETURN_END_OF_MEDIA +#define EFI_END_OF_FILE RETURN_END_OF_FILE +#define EFI_INVALID_LANGUAGE RETURN_INVALID_LANGUAGE + +#define EFI_WARN_UNKNOWN_GLYPH RETURN_WARN_UNKNOWN_GLYPH +#define EFI_WARN_DELETE_FAILURE RETURN_WARN_DELETE_FAILURE +#define EFI_WARN_WRITE_FAILURE RETURN_WARN_WRITE_FAILURE +#define EFI_WARN_BUFFER_TOO_SMALL RETURN_WARN_BUFFER_TOO_SMALL + + +#define NULL_HANDLE ((VOID *) 0) + +// +// Define macro to encode the status code. +// +#define EFIERR(_a) ENCODE_ERROR(_a) + +#define EFI_ERROR(A) RETURN_ERROR(A) + +// +// Define macros to build data structure signatures from characters. +// +#define EFI_SIGNATURE_16(A, B) ((A) | (B << 8)) +#define EFI_SIGNATURE_32(A, B, C, D) (EFI_SIGNATURE_16 (A, B) | (EFI_SIGNATURE_16 (C, D) << 16)) +#define EFI_SIGNATURE_64(A, B, C, D, E, F, G, H) \ + (EFI_SIGNATURE_32 (A, B, C, D) | ((UINT64) (EFI_SIGNATURE_32 (E, F, G, H)) << 32)) + + +/// +/// Returns the byte offset to a field within a structure +/// +#define EFI_FIELD_OFFSET(TYPE,Field) ((UINTN)(&(((TYPE *) 0)->Field))) + +// +// The EFI memory allocation functions work in units of EFI_PAGEs that are +// 4K. This should in no way be confused with the page size of the processor. +// An EFI_PAGE is just the quanta of memory in EFI. +// +#define EFI_PAGE_SIZE 0x1000 +#define EFI_PAGE_MASK 0xFFF +#define EFI_PAGE_SHIFT 12 + +#define EFI_SIZE_TO_PAGES(a) (((a) >> EFI_PAGE_SHIFT) + (((a) & EFI_PAGE_MASK) ? 1 : 0)) + +#define EFI_PAGES_TO_SIZE(a) ( (a) << EFI_PAGE_SHIFT) + + +#define EFI_MAX_BIT MAX_BIT +#define EFI_MAX_ADDRESS MAX_ADDRESS + +#endif diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiGpt.h b/gpxe/src/include/gpxe/efi/Uefi/UefiGpt.h new file mode 100644 index 00000000..70d62fca --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Uefi/UefiGpt.h @@ -0,0 +1,66 @@ +/** @file + EFI Guid Partition Table Format Definition. + + Copyright (c) 2006 - 2007, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __UEFI_GPT_H__ +#define __UEFI_GPT_H__ + +#define PRIMARY_PART_HEADER_LBA 1 + +/// +/// EFI Partition Table Signature: "EFI PART" +/// +#define EFI_PTAB_HEADER_ID 0x5452415020494645ULL + +#pragma pack(1) + +/// +/// GPT Partition Table Header +/// +typedef struct { + EFI_TABLE_HEADER Header; + EFI_LBA MyLBA; + EFI_LBA AlternateLBA; + EFI_LBA FirstUsableLBA; + EFI_LBA LastUsableLBA; + EFI_GUID DiskGUID; + EFI_LBA PartitionEntryLBA; + UINT32 NumberOfPartitionEntries; + UINT32 SizeOfPartitionEntry; + UINT32 PartitionEntryArrayCRC32; +} EFI_PARTITION_TABLE_HEADER; + +/// +/// GPT Partition Entry +/// +typedef struct { + EFI_GUID PartitionTypeGUID; + EFI_GUID UniquePartitionGUID; + EFI_LBA StartingLBA; + EFI_LBA EndingLBA; + UINT64 Attributes; + CHAR16 PartitionName[36]; +} EFI_PARTITION_ENTRY; + +/// +/// GPT Partition Entry Status +/// +typedef struct { + BOOLEAN OutOfRange; + BOOLEAN Overlap; +} EFI_PARTITION_ENTRY_STATUS; + +#pragma pack() +#endif + + diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiInternalFormRepresentation.h b/gpxe/src/include/gpxe/efi/Uefi/UefiInternalFormRepresentation.h new file mode 100644 index 00000000..2a25c491 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Uefi/UefiInternalFormRepresentation.h @@ -0,0 +1,1499 @@ +/** @file + This file defines the encoding for the VFR (Visual Form Representation) language. + IFR is primarily consumed by the EFI presentation engine, and produced by EFI + internal application and drivers as well as all add-in card option-ROM drivers + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + These definitions are from UEFI2.1. + +**/ + +#ifndef __UEFI_INTERNAL_FORMREPRESENTATION_H__ +#define __UEFI_INTERNAL_FORMREPRESENTATION_H__ + +/// +/// The following types are currently defined: +/// +typedef UINT32 RELOFST; + +typedef VOID* EFI_HII_HANDLE; +typedef CHAR16* EFI_STRING; +typedef UINT16 EFI_IMAGE_ID; +typedef UINT16 EFI_QUESTION_ID; +typedef UINT16 EFI_STRING_ID; +typedef UINT16 EFI_FORM_ID; +typedef UINT16 EFI_VARSTORE_ID; +typedef UINT16 EFI_DEFAULT_ID; +typedef UINT32 EFI_HII_FONT_STYLE; + + + +#pragma pack(1) + + +/// +/// HII package list +/// +typedef struct { + EFI_GUID PackageListGuid; + UINT32 PackageLength; +} EFI_HII_PACKAGE_LIST_HEADER; + +/** + + Each package starts with a header, as defined above, which + indicates the size and type of the package. When added to a + pointer pointing to the start of the header, Length points at + the next package. The package lists form a package list when + concatenated together and terminated with an + EFI_HII_PACKAGE_HEADER with a Type of EFI_HII_PACKAGE_END. The + type EFI_HII_PACKAGE_TYPE_GUID is used for vendor-defined HII + packages, whose contents are determined by the Guid. The range + of package types starting with EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN + through EFI_HII_PACKAGE_TYPE_SYSTEM_END are reserved for system + firmware implementers. + + @param Length The size of the package in bytes. + + @param Type The package type. See EFI_HII_PACKAGE_TYPE_x, + below. + + @param Data The package data, the format of which is + determined by Type. + +**/ +typedef struct { + UINT32 Length:24; + UINT32 Type:8; + // UINT8 Data[...]; +} EFI_HII_PACKAGE_HEADER; + +// +// EFI_HII_PACKAGE_TYPE_x. +// +#define EFI_HII_PACKAGE_TYPE_ALL 0x00 +#define EFI_HII_PACKAGE_TYPE_GUID 0x01 +#define EFI_HII_PACKAGE_FORM 0x02 +#define EFI_HII_PACKAGE_KEYBOARD_LAYOUT 0x03 +#define EFI_HII_PACKAGE_STRINGS 0x04 +#define EFI_HII_PACKAGE_FONTS 0x05 +#define EFI_HII_PACKAGE_IMAGES 0x06 +#define EFI_HII_PACKAGE_SIMPLE_FONTS 0x07 +#define EFI_HII_PACKAGE_DEVICE_PATH 0x08 +#define EFI_HII_PACKAGE_END 0xDF +#define EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN 0xE0 +#define EFI_HII_PACKAGE_TYPE_SYSTEM_END 0xFF + +// +// Simplified Font Package +// + +#define EFI_GLYPH_HEIGHT 19 +#define EFI_GLYPH_WIDTH 8 +// +// Contents of EFI_NARROW_GLYPH.Attributes +// +#define EFI_GLYPH_NON_SPACING 0x01 +#define EFI_GLYPH_WIDE 0x02 + +typedef struct { + CHAR16 UnicodeWeight; + UINT8 Attributes; + UINT8 GlyphCol1[EFI_GLYPH_HEIGHT]; +} EFI_NARROW_GLYPH; + +typedef struct { + CHAR16 UnicodeWeight; + UINT8 Attributes; + UINT8 GlyphCol1[EFI_GLYPH_HEIGHT]; + UINT8 GlyphCol2[EFI_GLYPH_HEIGHT]; + UINT8 Pad[3]; +} EFI_WIDE_GLYPH; + + +typedef struct _EFI_HII_SIMPLE_FONT_PACKAGE_HDR { + EFI_HII_PACKAGE_HEADER Header; + UINT16 NumberOfNarrowGlyphs; + UINT16 NumberOfWideGlyphs; + // EFI_NARROW_GLYPH NarrowGlyphs[]; + // EFI_WIDE_GLYPH WideGlyphs[]; +} EFI_HII_SIMPLE_FONT_PACKAGE_HDR; + +// +// Font Package +// + +#define EFI_HII_FONT_STYLE_NORMAL 0x00000000 +#define EFI_HII_FONT_STYLE_BOLD 0x00000001 +#define EFI_HII_FONT_STYLE_ITALIC 0x00000002 +#define EFI_HII_FONT_STYLE_EMBOSS 0x00010000 +#define EFI_HII_FONT_STYLE_OUTLINE 0x00020000 +#define EFI_HII_FONT_STYLE_SHADOW 0x00040000 +#define EFI_HII_FONT_STYLE_UNDERLINE 0x00080000 +#define EFI_HII_FONT_STYLE_DBL_UNDER 0x00100000 + +typedef struct _EFI_HII_GLYPH_INFO { + UINT16 Width; + UINT16 Height; + INT16 OffsetX; + INT16 OffsetY; + INT16 AdvanceX; +} EFI_HII_GLYPH_INFO; + +typedef struct _EFI_HII_FONT_PACKAGE_HDR { + EFI_HII_PACKAGE_HEADER Header; + UINT32 HdrSize; + UINT32 GlyphBlockOffset; + EFI_HII_GLYPH_INFO Cell; + EFI_HII_FONT_STYLE FontStyle; + CHAR16 FontFamily[1]; +} EFI_HII_FONT_PACKAGE_HDR; + +#define EFI_HII_GIBT_END 0x00 +#define EFI_HII_GIBT_GLYPH 0x10 +#define EFI_HII_GIBT_GLYPHS 0x11 +#define EFI_HII_GIBT_GLYPH_DEFAULT 0x12 +#define EFI_HII_GIBT_GLYPHS_DEFAULT 0x13 +#define EFI_HII_GIBT_DUPLICATE 0x20 +#define EFI_HII_GIBT_SKIP2 0x21 +#define EFI_HII_GIBT_SKIP1 0x22 +#define EFI_HII_GIBT_DEFAULTS 0x23 +#define EFI_HII_GIBT_EXT1 0x30 +#define EFI_HII_GIBT_EXT2 0x31 +#define EFI_HII_GIBT_EXT4 0x32 + +typedef struct _EFI_HII_GLYPH_BLOCK { + UINT8 BlockType; +} EFI_HII_GLYPH_BLOCK; + +typedef struct _EFI_HII_GIBT_DEFAULTS_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + EFI_HII_GLYPH_INFO Cell; +} EFI_HII_GIBT_DEFAULTS_BLOCK; + +typedef struct _EFI_HII_GIBT_DUPLICATE_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + CHAR16 CharValue; +} EFI_HII_GIBT_DUPLICATE_BLOCK; + +typedef struct _EFI_GLYPH_GIBT_END_BLOCK { + EFI_HII_GLYPH_BLOCK Header; +} EFI_GLYPH_GIBT_END_BLOCK; + +typedef struct _EFI_HII_GIBT_EXT1_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT8 BlockType2; + UINT8 Length; +} EFI_HII_GIBT_EXT1_BLOCK; + +typedef struct _EFI_HII_GIBT_EXT2_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT8 BlockType2; + UINT16 Length; +} EFI_HII_GIBT_EXT2_BLOCK; + +typedef struct _EFI_HII_GIBT_EXT4_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT8 BlockType2; + UINT32 Length; +} EFI_HII_GIBT_EXT4_BLOCK; + +typedef struct _EFI_HII_GIBT_GLYPH_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + EFI_HII_GLYPH_INFO Cell; + UINT8 BitmapData[1]; // the number of bytes per bitmap can be calculated by ((Cell.Width+7)/8)*Cell.Height +} EFI_HII_GIBT_GLYPH_BLOCK; + +typedef struct _EFI_HII_GIBT_GLYPHS_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + EFI_HII_GLYPH_INFO Cell; + UINT16 Count; + UINT8 BitmapData[1]; // the number of bytes per bitmap can be calculated by ((Cell.Width+7)/8)*Cell.Height +} EFI_HII_GIBT_GLYPHS_BLOCK; + +typedef struct _EFI_HII_GIBT_GLYPH_DEFAULT_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT8 BitmapData[1]; // the number of bytes per bitmap can be calculated by ((Global.Cell.Width+7)/8)*Global.Cell.Height +} EFI_HII_GIBT_GLYPH_DEFAULT_BLOCK; + +typedef struct _EFI_HII_GIBT_GLYPHS_DEFAULT_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT16 Count; + UINT8 BitmapData[1]; // the number of bytes per bitmap can be calculated by ((Global.Cell.Width+7)/8)*Global.Cell.Height +} EFI_HII_GIBT_GLYPHS_DEFAULT_BLOCK; + +typedef struct _EFI_HII_GIBT_SKIP1_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT8 SkipCount; +} EFI_HII_GIBT_SKIP1_BLOCK; + +typedef struct _EFI_HII_GIBT_SKIP2_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT16 SkipCount; +} EFI_HII_GIBT_SKIP2_BLOCK; + +// +// Device Path Package +// +typedef struct _EFI_HII_DEVICE_PATH_PACKAGE { + EFI_HII_PACKAGE_HEADER Header; + // EFI_DEVICE_PATH_PROTOCOL DevicePath[]; +} EFI_HII_DEVICE_PATH_PACKAGE; + +// +// GUID Package +// +typedef struct _EFI_HII_GUID_PACKAGE_HDR { + EFI_HII_PACKAGE_HEADER Header; + EFI_GUID Guid; + // Data per GUID definition may follow +} EFI_HII_GUID_PACKAGE_HDR; + +// +// String Package +// + +#define UEFI_CONFIG_LANG L"x-UEFI" +#define UEFI_CONFIG_LANG2 L"x-i-UEFI" // BUGBUG, spec need to be updated. + +typedef struct _EFI_HII_STRING_PACKAGE_HDR { + EFI_HII_PACKAGE_HEADER Header; + UINT32 HdrSize; + UINT32 StringInfoOffset; + CHAR16 LanguageWindow[16]; + EFI_STRING_ID LanguageName; + CHAR8 Language[1]; +} EFI_HII_STRING_PACKAGE_HDR; + +typedef struct { + UINT8 BlockType; +} EFI_HII_STRING_BLOCK; + +#define EFI_HII_SIBT_END 0x00 +#define EFI_HII_SIBT_STRING_SCSU 0x10 +#define EFI_HII_SIBT_STRING_SCSU_FONT 0x11 +#define EFI_HII_SIBT_STRINGS_SCSU 0x12 +#define EFI_HII_SIBT_STRINGS_SCSU_FONT 0x13 +#define EFI_HII_SIBT_STRING_UCS2 0x14 +#define EFI_HII_SIBT_STRING_UCS2_FONT 0x15 +#define EFI_HII_SIBT_STRINGS_UCS2 0x16 +#define EFI_HII_SIBT_STRINGS_UCS2_FONT 0x17 +#define EFI_HII_SIBT_DUPLICATE 0x20 +#define EFI_HII_SIBT_SKIP2 0x21 +#define EFI_HII_SIBT_SKIP1 0x22 +#define EFI_HII_SIBT_EXT1 0x30 +#define EFI_HII_SIBT_EXT2 0x31 +#define EFI_HII_SIBT_EXT4 0x32 +#define EFI_HII_SIBT_FONT 0x40 + +typedef struct _EFI_HII_SIBT_DUPLICATE_BLOCK { + EFI_HII_STRING_BLOCK Header; + EFI_STRING_ID StringId; +} EFI_HII_SIBT_DUPLICATE_BLOCK; + +typedef struct _EFI_HII_SIBT_END_BLOCK { + EFI_HII_STRING_BLOCK Header; +} EFI_HII_SIBT_END_BLOCK; + +typedef struct _EFI_HII_SIBT_EXT1_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 BlockType2; + UINT8 Length; +} EFI_HII_SIBT_EXT1_BLOCK; + +typedef struct _EFI_HII_SIBT_EXT2_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 BlockType2; + UINT16 Length; +} EFI_HII_SIBT_EXT2_BLOCK; + +typedef struct _EFI_HII_SIBT_EXT4_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 BlockType2; + UINT32 Length; +} EFI_HII_SIBT_EXT4_BLOCK; + +typedef struct _EFI_HII_SIBT_FONT_BLOCK { + EFI_HII_SIBT_EXT2_BLOCK Header; + UINT8 FontId; + UINT16 FontSize; + EFI_HII_FONT_STYLE FontStyle; + CHAR16 FontName[1]; +} EFI_HII_SIBT_FONT_BLOCK; + +typedef struct _EFI_HII_SIBT_SKIP1_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 SkipCount; +} EFI_HII_SIBT_SKIP1_BLOCK; + +typedef struct _EFI_HII_SIBT_SKIP2_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT16 SkipCount; +} EFI_HII_SIBT_SKIP2_BLOCK; + +typedef struct _EFI_HII_SIBT_STRING_SCSU_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 StringText[1]; +} EFI_HII_SIBT_STRING_SCSU_BLOCK; + +typedef struct _EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 FontIdentifier; + UINT8 StringText[1]; +} EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK; + +typedef struct _EFI_HII_SIBT_STRINGS_SCSU_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT16 StringCount; + UINT8 StringText[1]; +} EFI_HII_SIBT_STRINGS_SCSU_BLOCK; + +typedef struct _EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 FontIdentifier; + UINT16 StringCount; + UINT8 StringText[1]; +} EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK; + +typedef struct _EFI_HII_SIBT_STRING_UCS2_BLOCK { + EFI_HII_STRING_BLOCK Header; + CHAR16 StringText[1]; +} EFI_HII_SIBT_STRING_UCS2_BLOCK; + +typedef struct _EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 FontIdentifier; + CHAR16 StringText[1]; +} EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK; + +typedef struct _EFI_HII_SIBT_STRINGS_UCS2_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT16 StringCount; + CHAR16 StringText[1]; +} EFI_HII_SIBT_STRINGS_UCS2_BLOCK; + +typedef struct _EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 FontIdentifier; + UINT16 StringCount; + CHAR16 StringText[1]; +} EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK; + +// +// Image Packages +// + +typedef struct _EFI_HII_IMAGE_PACKAGE_HDR { + EFI_HII_PACKAGE_HEADER Header; + UINT32 ImageInfoOffset; + UINT32 PaletteInfoOffset; +} EFI_HII_IMAGE_PACKAGE_HDR; + +typedef struct _EFI_HII_IMAGE_BLOCK { + UINT8 BlockType; +} EFI_HII_IMAGE_BLOCK; + +#define EFI_HII_IIBT_END 0x00 +#define EFI_HII_IIBT_IMAGE_1BIT 0x10 +#define EFI_HII_IIBT_IMAGE_1BIT_TRANS 0x11 +#define EFI_HII_IIBT_IMAGE_4BIT 0x12 +#define EFI_HII_IIBT_IMAGE_4BIT_TRANS 0x13 +#define EFI_HII_IIBT_IMAGE_8BIT 0x14 +#define EFI_HII_IIBT_IMAGE_8BIT_TRANS 0x15 +#define EFI_HII_IIBT_IMAGE_24BIT 0x16 +#define EFI_HII_IIBT_IMAGE_24BIT_TRANS 0x17 +#define EFI_HII_IIBT_IMAGE_JPEG 0x18 +#define EFI_HII_IIBT_DUPLICATE 0x20 +#define EFI_HII_IIBT_SKIP2 0x21 +#define EFI_HII_IIBT_SKIP1 0x22 +#define EFI_HII_IIBT_EXT1 0x30 +#define EFI_HII_IIBT_EXT2 0x31 +#define EFI_HII_IIBT_EXT4 0x32 + +typedef struct _EFI_HII_IIBT_END_BLOCK { + EFI_HII_IMAGE_BLOCK Header; +} EFI_HII_IIBT_END_BLOCK; + +typedef struct _EFI_HII_IIBT_EXT1_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 BlockType2; + UINT8 Length; +} EFI_HII_IIBT_EXT1_BLOCK; + +typedef struct _EFI_HII_IIBT_EXT2_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 BlockType2; + UINT16 Length; +} EFI_HII_IIBT_EXT2_BLOCK; + +typedef struct _EFI_HII_IIBT_EXT4_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 BlockType2; + UINT32 Length; +} EFI_HII_IIBT_EXT4_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_1BIT_BASE { + UINT16 Width; + UINT16 Height; + UINT8 Data[1]; +} EFI_HII_IIBT_IMAGE_1BIT_BASE; + +typedef struct _EFI_HII_IIBT_IMAGE_1BIT_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 PaletteIndex; + EFI_HII_IIBT_IMAGE_1BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_1BIT_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_1BIT_TRANS_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 PaletteIndex; + EFI_HII_IIBT_IMAGE_1BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_1BIT_TRANS_BLOCK; + +typedef struct _EFI_HII_RGB_PIXEL { + UINT8 b; + UINT8 g; + UINT8 r; +} EFI_HII_RGB_PIXEL; + +typedef struct _EFI_HII_IIBT_IMAGE_24BIT_BASE { + UINT16 Width; + UINT16 Height; + EFI_HII_RGB_PIXEL Bitmap[1]; +} EFI_HII_IIBT_IMAGE_24BIT_BASE; + +typedef struct _EFI_HII_IIBT_IMAGE_24BIT_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + EFI_HII_IIBT_IMAGE_24BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_24BIT_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_24BIT_TRANS_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + EFI_HII_IIBT_IMAGE_24BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_24BIT_TRANS_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_4BIT_BASE { + UINT16 Width; + UINT16 Height; + UINT8 Data[1]; +} EFI_HII_IIBT_IMAGE_4BIT_BASE; + +typedef struct _EFI_HII_IIBT_IMAGE_4BIT_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 PaletteIndex; + EFI_HII_IIBT_IMAGE_4BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_4BIT_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_4BIT_TRANS_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 PaletteIndex; + EFI_HII_IIBT_IMAGE_4BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_4BIT_TRANS_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_8BIT_BASE { + UINT16 Width; + UINT16 Height; + UINT8 Data[1]; +} EFI_HII_IIBT_IMAGE_8BIT_BASE; + +typedef struct _EFI_HII_IIBT_IMAGE_8BIT_PALETTE_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 PaletteIndex; + EFI_HII_IIBT_IMAGE_8BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_8BIT_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_8BIT_TRANS_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 PaletteIndex; + EFI_HII_IIBT_IMAGE_8BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_8BIT_TRAN_BLOCK; + +typedef struct _EFI_HII_IIBT_DUPLICATE_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + EFI_IMAGE_ID ImageId; +} EFI_HII_IIBT_DUPLICATE_BLOCK; + +typedef struct _EFI_HII_IIBT_JPEG_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT32 Size; + UINT8 Data[1]; +} EFI_HII_IIBT_JPEG_BLOCK; + +typedef struct _EFI_HII_IIBT_SKIP1_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 SkipCount; +} EFI_HII_IIBT_SKIP1_BLOCK; + +typedef struct _EFI_HII_IIBT_SKIP2_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT16 SkipCount; +} EFI_HII_IIBT_SKIP2_BLOCK; + +typedef struct _EFI_HII_IMAGE_PALETTE_INFO_HEADER { + UINT16 PaletteCount; +} EFI_HII_IMAGE_PALETTE_INFO_HEADER; + +typedef struct _EFI_HII_IMAGE_PALETTE_INFO { + UINT16 PaletteSize; + EFI_HII_RGB_PIXEL PaletteValue[1]; +} EFI_HII_IMAGE_PALETTE_INFO; + +// +// Forms Package +// + +typedef struct _EFI_HII_FORM_PACKAGE { + EFI_HII_PACKAGE_HEADER Header; + // EFI_IFR_OP_HEADER OpCodeHeader; + // More op-codes follow +} EFI_HII_FORM_PACKAGE; + +typedef struct { + UINT8 Hour; + UINT8 Minute; + UINT8 Second; +} EFI_HII_TIME; + +typedef struct { + UINT16 Year; + UINT8 Month; + UINT8 Day; +} EFI_HII_DATE; + +typedef union { + UINT8 u8; + UINT16 u16; + UINT32 u32; + UINT64 u64; + BOOLEAN b; + EFI_HII_TIME time; + EFI_HII_DATE date; + EFI_STRING_ID string; +} EFI_IFR_TYPE_VALUE; + +// +// IFR Opcodes +// +#define EFI_IFR_FORM_OP 0x01 +#define EFI_IFR_SUBTITLE_OP 0x02 +#define EFI_IFR_TEXT_OP 0x03 +#define EFI_IFR_IMAGE_OP 0x04 +#define EFI_IFR_ONE_OF_OP 0x05 +#define EFI_IFR_CHECKBOX_OP 0x06 +#define EFI_IFR_NUMERIC_OP 0x07 +#define EFI_IFR_PASSWORD_OP 0x08 +#define EFI_IFR_ONE_OF_OPTION_OP 0x09 +#define EFI_IFR_SUPPRESS_IF_OP 0x0A +#define EFI_IFR_LOCKED_OP 0x0B +#define EFI_IFR_ACTION_OP 0x0C +#define EFI_IFR_RESET_BUTTON_OP 0x0D +#define EFI_IFR_FORM_SET_OP 0x0E +#define EFI_IFR_REF_OP 0x0F +#define EFI_IFR_NO_SUBMIT_IF_OP 0x10 +#define EFI_IFR_INCONSISTENT_IF_OP 0x11 +#define EFI_IFR_EQ_ID_VAL_OP 0x12 +#define EFI_IFR_EQ_ID_ID_OP 0x13 +#define EFI_IFR_EQ_ID_LIST_OP 0x14 +#define EFI_IFR_AND_OP 0x15 +#define EFI_IFR_OR_OP 0x16 +#define EFI_IFR_NOT_OP 0x17 +#define EFI_IFR_RULE_OP 0x18 +#define EFI_IFR_GRAY_OUT_IF_OP 0x19 +#define EFI_IFR_DATE_OP 0x1A +#define EFI_IFR_TIME_OP 0x1B +#define EFI_IFR_STRING_OP 0x1C +#define EFI_IFR_REFRESH_OP 0x1D +#define EFI_IFR_DISABLE_IF_OP 0x1E +#define EFI_IFR_TO_LOWER_OP 0x20 +#define EFI_IFR_TO_UPPER_OP 0x21 +#define EFI_IFR_ORDERED_LIST_OP 0x23 +#define EFI_IFR_VARSTORE_OP 0x24 +#define EFI_IFR_VARSTORE_NAME_VALUE_OP 0x25 +#define EFI_IFR_VARSTORE_EFI_OP 0x26 +#define EFI_IFR_VARSTORE_DEVICE_OP 0x27 +#define EFI_IFR_VERSION_OP 0x28 +#define EFI_IFR_END_OP 0x29 +#define EFI_IFR_MATCH_OP 0x2A +#define EFI_IFR_EQUAL_OP 0x2F +#define EFI_IFR_NOT_EQUAL_OP 0x30 +#define EFI_IFR_GREATER_THAN_OP 0x31 +#define EFI_IFR_GREATER_EQUAL_OP 0x32 +#define EFI_IFR_LESS_THAN_OP 0x33 +#define EFI_IFR_LESS_EQUAL_OP 0x34 +#define EFI_IFR_BITWISE_AND_OP 0x35 +#define EFI_IFR_BITWISE_OR_OP 0x36 +#define EFI_IFR_BITWISE_NOT_OP 0x37 +#define EFI_IFR_SHIFT_LEFT_OP 0x38 +#define EFI_IFR_SHIFT_RIGHT_OP 0x39 +#define EFI_IFR_ADD_OP 0x3A +#define EFI_IFR_SUBTRACT_OP 0x3B +#define EFI_IFR_MULTIPLY_OP 0x3C +#define EFI_IFR_DIVIDE_OP 0x3D +#define EFI_IFR_MODULO_OP 0x3E +#define EFI_IFR_RULE_REF_OP 0x3F +#define EFI_IFR_QUESTION_REF1_OP 0x40 +#define EFI_IFR_QUESTION_REF2_OP 0x41 +#define EFI_IFR_UINT8_OP 0x42 +#define EFI_IFR_UINT16_OP 0x43 +#define EFI_IFR_UINT32_OP 0x44 +#define EFI_IFR_UINT64_OP 0x45 +#define EFI_IFR_TRUE_OP 0x46 +#define EFI_IFR_FALSE_OP 0x47 +#define EFI_IFR_TO_UINT_OP 0x48 +#define EFI_IFR_TO_STRING_OP 0x49 +#define EFI_IFR_TO_BOOLEAN_OP 0x4A +#define EFI_IFR_MID_OP 0x4B +#define EFI_IFR_FIND_OP 0x4C +#define EFI_IFR_TOKEN_OP 0x4D +#define EFI_IFR_STRING_REF1_OP 0x4E +#define EFI_IFR_STRING_REF2_OP 0x4F +#define EFI_IFR_CONDITIONAL_OP 0x50 +#define EFI_IFR_QUESTION_REF3_OP 0x51 +#define EFI_IFR_ZERO_OP 0x52 +#define EFI_IFR_ONE_OP 0x53 +#define EFI_IFR_ONES_OP 0x54 +#define EFI_IFR_UNDEFINED_OP 0x55 +#define EFI_IFR_LENGTH_OP 0x56 +#define EFI_IFR_DUP_OP 0x57 +#define EFI_IFR_THIS_OP 0x58 +#define EFI_IFR_SPAN_OP 0x59 +#define EFI_IFR_VALUE_OP 0x5A +#define EFI_IFR_DEFAULT_OP 0x5B +#define EFI_IFR_DEFAULTSTORE_OP 0x5C +#define EFI_IFR_CATENATE_OP 0x5E +#define EFI_IFR_GUID_OP 0x5F + + +typedef struct _EFI_IFR_OP_HEADER { + UINT8 OpCode; + UINT8 Length:7; + UINT8 Scope:1; +} EFI_IFR_OP_HEADER; + +typedef struct _EFI_IFR_STATEMENT_HEADER { + EFI_STRING_ID Prompt; + EFI_STRING_ID Help; +} EFI_IFR_STATEMENT_HEADER; + +typedef struct _EFI_IFR_QUESTION_HEADER { + EFI_IFR_STATEMENT_HEADER Header; + EFI_QUESTION_ID QuestionId; + EFI_VARSTORE_ID VarStoreId; + union { + EFI_STRING_ID VarName; + UINT16 VarOffset; + } VarStoreInfo; + UINT8 Flags; +} EFI_IFR_QUESTION_HEADER; + +#define EFI_IFR_FLAG_READ_ONLY 0x01 +#define EFI_IFR_FLAG_CALLBACK 0x04 +#define EFI_IFR_FLAG_RESET_REQUIRED 0x10 +#define EFI_IFR_FLAG_OPTIONS_ONLY 0x80 + +typedef struct _EFI_IFR_DEFAULTSTORE { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID DefaultName; + UINT16 DefaultId; +} EFI_IFR_DEFAULTSTORE; + +#define EFI_HII_DEFAULT_CLASS_STANDARD 0x0000 +#define EFI_HII_DEFAULT_CLASS_MANUFACTURING 0x0001 +#define EFI_HII_DEFAULT_CLASS_SAFE 0x0002 +#define EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN 0x4000 +#define EFI_HII_DEFAULT_CLASS_PLATFORM_END 0x7fff +#define EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN 0x8000 +#define EFI_HII_DEFAULT_CLASS_HARDWARE_END 0xbfff +#define EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN 0xc000 +#define EFI_HII_DEFAULT_CLASS_FIRMWARE_END 0xffff + +typedef struct _EFI_IFR_VARSTORE { + EFI_IFR_OP_HEADER Header; + EFI_GUID Guid; + EFI_VARSTORE_ID VarStoreId; + UINT16 Size; + UINT8 Name[1]; +} EFI_IFR_VARSTORE; + +typedef struct _EFI_IFR_VARSTORE_EFI { + EFI_IFR_OP_HEADER Header; + EFI_VARSTORE_ID VarStoreId; + EFI_GUID Guid; + UINT32 Attributes; +} EFI_IFR_VARSTORE_EFI; + +typedef struct _EFI_IFR_VARSTORE_NAME_VALUE { + EFI_IFR_OP_HEADER Header; + EFI_VARSTORE_ID VarStoreId; + EFI_GUID Guid; +} EFI_IFR_VARSTORE_NAME_VALUE; + +typedef struct _EFI_IFR_FORM_SET { + EFI_IFR_OP_HEADER Header; + EFI_GUID Guid; + EFI_STRING_ID FormSetTitle; + EFI_STRING_ID Help; +} EFI_IFR_FORM_SET; + +typedef struct _EFI_IFR_END { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_END; + +typedef struct _EFI_IFR_FORM { + EFI_IFR_OP_HEADER Header; + UINT16 FormId; + EFI_STRING_ID FormTitle; +} EFI_IFR_FORM; + +typedef struct _EFI_IFR_IMAGE { + EFI_IFR_OP_HEADER Header; + EFI_IMAGE_ID Id; +} EFI_IFR_IMAGE; + +typedef struct _EFI_IFR_LOCKED { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_LOCKED; + +typedef struct _EFI_IFR_RULE { + EFI_IFR_OP_HEADER Header; + UINT8 RuleId; +} EFI_IFR_RULE; + +typedef struct _EFI_IFR_DEFAULT { + EFI_IFR_OP_HEADER Header; + UINT16 DefaultId; + UINT8 Type; + EFI_IFR_TYPE_VALUE Value; +} EFI_IFR_DEFAULT; + +typedef struct _EFI_IFR_VALUE { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_VALUE; + +typedef struct _EFI_IFR_SUBTITLE { + EFI_IFR_OP_HEADER Header; + EFI_IFR_STATEMENT_HEADER Statement; + UINT8 Flags; +} EFI_IFR_SUBTITLE; + +#define EFI_IFR_FLAGS_HORIZONTAL 0x01 + +typedef struct _EFI_IFR_CHECKBOX { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 Flags; +} EFI_IFR_CHECKBOX; + +#define EFI_IFR_CHECKBOX_DEFAULT 0x01 +#define EFI_IFR_CHECKBOX_DEFAULT_MFG 0x02 + +typedef struct _EFI_IFR_TEXT { + EFI_IFR_OP_HEADER Header; + EFI_IFR_STATEMENT_HEADER Statement; + EFI_STRING_ID TextTwo; +} EFI_IFR_TEXT; + +typedef struct _EFI_IFR_REF { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + EFI_FORM_ID FormId; +} EFI_IFR_REF; + +typedef struct _EFI_IFR_REF2 { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + EFI_FORM_ID FormId; + EFI_QUESTION_ID QuestionId; +} EFI_IFR_REF2; + +typedef struct _EFI_IFR_REF3 { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + EFI_FORM_ID FormId; + EFI_QUESTION_ID QuestionId; + EFI_GUID FormSetId; +} EFI_IFR_REF3; + +typedef struct _EFI_IFR_REF4 { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + EFI_FORM_ID FormId; + EFI_QUESTION_ID QuestionId; + EFI_GUID FormSetId; + EFI_STRING_ID DevicePath; +} EFI_IFR_REF4; + +typedef struct _EFI_IFR_RESET_BUTTON { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + EFI_DEFAULT_ID DefaultId; +} EFI_IFR_RESET_BUTTON; + +typedef struct _EFI_IFR_ACTION { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + EFI_STRING_ID QuestionConfig; +} EFI_IFR_ACTION; + +typedef struct _EFI_IFR_ACTION_1 { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; +} EFI_IFR_ACTION_1; + +typedef struct _EFI_IFR_DATE { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 Flags; +} EFI_IFR_DATE; + +#define EFI_QF_DATE_YEAR_SUPPRESS 0x01 +#define EFI_QF_DATE_MONTH_SUPPRESS 0x02 +#define EFI_QF_DATE_DAY_SUPPRESS 0x04 + +#define EFI_QF_DATE_STORAGE 0x30 +#define QF_DATE_STORAGE_NORMAL 0x00 +#define QF_DATE_STORAGE_TIME 0x10 +#define QF_DATE_STORAGE_WAKEUP 0x20 + +typedef union { + struct { + UINT8 MinValue; + UINT8 MaxValue; + UINT8 Step; + } u8; + struct { + UINT16 MinValue; + UINT16 MaxValue; + UINT16 Step; + } u16; + struct { + UINT32 MinValue; + UINT32 MaxValue; + UINT32 Step; + } u32; + struct { + UINT64 MinValue; + UINT64 MaxValue; + UINT64 Step; + } u64; +} MINMAXSTEP_DATA; + +typedef struct _EFI_IFR_NUMERIC { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 Flags; + MINMAXSTEP_DATA data; +} EFI_IFR_NUMERIC; + +#define EFI_IFR_NUMERIC_SIZE 0x03 +#define EFI_IFR_NUMERIC_SIZE_1 0x00 +#define EFI_IFR_NUMERIC_SIZE_2 0x01 +#define EFI_IFR_NUMERIC_SIZE_4 0x02 +#define EFI_IFR_NUMERIC_SIZE_8 0x03 + +#define EFI_IFR_DISPLAY 0x30 +#define EFI_IFR_DISPLAY_INT_DEC 0x00 +#define EFI_IFR_DISPLAY_UINT_DEC 0x10 +#define EFI_IFR_DISPLAY_UINT_HEX 0x20 + +typedef struct _EFI_IFR_ONE_OF { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 Flags; + MINMAXSTEP_DATA data; +} EFI_IFR_ONE_OF; + +typedef struct _EFI_IFR_STRING { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 MinSize; + UINT8 MaxSize; + UINT8 Flags; +} EFI_IFR_STRING; + +#define EFI_IFR_STRING_MULTI_LINE 0x01 + +typedef struct _EFI_IFR_PASSWORD { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT16 MinSize; + UINT16 MaxSize; +} EFI_IFR_PASSWORD; + +typedef struct _EFI_IFR_ORDERED_LIST { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 MaxContainers; + UINT8 Flags; +} EFI_IFR_ORDERED_LIST; + +#define EFI_IFR_UNIQUE_SET 0x01 +#define EFI_IFR_NO_EMPTY_SET 0x02 + +typedef struct _EFI_IFR_TIME { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 Flags; +} EFI_IFR_TIME; + +#define QF_TIME_HOUR_SUPPRESS 0x01 +#define QF_TIME_MINUTE_SUPPRESS 0x02 +#define QF_TIME_SECOND_SUPPRESS 0x04 + +#define QF_TIME_STORAGE 0x30 +#define QF_TIME_STORAGE_NORMAL 0x00 +#define QF_TIME_STORAGE_TIME 0x10 +#define QF_TIME_STORAGE_WAKEUP 0x20 + +typedef struct _EFI_IFR_DISABLE_IF { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_DISABLE_IF; + +typedef struct _EFI_IFR_SUPPRESS_IF { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_SUPPRESS_IF; + +typedef struct _EFI_IFR_GRAY_OUT_IF { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_GRAY_OUT_IF; + +typedef struct _EFI_IFR_INCONSISTENT_IF { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID Error; +} EFI_IFR_INCONSISTENT_IF; + +typedef struct _EFI_IFR_NO_SUBMIT_IF { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID Error; +} EFI_IFR_NO_SUBMIT_IF; + +typedef struct _EFI_IFR_REFRESH { + EFI_IFR_OP_HEADER Header; + UINT8 RefreshInterval; +} EFI_IFR_REFRESH; + +typedef struct _EFI_IFR_VARSTORE_DEVICE { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID DevicePath; +} EFI_IFR_VARSTORE_DEVICE; + +typedef struct _EFI_IFR_ONE_OF_OPTION { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID Option; + UINT8 Flags; + UINT8 Type; + EFI_IFR_TYPE_VALUE Value; +} EFI_IFR_ONE_OF_OPTION; + +#define EFI_IFR_TYPE_NUM_SIZE_8 0x00 +#define EFI_IFR_TYPE_NUM_SIZE_16 0x01 +#define EFI_IFR_TYPE_NUM_SIZE_32 0x02 +#define EFI_IFR_TYPE_NUM_SIZE_64 0x03 +#define EFI_IFR_TYPE_BOOLEAN 0x04 +#define EFI_IFR_TYPE_TIME 0x05 +#define EFI_IFR_TYPE_DATE 0x06 +#define EFI_IFR_TYPE_STRING 0x07 +#define EFI_IFR_TYPE_OTHER 0x08 + +#define EFI_IFR_OPTION_DEFAULT 0x10 +#define EFI_IFR_OPTION_DEFAULT_MFG 0x20 + +typedef struct _EFI_IFR_GUID { + EFI_IFR_OP_HEADER Header; + EFI_GUID Guid; + //Optional Data Follows +} EFI_IFR_GUID; + +typedef struct _EFI_IFR_DUP { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_DUP; + +typedef struct _EFI_IFR_EQ_ID_ID { + EFI_IFR_OP_HEADER Header; + EFI_QUESTION_ID QuestionId1; + EFI_QUESTION_ID QuestionId2; +} EFI_IFR_EQ_ID_ID; + +typedef struct _EFI_IFR_EQ_ID_VAL { + EFI_IFR_OP_HEADER Header; + EFI_QUESTION_ID QuestionId; + UINT16 Value; +} EFI_IFR_EQ_ID_VAL; + +typedef struct _EFI_IFR_EQ_ID_LIST { + EFI_IFR_OP_HEADER Header; + EFI_QUESTION_ID QuestionId; + UINT16 ListLength; + UINT16 ValueList[1]; +} EFI_IFR_EQ_ID_LIST; + +typedef struct _EFI_IFR_QUESTION_REF1 { + EFI_IFR_OP_HEADER Header; + EFI_QUESTION_ID QuestionId; +} EFI_IFR_QUESTION_REF1; + +typedef struct _EFI_IFR_UINT8 { + EFI_IFR_OP_HEADER Header; + UINT8 Value; +} EFI_IFR_UINT8; + +typedef struct _EFI_IFR_UINT16 { + EFI_IFR_OP_HEADER Header; + UINT16 Value; +} EFI_IFR_UINT16; + +typedef struct _EFI_IFR_QUESTION_REF2 { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_QUESTION_REF2; + +typedef struct _EFI_IFR_UINT32 { + EFI_IFR_OP_HEADER Header; + UINT32 Value; +} EFI_IFR_UINT32; + +typedef struct _EFI_IFR_UINT64 { + EFI_IFR_OP_HEADER Header; + UINT64 Value; +} EFI_IFR_UINT64; + +typedef struct _EFI_IFR_QUESTION_REF3 { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_QUESTION_REF3; + +typedef struct _EFI_IFR_QUESTION_REF3_2 { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID DevicePath; +} EFI_IFR_QUESTION_REF3_2; + +typedef struct _EFI_IFR_QUESTION_REF3_3 { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID DevicePath; + EFI_GUID Guid; +} EFI_IFR_QUESTION_REF3_3; + +typedef struct _EFI_IFR_RULE_REF { + EFI_IFR_OP_HEADER Header; + UINT8 RuleId; +} EFI_IFR_RULE_REF; + +typedef struct _EFI_IFR_STRING_REF1 { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID StringId; +} EFI_IFR_STRING_REF1; + +typedef struct _EFI_IFR_STRING_REF2 { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_STRING_REF2; + +typedef struct _EFI_IFR_THIS { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_THIS; + +typedef struct _EFI_IFR_TRUE { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_TRUE; + +typedef struct _EFI_IFR_FALSE { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_FALSE; + +typedef struct _EFI_IFR_ONE { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_ONE; + +typedef struct _EFI_IFR_ONES { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_ONES; + +typedef struct _EFI_IFR_ZERO { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_ZERO; + +typedef struct _EFI_IFR_UNDEFINED { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_UNDEFINED; + +typedef struct _EFI_IFR_VERSION { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_VERSION; + +typedef struct _EFI_IFR_LENGTH { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_LENGTH; + +typedef struct _EFI_IFR_NOT { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_NOT; + +typedef struct _EFI_IFR_BITWISE_NOT { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_BITWISE_NOT; + +typedef struct _EFI_IFR_TO_BOOLEAN { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_TO_BOOLEAN; + +#define EFI_IFR_STRING_UNSIGNED_DEC 0 +#define EFI_IFR_STRING_SIGNED_DEC 1 +#define EFI_IFR_STRING_LOWERCASE_HEX 2 +#define EFI_IFR_STRING_UPPERCASE_HEX 3 + +#define EFI_IFR_STRING_ASCII 0 +#define EFI_IFR_STRING_UNICODE 8 + +typedef struct _EFI_IFR_TO_STRING { + EFI_IFR_OP_HEADER Header; + UINT8 Format; +} EFI_IFR_TO_STRING; + +typedef struct _EFI_IFR_TO_UINT { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_TO_UINT; + +typedef struct _EFI_IFR_TO_UPPER { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_TO_UPPER; + +typedef struct _EFI_IFR_TO_LOWER { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_TO_LOWER; + +typedef struct _EFI_IFR_ADD { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_ADD; + +typedef struct _EFI_IFR_AND { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_AND; + +typedef struct _EFI_IFR_BITWISE_AND { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_BITWISE_AND; + +typedef struct _EFI_IFR_BITWISE_OR { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_BITWISE_OR; + +typedef struct _EFI_IFR_CATENATE { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_CATENATE; + +typedef struct _EFI_IFR_DIVIDE { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_DIVIDE; + +typedef struct _EFI_IFR_EQUAL { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_EQUAL; + +typedef struct _EFI_IFR_GREATER_EQUAL { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_GREATER_EQUAL; + +typedef struct _EFI_IFR_GREATER_THAN { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_GREATER_THAN; + +typedef struct _EFI_IFR_LESS_EQUAL { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_LESS_EQUAL; + +typedef struct _EFI_IFR_LESS_THAN { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_LESS_THAN; + +typedef struct _EFI_IFR_MATCH { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_MATCH; + +typedef struct _EFI_IFR_MULTIPLY { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_MULTIPLY; + +typedef struct _EFI_IFR_MODULO { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_MODULO; + +typedef struct _EFI_IFR_NOT_EQUAL { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_NOT_EQUAL; + +typedef struct _EFI_IFR_OR { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_OR; + +typedef struct _EFI_IFR_SHIFT_LEFT { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_SHIFT_LEFT; + +typedef struct _EFI_IFR_SHIFT_RIGHT { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_SHIFT_RIGHT; + +typedef struct _EFI_IFR_SUBTRACT { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_SUBTRACT; + +typedef struct _EFI_IFR_CONDITIONAL { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_CONDITIONAL; + +#define EFI_IFR_FF_CASE_SENSITIVE 0x00 +#define EFI_IFR_FF_CASE_INSENSITIVE 0x01 + +typedef struct _EFI_IFR_FIND { + EFI_IFR_OP_HEADER Header; + UINT8 Format; +} EFI_IFR_FIND; + +typedef struct _EFI_IFR_MID { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_MID; + +typedef struct _EFI_IFR_TOKEN { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_TOKEN; + +#define EFI_IFR_FLAGS_FIRST_MATCHING 0x00 +#define EFI_IFR_FLAGS_FIRST_NON_MATCHING 0x01 + +typedef struct _EFI_IFR_SPAN { + EFI_IFR_OP_HEADER Header; + UINT8 Flags; +} EFI_IFR_SPAN; + +// +// Keyboard Package +// + +typedef enum { + EfiKeyLCtrl, + EfiKeyA0, + EfiKeyLAlt, + EfiKeySpaceBar, + EfiKeyA2, + EfiKeyA3, + EfiKeyA4, + EfiKeyRCtrl, + EfiKeyLeftArrow, + EfiKeyDownArrow, + EfiKeyRightArrow, + EfiKeyZero, + EfiKeyPeriod, + EfiKeyEnter, + EfiKeyLShift, + EfiKeyB0, + EfiKeyB1, + EfiKeyB2, + EfiKeyB3, + EfiKeyB4, + EfiKeyB5, + EfiKeyB6, + EfiKeyB7, + EfiKeyB8, + EfiKeyB9, + EfiKeyB10, + EfiKeyRShift, + EfiKeyUpArrow, + EfiKeyOne, + EfiKeyTwo, + EfiKeyThree, + EfiKeyCapsLock, + EfiKeyC1, + EfiKeyC2, + EfiKeyC3, + EfiKeyC4, + EfiKeyC5, + EfiKeyC6, + EfiKeyC7, + EfiKeyC8, + EfiKeyC9, + EfiKeyC10, + EfiKeyC11, + EfiKeyC12, + EfiKeyFour, + EfiKeyFive, + EfiKeySix, + EfiKeyPlus, + EfiKeyTab, + EfiKeyD1, + EfiKeyD2, + EfiKeyD3, + EfiKeyD4, + EfiKeyD5, + EfiKeyD6, + EfiKeyD7, + EfiKeyD8, + EfiKeyD9, + EfiKeyD10, + EfiKeyD11, + EfiKeyD12, + EfiKeyD13, + EfiKeyDel, + EfiKeyEnd, + EfiKeyPgDn, + EfiKeySeven, + EfiKeyEight, + EfiKeyNine, + EfiKeyE0, + EfiKeyE1, + EfiKeyE2, + EfiKeyE3, + EfiKeyE4, + EfiKeyE5, + EfiKeyE6, + EfiKeyE7, + EfiKeyE8, + EfiKeyE9, + EfiKeyE10, + EfiKeyE11, + EfiKeyE12, + EfiKeyBackSpace, + EfiKeyIns, + EfiKeyHome, + EfiKeyPgUp, + EfiKeyNLck, + EfiKeySlash, + EfiKeyAsterisk, + EfiKeyMinus, + EfiKeyEsc, + EfiKeyF1, + EfiKeyF2, + EfiKeyF3, + EfiKeyF4, + EfiKeyF5, + EfiKeyF6, + EfiKeyF7, + EfiKeyF8, + EfiKeyF9, + EfiKeyF10, + EfiKeyF11, + EfiKeyF12, + EfiKeyPrint, + EfiKeySLck, + EfiKeyPause +} EFI_KEY; + +typedef struct { + EFI_KEY Key; + CHAR16 Unicode; + CHAR16 ShiftedUnicode; + CHAR16 AltGrUnicode; + CHAR16 ShiftedAltGrUnicode; + UINT16 Modifier; + UINT16 AffectedAttribute; +} EFI_KEY_DESCRIPTOR; + +/// +/// A key which is affected by all the standard shift modifiers. +/// Most keys would be expected to have this bit active. +/// +#define EFI_AFFECTED_BY_STANDARD_SHIFT 0x0001 + +/// +/// This key is affected by the caps lock so that if a keyboard driver +/// would need to disambiguate between a key which had a "1" defined +/// versus a "a" character. Having this bit turned on would tell +/// the keyboard driver to use the appropriate shifted state or not. +/// +#define EFI_AFFECTED_BY_CAPS_LOCK 0x0002 + +/// +/// Similar to the case of CAPS lock, if this bit is active, the key +/// is affected by the num lock being turned on. +/// +#define EFI_AFFECTED_BY_NUM_LOCK 0x0004 + +typedef struct { + UINT16 LayoutLength; + EFI_GUID Guid; + UINT32 LayoutDescriptorStringOffset; + UINT8 DescriptorCount; + // EFI_KEY_DESCRIPTOR Descriptors[]; +} EFI_HII_KEYBOARD_LAYOUT; + +typedef struct { + EFI_HII_PACKAGE_HEADER Header; + UINT16 LayoutCount; + // EFI_HII_KEYBOARD_LAYOUT Layout[]; +} EFI_HII_KEYBOARD_PACKAGE_HDR; + +// +// Modifier values +// +#define EFI_NULL_MODIFIER 0x0000 +#define EFI_LEFT_CONTROL_MODIFIER 0x0001 +#define EFI_RIGHT_CONTROL_MODIFIER 0x0002 +#define EFI_LEFT_ALT_MODIFIER 0x0003 +#define EFI_RIGHT_ALT_MODIFIER 0x0004 +#define EFI_ALT_GR_MODIFIER 0x0005 +#define EFI_INSERT_MODIFIER 0x0006 +#define EFI_DELETE_MODIFIER 0x0007 +#define EFI_PAGE_DOWN_MODIFIER 0x0008 +#define EFI_PAGE_UP_MODIFIER 0x0009 +#define EFI_HOME_MODIFIER 0x000A +#define EFI_END_MODIFIER 0x000B +#define EFI_LEFT_SHIFT_MODIFIER 0x000C +#define EFI_RIGHT_SHIFT_MODIFIER 0x000D +#define EFI_CAPS_LOCK_MODIFIER 0x000E +#define EFI_NUM_LOCK_MODIFIER 0x000F +#define EFI_LEFT_ARROW_MODIFIER 0x0010 +#define EFI_RIGHT_ARROW_MODIFIER 0x0011 +#define EFI_DOWN_ARROW_MODIFIER 0x0012 +#define EFI_UP_ARROW_MODIFIER 0x0013 +#define EFI_NS_KEY_MODIFIER 0x0014 +#define EFI_NS_KEY_DEPENDENCY_MODIFIER 0x0015 +#define EFI_FUNCTION_KEY_ONE_MODIFIER 0x0016 +#define EFI_FUNCTION_KEY_TWO_MODIFIER 0x0017 +#define EFI_FUNCTION_KEY_THREE_MODIFIER 0x0018 +#define EFI_FUNCTION_KEY_FOUR_MODIFIER 0x0019 +#define EFI_FUNCTION_KEY_FIVE_MODIFIER 0x001A +#define EFI_FUNCTION_KEY_SIX_MODIFIER 0x001B +#define EFI_FUNCTION_KEY_SEVEN_MODIFIER 0x001C +#define EFI_FUNCTION_KEY_EIGHT_MODIFIER 0x001D +#define EFI_FUNCTION_KEY_NINE_MODIFIER 0x001E +#define EFI_FUNCTION_KEY_TEN_MODIFIER 0x001F +#define EFI_FUNCTION_KEY_ELEVEN_MODIFIER 0x0020 +#define EFI_FUNCTION_KEY_TWELVE_MODIFIER 0x0021 + +// +// Keys that have multiple control functions based on modifier +// settings are handled in the keyboard driver implementation. +// For instance PRINT_KEY might have a modifier held down and +// is still a nonprinting character, but might have an alternate +// control function like SYSREQUEST +// +#define EFI_PRINT_MODIFIER 0x0022 +#define EFI_SYS_REQUEST_MODIFIER 0x0023 +#define EFI_SCROLL_LOCK_MODIFIER 0x0024 +#define EFI_PAUSE_MODIFIER 0x0025 +#define EFI_BREAK_MODIFIER 0x0026 + +#define EFI_LEFT_LOGO_MODIFIER 0x0027 +#define EFI_RIGHT_LOGO_MODIFIER 0x0028 +#define EFI_MENU_MODIFIER 0x0029 + +#pragma pack() + + + +/// +/// References to string tokens must use this macro to enable scanning for +/// token usages. +/// +/// +/// STRING_TOKEN is not defined in UEFI specification. But it is placed +/// here for the easy access by C files and VFR source files. +/// +#define STRING_TOKEN(t) t + +#endif diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiMultiPhase.h b/gpxe/src/include/gpxe/efi/Uefi/UefiMultiPhase.h new file mode 100644 index 00000000..c72697a6 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Uefi/UefiMultiPhase.h @@ -0,0 +1,218 @@ +/** @file + This includes some definitions introduced in UEFI that will be used in both PEI and DXE phases. + + Copyright (c) 2006, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __UEFI_MULTIPHASE_H__ +#define __UEFI_MULTIPHASE_H__ + +#include + +/// +/// Enumeration of memory types introduced in UEFI. +/// +typedef enum { + EfiReservedMemoryType, + EfiLoaderCode, + EfiLoaderData, + EfiBootServicesCode, + EfiBootServicesData, + EfiRuntimeServicesCode, + EfiRuntimeServicesData, + EfiConventionalMemory, + EfiUnusableMemory, + EfiACPIReclaimMemory, + EfiACPIMemoryNVS, + EfiMemoryMappedIO, + EfiMemoryMappedIOPortSpace, + EfiPalCode, + EfiMaxMemoryType +} EFI_MEMORY_TYPE; + + +/// +/// Data structure that precedes all of the standard EFI table types. +/// +typedef struct { + UINT64 Signature; + UINT32 Revision; + UINT32 HeaderSize; + UINT32 CRC32; + UINT32 Reserved; +} EFI_TABLE_HEADER; + +/// +/// Attributes of variable. +/// +#define EFI_VARIABLE_NON_VOLATILE 0x00000001 +#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 +#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 +#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x00000008 + +/// +/// This attribute is identified by the mnemonic 'HR' +/// elsewhere in this specification. +/// +#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010 + +// +// _WIN_CERTIFICATE.wCertificateType +// +#define WIN_CERT_TYPE_EFI_PKCS115 0x0EF0 +#define WIN_CERT_TYPE_EFI_GUID 0x0EF1 + +/** + + The WIN_CERTIFICATE structure is part of the PE/COFF + specification and has the following definition: + + @param dwLength The length of the entire certificate, + including the length of the header, in + bytes. + + @param wRevision The revision level of the WIN_CERTIFICATE + structure. The current revision level is + 0x0200. + + @param wCertificateType The certificate type. See + WIN_CERT_TYPE_xxx for the UEFI + certificate types. The UEFI + specification reserves the range of + certificate type values from 0x0EF0 + to 0x0EFF. + + @param bCertificate The actual certificate. The format of + the certificate depends on + wCertificateType. The format of the UEFI + certificates is defined below. + + +**/ +typedef struct _WIN_CERTIFICATE { + UINT32 dwLength; + UINT16 wRevision; + UINT16 wCertificateType; + //UINT8 bCertificate[ANYSIZE_ARRAY]; +} WIN_CERTIFICATE; + +/// +/// WIN_CERTIFICATE_UEFI_GUID.CertType +/// +#define EFI_CERT_TYPE_RSA2048_SHA256_GUID \ + {0xa7717414, 0xc616, 0x4977, {0x94, 0x20, 0x84, 0x47, 0x12, 0xa7, 0x35, 0xbf } } + +/// +/// WIN_CERTIFICATE_UEFI_GUID.CertData +/// +typedef struct _EFI_CERT_BLOCK_RSA_2048_SHA256 { + UINT32 HashType; + UINT8 PublicKey[256]; + UINT8 Signature[256]; +} EFI_CERT_BLOCK_RSA_2048_SHA256; + + +/** + + @param Hdr This is the standard WIN_CERTIFICATE header, where + wCertificateType is set to + WIN_CERT_TYPE_UEFI_GUID. + + @param CertType This is the unique id which determines the + format of the CertData. In this case, the + value is EFI_CERT_TYPE_RSA2048_SHA256_GUID. + + @param CertData This is the certificate data. The format of + the data is determined by the CertType. In + this case the value is + EFI_CERT_BLOCK_RSA_2048_SHA256. + +**/ +typedef struct _WIN_CERTIFICATE_UEFI_GUID { + WIN_CERTIFICATE Hdr; + EFI_GUID CertType; + // UINT8 CertData[ANYSIZE_ARRAY]; +} WIN_CERTIFICATE_UEFI_GUID; + + +/** + + Certificate which encapsulates the RSASSA_PKCS1-v1_5 digital + signature. + + The WIN_CERTIFICATE_UEFI_PKCS1_15 structure is derived from + WIN_CERTIFICATE and encapsulate the information needed to + implement the RSASSA-PKCS1-v1_5 digital signature algorithm as + specified in RFC2437. + + @param Hdr This is the standard WIN_CERTIFICATE header, where + wCertificateType is set to + WIN_CERT_TYPE_UEFI_PKCS1_15. + + @param HashAlgorithm This is the hashing algorithm which was + performed on the UEFI executable when + creating the digital signature. It is + one of the enumerated values pre-defined + in Section 26.4.1. See + EFI_HASH_ALGORITHM_x. + + @param Signature This is the actual digital signature. The + size of the signature is the same size as + the key (1024-bit key is 128 bytes) and can + be determined by subtracting the length of + the other parts of this header from the + total length of the certificate as found in + Hdr.dwLength. + +**/ +typedef struct _WIN_CERTIFICATE_EFI_PKCS1_15 { + WIN_CERTIFICATE Hdr; + EFI_GUID HashAlgorithm; + // UINT8 Signature[ANYSIZE_ARRAY]; +} WIN_CERTIFICATE_EFI_PKCS1_15; + + +/** + + AuthInfo is a WIN_CERTIFICATE using the wCertificateType + WIN_CERTIFICATE_UEFI_GUID and the CertType + EFI_CERT_TYPE_RSA2048_SHA256. If the attribute specifies + authenticated access, then the Data buffer should begin with an + authentication descriptor prior to the data payload and DataSize + should reflect the the data.and descriptor size. The caller + shall digest the Monotonic Count value and the associated data + for the variable update using the SHA-256 1-way hash algorithm. + The ensuing the 32-byte digest will be signed using the private + key associated w/ the public/private 2048-bit RSA key-pair. The + WIN_CERTIFICATE shall be used to describe the signature of the + Variable data *Data. In addition, the signature will also + include the MonotonicCount value to guard against replay attacks + + @param MonotonicCount Included in the signature of + AuthInfo.Used to ensure freshness/no + replay. Incremented during each + "Write" access. + + @param AuthInfo Provides the authorization for the variable + access. It is a signature across the + variable data and the Monotonic Count + value. Caller uses Private key that is + associated with a public key that has been + provisioned via the key exchange. + +**/ +typedef struct { + UINT64 MonotonicCount; + WIN_CERTIFICATE_UEFI_GUID AuthInfo; +} EFI_VARIABLE_AUTHENTICATION; + +#endif + diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiPxe.h b/gpxe/src/include/gpxe/efi/Uefi/UefiPxe.h new file mode 100644 index 00000000..bdc834fc --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Uefi/UefiPxe.h @@ -0,0 +1,1811 @@ +/** @file + This header file contains all of the PXE type definitions, + structure prototypes, global variables and constants that + are needed for porting PXE to EFI. + + Copyright (c) 2006, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + 32/64-bit PXE specification: + alpha-4, 99-Dec-17 + +**/ + +#ifndef __EFI_PXE_H__ +#define __EFI_PXE_H__ + +#pragma pack(1) + + + +#define PXE_BUSTYPE(a, b, c, d) \ + ( \ + (((PXE_UINT32) (d) & 0xFF) << 24) | (((PXE_UINT32) (c) & 0xFF) << 16) | (((PXE_UINT32) (b) & 0xFF) << 8) | \ + ((PXE_UINT32) (a) & 0xFF) \ + ) + +/// +/// UNDI ROM ID and devive ID signature +/// +#define PXE_BUSTYPE_PXE PXE_BUSTYPE ('!', 'P', 'X', 'E') + +/// +/// BUS ROM ID signatures +/// +#define PXE_BUSTYPE_PCI PXE_BUSTYPE ('P', 'C', 'I', 'R') +#define PXE_BUSTYPE_PC_CARD PXE_BUSTYPE ('P', 'C', 'C', 'R') +#define PXE_BUSTYPE_USB PXE_BUSTYPE ('U', 'S', 'B', 'R') +#define PXE_BUSTYPE_1394 PXE_BUSTYPE ('1', '3', '9', '4') + +#define PXE_SWAP_UINT16(n) ((((PXE_UINT16) (n) & 0x00FF) << 8) | (((PXE_UINT16) (n) & 0xFF00) >> 8)) + +#define PXE_SWAP_UINT32(n) \ + ((((PXE_UINT32)(n) & 0x000000FF) << 24) | \ + (((PXE_UINT32)(n) & 0x0000FF00) << 8) | \ + (((PXE_UINT32)(n) & 0x00FF0000) >> 8) | \ + (((PXE_UINT32)(n) & 0xFF000000) >> 24)) + +#define PXE_SWAP_UINT64(n) \ + ((((PXE_UINT64)(n) & 0x00000000000000FFULL) << 56) | \ + (((PXE_UINT64)(n) & 0x000000000000FF00ULL) << 40) | \ + (((PXE_UINT64)(n) & 0x0000000000FF0000ULL) << 24) | \ + (((PXE_UINT64)(n) & 0x00000000FF000000ULL) << 8) | \ + (((PXE_UINT64)(n) & 0x000000FF00000000ULL) >> 8) | \ + (((PXE_UINT64)(n) & 0x0000FF0000000000ULL) >> 24) | \ + (((PXE_UINT64)(n) & 0x00FF000000000000ULL) >> 40) | \ + (((PXE_UINT64)(n) & 0xFF00000000000000ULL) >> 56)) + + +#define PXE_CPBSIZE_NOT_USED 0 // zero +#define PXE_DBSIZE_NOT_USED 0 // zero +#define PXE_CPBADDR_NOT_USED (PXE_UINT64) 0 // zero +#define PXE_DBADDR_NOT_USED (PXE_UINT64) 0 // zero +#define PXE_CONST const + +#define PXE_VOLATILE volatile + +typedef VOID PXE_VOID; +typedef UINT8 PXE_UINT8; +typedef UINT16 PXE_UINT16; +typedef UINT32 PXE_UINT32; +typedef UINTN PXE_UINTN; + +/// +/// typedef unsigned long PXE_UINT64; +/// +typedef UINT64 PXE_UINT64; + +typedef PXE_UINT8 PXE_BOOL; +#define PXE_FALSE 0 // zero +#define PXE_TRUE (!PXE_FALSE) + +typedef PXE_UINT16 PXE_OPCODE; + +/// +/// Return UNDI operational state. +/// +#define PXE_OPCODE_GET_STATE 0x0000 + +/// +/// Change UNDI operational state from Stopped to Started. +/// +#define PXE_OPCODE_START 0x0001 + +/// +/// Change UNDI operational state from Started to Stopped. +/// +#define PXE_OPCODE_STOP 0x0002 + +/// +/// Get UNDI initialization information. +/// +#define PXE_OPCODE_GET_INIT_INFO 0x0003 + +/// +/// Get NIC configuration information. +/// +#define PXE_OPCODE_GET_CONFIG_INFO 0x0004 + +/// +/// Changed UNDI operational state from Started to Initialized. +/// +#define PXE_OPCODE_INITIALIZE 0x0005 + +/// +/// Re-initialize the NIC H/W. +/// +#define PXE_OPCODE_RESET 0x0006 + +/// +/// Change the UNDI operational state from Initialized to Started. +/// +#define PXE_OPCODE_SHUTDOWN 0x0007 + +/// +/// Read & change state of external interrupt enables. +/// +#define PXE_OPCODE_INTERRUPT_ENABLES 0x0008 + +/// +/// Read & change state of packet receive filters. +/// +#define PXE_OPCODE_RECEIVE_FILTERS 0x0009 + +/// +/// Read & change station MAC address. +/// +#define PXE_OPCODE_STATION_ADDRESS 0x000A + +/// +/// Read traffic statistics. +/// +#define PXE_OPCODE_STATISTICS 0x000B + +/// +/// Convert multicast IP address to multicast MAC address. +/// +#define PXE_OPCODE_MCAST_IP_TO_MAC 0x000C + +/// +/// Read or change non-volatile storage on the NIC. +/// +#define PXE_OPCODE_NVDATA 0x000D + +/// +/// Get & clear interrupt status. +/// +#define PXE_OPCODE_GET_STATUS 0x000E + +/// +/// Fill media header in packet for transmit. +/// +#define PXE_OPCODE_FILL_HEADER 0x000F + +/// +/// Transmit packet(s). +/// +#define PXE_OPCODE_TRANSMIT 0x0010 + +/// +/// Receive packet. +/// +#define PXE_OPCODE_RECEIVE 0x0011 + +/// +/// Last valid PXE UNDI OpCode number. +/// +#define PXE_OPCODE_LAST_VALID 0x0011 + +typedef PXE_UINT16 PXE_OPFLAGS; + +#define PXE_OPFLAGS_NOT_USED 0x0000 + +// +// ////////////////////////////////////// +// UNDI Get State +// +// No OpFlags + +//////////////////////////////////////// +// UNDI Start +// +// No OpFlags + +//////////////////////////////////////// +// UNDI Stop +// +// No OpFlags + +//////////////////////////////////////// +// UNDI Get Init Info +// +// No Opflags + +//////////////////////////////////////// +// UNDI Get Config Info +// +// No Opflags + +//////////////////////////////////////// +// UNDI Initialize +// +#define PXE_OPFLAGS_INITIALIZE_CABLE_DETECT_MASK 0x0001 +#define PXE_OPFLAGS_INITIALIZE_DETECT_CABLE 0x0000 +#define PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE 0x0001 + +// +// ////////////////////////////////////// +// UNDI Reset +// +#define PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS 0x0001 +#define PXE_OPFLAGS_RESET_DISABLE_FILTERS 0x0002 + +// +// ////////////////////////////////////// +// UNDI Shutdown +// +// No OpFlags + +//////////////////////////////////////// +// UNDI Interrupt Enables +// +// +// Select whether to enable or disable external interrupt signals. +// Setting both enable and disable will return PXE_STATCODE_INVALID_OPFLAGS. +// +#define PXE_OPFLAGS_INTERRUPT_OPMASK 0xC000 +#define PXE_OPFLAGS_INTERRUPT_ENABLE 0x8000 +#define PXE_OPFLAGS_INTERRUPT_DISABLE 0x4000 +#define PXE_OPFLAGS_INTERRUPT_READ 0x0000 + +/// +/// Enable receive interrupts. An external interrupt will be generated +/// after a complete non-error packet has been received. +/// +#define PXE_OPFLAGS_INTERRUPT_RECEIVE 0x0001 + +/// +/// Enable transmit interrupts. An external interrupt will be generated +/// after a complete non-error packet has been transmitted. +/// +#define PXE_OPFLAGS_INTERRUPT_TRANSMIT 0x0002 + +/// +/// Enable command interrupts. An external interrupt will be generated +/// when command execution stops. +/// +#define PXE_OPFLAGS_INTERRUPT_COMMAND 0x0004 + +/// +/// Generate software interrupt. Setting this bit generates an external +/// interrupt, if it is supported by the hardware. +/// +#define PXE_OPFLAGS_INTERRUPT_SOFTWARE 0x0008 + +// +// ////////////////////////////////////// +// UNDI Receive Filters +// +// +// Select whether to enable or disable receive filters. +// Setting both enable and disable will return PXE_STATCODE_INVALID_OPCODE. +// +#define PXE_OPFLAGS_RECEIVE_FILTER_OPMASK 0xC000 +#define PXE_OPFLAGS_RECEIVE_FILTER_ENABLE 0x8000 +#define PXE_OPFLAGS_RECEIVE_FILTER_DISABLE 0x4000 +#define PXE_OPFLAGS_RECEIVE_FILTER_READ 0x0000 + +/// +/// To reset the contents of the multicast MAC address filter list, +/// set this OpFlag: +/// +#define PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST 0x2000 + +/// +/// Enable unicast packet receiving. Packets sent to the current station +/// MAC address will be received. +/// +#define PXE_OPFLAGS_RECEIVE_FILTER_UNICAST 0x0001 + +/// +/// Enable broadcast packet receiving. Packets sent to the broadcast +/// MAC address will be received. +/// +#define PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST 0x0002 + +/// +/// Enable filtered multicast packet receiving. Packets sent to any +/// of the multicast MAC addresses in the multicast MAC address filter +/// list will be received. If the filter list is empty, no multicast +/// +#define PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST 0x0004 + +/// +/// Enable promiscuous packet receiving. All packets will be received. +/// +#define PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS 0x0008 + +/// +/// Enable promiscuous multicast packet receiving. All multicast +/// packets will be received. +/// +#define PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST 0x0010 + +// +// ////////////////////////////////////// +// UNDI Station Address +// +#define PXE_OPFLAGS_STATION_ADDRESS_READ 0x0000 +#define PXE_OPFLAGS_STATION_ADDRESS_WRITE 0x0000 +#define PXE_OPFLAGS_STATION_ADDRESS_RESET 0x0001 + +// +// ////////////////////////////////////// +// UNDI Statistics +// +#define PXE_OPFLAGS_STATISTICS_READ 0x0000 +#define PXE_OPFLAGS_STATISTICS_RESET 0x0001 + +// +// ////////////////////////////////////// +// UNDI MCast IP to MAC +// +// +// Identify the type of IP address in the CPB. +// +#define PXE_OPFLAGS_MCAST_IP_TO_MAC_OPMASK 0x0003 +#define PXE_OPFLAGS_MCAST_IPV4_TO_MAC 0x0000 +#define PXE_OPFLAGS_MCAST_IPV6_TO_MAC 0x0001 + +// +// ////////////////////////////////////// +// UNDI NvData +// +// +// Select the type of non-volatile data operation. +// +#define PXE_OPFLAGS_NVDATA_OPMASK 0x0001 +#define PXE_OPFLAGS_NVDATA_READ 0x0000 +#define PXE_OPFLAGS_NVDATA_WRITE 0x0001 + +// +// ////////////////////////////////////// +// UNDI Get Status +// +// +// Return current interrupt status. This will also clear any interrupts +// that are currently set. This can be used in a polling routine. The +// interrupt flags are still set and cleared even when the interrupts +// are disabled. +// +#define PXE_OPFLAGS_GET_INTERRUPT_STATUS 0x0001 + +// +// Return list of transmitted buffers for recycling. Transmit buffers +// must not be changed or unallocated until they have recycled. After +// issuing a transmit command, wait for a transmit complete interrupt. +// When a transmit complete interrupt is received, read the transmitted +// buffers. Do not plan on getting one buffer per interrupt. Some +// NICs and UNDIs may transmit multiple buffers per interrupt. +// +#define PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS 0x0002 + +// +// ////////////////////////////////////// +// UNDI Fill Header +// +#define PXE_OPFLAGS_FILL_HEADER_OPMASK 0x0001 +#define PXE_OPFLAGS_FILL_HEADER_FRAGMENTED 0x0001 +#define PXE_OPFLAGS_FILL_HEADER_WHOLE 0x0000 + +// +// ////////////////////////////////////// +// UNDI Transmit +// +// +// S/W UNDI only. Return after the packet has been transmitted. A +// transmit complete interrupt will still be generated and the transmit +// buffer will have to be recycled. +// +#define PXE_OPFLAGS_SWUNDI_TRANSMIT_OPMASK 0x0001 +#define PXE_OPFLAGS_TRANSMIT_BLOCK 0x0001 +#define PXE_OPFLAGS_TRANSMIT_DONT_BLOCK 0x0000 + +// +// +// +#define PXE_OPFLAGS_TRANSMIT_OPMASK 0x0002 +#define PXE_OPFLAGS_TRANSMIT_FRAGMENTED 0x0002 +#define PXE_OPFLAGS_TRANSMIT_WHOLE 0x0000 + +// +// ////////////////////////////////////// +// UNDI Receive +// +// No OpFlags +// +typedef PXE_UINT16 PXE_STATFLAGS; + +#define PXE_STATFLAGS_INITIALIZE 0x0000 + +// +// ////////////////////////////////////// +// Common StatFlags that can be returned by all commands. +// +// +// The COMMAND_COMPLETE and COMMAND_FAILED status flags must be +// implemented by all UNDIs. COMMAND_QUEUED is only needed by UNDIs +// that support command queuing. +// +#define PXE_STATFLAGS_STATUS_MASK 0xC000 +#define PXE_STATFLAGS_COMMAND_COMPLETE 0xC000 +#define PXE_STATFLAGS_COMMAND_FAILED 0x8000 +#define PXE_STATFLAGS_COMMAND_QUEUED 0x4000 + +// +// ////////////////////////////////////// +// UNDI Get State +// +#define PXE_STATFLAGS_GET_STATE_MASK 0x0003 +#define PXE_STATFLAGS_GET_STATE_INITIALIZED 0x0002 +#define PXE_STATFLAGS_GET_STATE_STARTED 0x0001 +#define PXE_STATFLAGS_GET_STATE_STOPPED 0x0000 + +// +// ////////////////////////////////////// +// UNDI Start +// +// No additional StatFlags + +//////////////////////////////////////// +// UNDI Get Init Info +// +#define PXE_STATFLAGS_CABLE_DETECT_MASK 0x0001 +#define PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED 0x0000 +#define PXE_STATFLAGS_CABLE_DETECT_SUPPORTED 0x0001 + +// +// ////////////////////////////////////// +// UNDI Initialize +// +#define PXE_STATFLAGS_INITIALIZED_NO_MEDIA 0x0001 + +// +// ////////////////////////////////////// +// UNDI Reset +// +#define PXE_STATFLAGS_RESET_NO_MEDIA 0x0001 + +// +// ////////////////////////////////////// +// UNDI Shutdown +// +// No additional StatFlags + +//////////////////////////////////////// +// UNDI Interrupt Enables +// +// +// If set, receive interrupts are enabled. +// +#define PXE_STATFLAGS_INTERRUPT_RECEIVE 0x0001 + +// +// If set, transmit interrupts are enabled. +// +#define PXE_STATFLAGS_INTERRUPT_TRANSMIT 0x0002 + +// +// If set, command interrupts are enabled. +// +#define PXE_STATFLAGS_INTERRUPT_COMMAND 0x0004 + +// +// ////////////////////////////////////// +// UNDI Receive Filters +// +// +// If set, unicast packets will be received. +// +#define PXE_STATFLAGS_RECEIVE_FILTER_UNICAST 0x0001 + +// +// If set, broadcast packets will be received. +// +#define PXE_STATFLAGS_RECEIVE_FILTER_BROADCAST 0x0002 + +// +// If set, multicast packets that match up with the multicast address +// filter list will be received. +// +#define PXE_STATFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST 0x0004 + +// +// If set, all packets will be received. +// +#define PXE_STATFLAGS_RECEIVE_FILTER_PROMISCUOUS 0x0008 + +// +// If set, all multicast packets will be received. +// +#define PXE_STATFLAGS_RECEIVE_FILTER_ALL_MULTICAST 0x0010 + +// +// ////////////////////////////////////// +// UNDI Station Address +// +// No additional StatFlags + +//////////////////////////////////////// +// UNDI Statistics +// +// No additional StatFlags + +//////////////////////////////////////// +// UNDI MCast IP to MAC +// +// No additional StatFlags + +//////////////////////////////////////// +// UNDI NvData +// +// No additional StatFlags + + +//////////////////////////////////////// +// UNDI Get Status +// +// +// Use to determine if an interrupt has occurred. +// +#define PXE_STATFLAGS_GET_STATUS_INTERRUPT_MASK 0x000F +#define PXE_STATFLAGS_GET_STATUS_NO_INTERRUPTS 0x0000 + +// +// If set, at least one receive interrupt occurred. +// +#define PXE_STATFLAGS_GET_STATUS_RECEIVE 0x0001 + +// +// If set, at least one transmit interrupt occurred. +// +#define PXE_STATFLAGS_GET_STATUS_TRANSMIT 0x0002 + +// +// If set, at least one command interrupt occurred. +// +#define PXE_STATFLAGS_GET_STATUS_COMMAND 0x0004 + +// +// If set, at least one software interrupt occurred. +// +#define PXE_STATFLAGS_GET_STATUS_SOFTWARE 0x0008 + +// +// This flag is set if the transmitted buffer queue is empty. This flag +// will be set if all transmitted buffer addresses get written into the DB. +// +#define PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY 0x0010 + +// +// This flag is set if no transmitted buffer addresses were written +// into the DB. (This could be because DBsize was too small.) +// +#define PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN 0x0020 + +// +// ////////////////////////////////////// +// UNDI Fill Header +// +// No additional StatFlags + +//////////////////////////////////////// +// UNDI Transmit +// +// No additional StatFlags. + +//////////////////////////////////////// +// UNDI Receive +// +// No additional StatFlags. +// +typedef PXE_UINT16 PXE_STATCODE; + +#define PXE_STATCODE_INITIALIZE 0x0000 + +// +// ////////////////////////////////////// +// Common StatCodes returned by all UNDI commands, UNDI protocol functions +// and BC protocol functions. +// +#define PXE_STATCODE_SUCCESS 0x0000 + +#define PXE_STATCODE_INVALID_CDB 0x0001 +#define PXE_STATCODE_INVALID_CPB 0x0002 +#define PXE_STATCODE_BUSY 0x0003 +#define PXE_STATCODE_QUEUE_FULL 0x0004 +#define PXE_STATCODE_ALREADY_STARTED 0x0005 +#define PXE_STATCODE_NOT_STARTED 0x0006 +#define PXE_STATCODE_NOT_SHUTDOWN 0x0007 +#define PXE_STATCODE_ALREADY_INITIALIZED 0x0008 +#define PXE_STATCODE_NOT_INITIALIZED 0x0009 +#define PXE_STATCODE_DEVICE_FAILURE 0x000A +#define PXE_STATCODE_NVDATA_FAILURE 0x000B +#define PXE_STATCODE_UNSUPPORTED 0x000C +#define PXE_STATCODE_BUFFER_FULL 0x000D +#define PXE_STATCODE_INVALID_PARAMETER 0x000E +#define PXE_STATCODE_INVALID_UNDI 0x000F +#define PXE_STATCODE_IPV4_NOT_SUPPORTED 0x0010 +#define PXE_STATCODE_IPV6_NOT_SUPPORTED 0x0011 +#define PXE_STATCODE_NOT_ENOUGH_MEMORY 0x0012 +#define PXE_STATCODE_NO_DATA 0x0013 + +typedef PXE_UINT16 PXE_IFNUM; + +// +// This interface number must be passed to the S/W UNDI Start command. +// +#define PXE_IFNUM_START 0x0000 + +// +// This interface number is returned by the S/W UNDI Get State and +// Start commands if information in the CDB, CPB or DB is invalid. +// +#define PXE_IFNUM_INVALID 0x0000 + +typedef PXE_UINT16 PXE_CONTROL; + +// +// Setting this flag directs the UNDI to queue this command for later +// execution if the UNDI is busy and it supports command queuing. +// If queuing is not supported, a PXE_STATCODE_INVALID_CONTROL error +// is returned. If the queue is full, a PXE_STATCODE_CDB_QUEUE_FULL +// error is returned. +// +#define PXE_CONTROL_QUEUE_IF_BUSY 0x0002 + +// +// These two bit values are used to determine if there are more UNDI +// CDB structures following this one. If the link bit is set, there +// must be a CDB structure following this one. Execution will start +// on the next CDB structure as soon as this one completes successfully. +// If an error is generated by this command, execution will stop. +// +#define PXE_CONTROL_LINK 0x0001 +#define PXE_CONTROL_LAST_CDB_IN_LIST 0x0000 + +typedef PXE_UINT8 PXE_FRAME_TYPE; + +#define PXE_FRAME_TYPE_NONE 0x00 +#define PXE_FRAME_TYPE_UNICAST 0x01 +#define PXE_FRAME_TYPE_BROADCAST 0x02 +#define PXE_FRAME_TYPE_FILTERED_MULTICAST 0x03 +#define PXE_FRAME_TYPE_PROMISCUOUS 0x04 +#define PXE_FRAME_TYPE_PROMISCUOUS_MULTICAST 0x05 + +#define PXE_FRAME_TYPE_MULTICAST PXE_FRAME_TYPE_FILTERED_MULTICAST + +typedef PXE_UINT32 PXE_IPV4; + +typedef PXE_UINT32 PXE_IPV6[4]; +#define PXE_MAC_LENGTH 32 + +typedef PXE_UINT8 PXE_MAC_ADDR[PXE_MAC_LENGTH]; + +typedef PXE_UINT8 PXE_IFTYPE; +typedef UINT16 PXE_MEDIA_PROTOCOL; + +// +// This information is from the ARP section of RFC 1700. +// +// 1 Ethernet (10Mb) [JBP] +// 2 Experimental Ethernet (3Mb) [JBP] +// 3 Amateur Radio AX.25 [PXK] +// 4 Proteon ProNET Token Ring [JBP] +// 5 Chaos [GXP] +// 6 IEEE 802 Networks [JBP] +// 7 ARCNET [JBP] +// 8 Hyperchannel [JBP] +// 9 Lanstar [TU] +// 10 Autonet Short Address [MXB1] +// 11 LocalTalk [JKR1] +// 12 LocalNet (IBM* PCNet or SYTEK* LocalNET) [JXM] +// 13 Ultra link [RXD2] +// 14 SMDS [GXC1] +// 15 Frame Relay [AGM] +// 16 Asynchronous Transmission Mode (ATM) [JXB2] +// 17 HDLC [JBP] +// 18 Fibre Channel [Yakov Rekhter] +// 19 Asynchronous Transmission Mode (ATM) [Mark Laubach] +// 20 Serial Line [JBP] +// 21 Asynchronous Transmission Mode (ATM) [MXB1] +// +// * Other names and brands may be claimed as the property of others. +// +#define PXE_IFTYPE_ETHERNET 0x01 +#define PXE_IFTYPE_TOKENRING 0x04 +#define PXE_IFTYPE_FIBRE_CHANNEL 0x12 + +typedef struct s_pxe_hw_undi { + PXE_UINT32 Signature; // PXE_ROMID_SIGNATURE + PXE_UINT8 Len; // sizeof(PXE_HW_UNDI) + PXE_UINT8 Fudge; // makes 8-bit cksum equal zero + PXE_UINT8 Rev; // PXE_ROMID_REV + PXE_UINT8 IFcnt; // physical connector count + PXE_UINT8 MajorVer; // PXE_ROMID_MAJORVER + PXE_UINT8 MinorVer; // PXE_ROMID_MINORVER + PXE_UINT16 reserved; // zero, not used + PXE_UINT32 Implementation; // implementation flags + // reserved // vendor use + // UINT32 Status; // status port + // UINT32 Command; // command port + // UINT64 CDBaddr; // CDB address port + // +} PXE_HW_UNDI; + +// +// Status port bit definitions +// +// +// UNDI operation state +// +#define PXE_HWSTAT_STATE_MASK 0xC0000000 +#define PXE_HWSTAT_BUSY 0xC0000000 +#define PXE_HWSTAT_INITIALIZED 0x80000000 +#define PXE_HWSTAT_STARTED 0x40000000 +#define PXE_HWSTAT_STOPPED 0x00000000 + +// +// If set, last command failed +// +#define PXE_HWSTAT_COMMAND_FAILED 0x20000000 + +// +// If set, identifies enabled receive filters +// +#define PXE_HWSTAT_PROMISCUOUS_MULTICAST_RX_ENABLED 0x00001000 +#define PXE_HWSTAT_PROMISCUOUS_RX_ENABLED 0x00000800 +#define PXE_HWSTAT_BROADCAST_RX_ENABLED 0x00000400 +#define PXE_HWSTAT_MULTICAST_RX_ENABLED 0x00000200 +#define PXE_HWSTAT_UNICAST_RX_ENABLED 0x00000100 + +// +// If set, identifies enabled external interrupts +// +#define PXE_HWSTAT_SOFTWARE_INT_ENABLED 0x00000080 +#define PXE_HWSTAT_TX_COMPLETE_INT_ENABLED 0x00000040 +#define PXE_HWSTAT_PACKET_RX_INT_ENABLED 0x00000020 +#define PXE_HWSTAT_CMD_COMPLETE_INT_ENABLED 0x00000010 + +// +// If set, identifies pending interrupts +// +#define PXE_HWSTAT_SOFTWARE_INT_PENDING 0x00000008 +#define PXE_HWSTAT_TX_COMPLETE_INT_PENDING 0x00000004 +#define PXE_HWSTAT_PACKET_RX_INT_PENDING 0x00000002 +#define PXE_HWSTAT_CMD_COMPLETE_INT_PENDING 0x00000001 + +// +// Command port definitions +// +// +// If set, CDB identified in CDBaddr port is given to UNDI. +// If not set, other bits in this word will be processed. +// +#define PXE_HWCMD_ISSUE_COMMAND 0x80000000 +#define PXE_HWCMD_INTS_AND_FILTS 0x00000000 + +// +// Use these to enable/disable receive filters. +// +#define PXE_HWCMD_PROMISCUOUS_MULTICAST_RX_ENABLE 0x00001000 +#define PXE_HWCMD_PROMISCUOUS_RX_ENABLE 0x00000800 +#define PXE_HWCMD_BROADCAST_RX_ENABLE 0x00000400 +#define PXE_HWCMD_MULTICAST_RX_ENABLE 0x00000200 +#define PXE_HWCMD_UNICAST_RX_ENABLE 0x00000100 + +// +// Use these to enable/disable external interrupts +// +#define PXE_HWCMD_SOFTWARE_INT_ENABLE 0x00000080 +#define PXE_HWCMD_TX_COMPLETE_INT_ENABLE 0x00000040 +#define PXE_HWCMD_PACKET_RX_INT_ENABLE 0x00000020 +#define PXE_HWCMD_CMD_COMPLETE_INT_ENABLE 0x00000010 + +// +// Use these to clear pending external interrupts +// +#define PXE_HWCMD_CLEAR_SOFTWARE_INT 0x00000008 +#define PXE_HWCMD_CLEAR_TX_COMPLETE_INT 0x00000004 +#define PXE_HWCMD_CLEAR_PACKET_RX_INT 0x00000002 +#define PXE_HWCMD_CLEAR_CMD_COMPLETE_INT 0x00000001 + +typedef struct s_pxe_sw_undi { + PXE_UINT32 Signature; // PXE_ROMID_SIGNATURE + PXE_UINT8 Len; // sizeof(PXE_SW_UNDI) + PXE_UINT8 Fudge; // makes 8-bit cksum zero + PXE_UINT8 Rev; // PXE_ROMID_REV + PXE_UINT8 IFcnt; // physical connector count + PXE_UINT8 MajorVer; // PXE_ROMID_MAJORVER + PXE_UINT8 MinorVer; // PXE_ROMID_MINORVER + PXE_UINT16 reserved1; // zero, not used + PXE_UINT32 Implementation; // Implementation flags + PXE_UINT64 EntryPoint; // API entry point + PXE_UINT8 reserved2[3]; // zero, not used + PXE_UINT8 BusCnt; // number of bustypes supported + PXE_UINT32 BusType[1]; // list of supported bustypes +} PXE_SW_UNDI; + +typedef union u_pxe_undi { + PXE_HW_UNDI hw; + PXE_SW_UNDI sw; +} PXE_UNDI; + +// +// Signature of !PXE structure +// +#define PXE_ROMID_SIGNATURE PXE_BUSTYPE ('!', 'P', 'X', 'E') + +// +// !PXE structure format revision +// +#define PXE_ROMID_REV 0x02 + +// +// UNDI command interface revision. These are the values that get sent +// in option 94 (Client Network Interface Identifier) in the DHCP Discover +// and PXE Boot Server Request packets. +// +#define PXE_ROMID_MAJORVER 0x03 +#define PXE_ROMID_MINORVER 0x01 + +// +// Implementation flags +// +#define PXE_ROMID_IMP_HW_UNDI 0x80000000 +#define PXE_ROMID_IMP_SW_VIRT_ADDR 0x40000000 +#define PXE_ROMID_IMP_64BIT_DEVICE 0x00010000 +#define PXE_ROMID_IMP_FRAG_SUPPORTED 0x00008000 +#define PXE_ROMID_IMP_CMD_LINK_SUPPORTED 0x00004000 +#define PXE_ROMID_IMP_CMD_QUEUE_SUPPORTED 0x00002000 +#define PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED 0x00001000 +#define PXE_ROMID_IMP_NVDATA_SUPPORT_MASK 0x00000C00 +#define PXE_ROMID_IMP_NVDATA_BULK_WRITABLE 0x00000C00 +#define PXE_ROMID_IMP_NVDATA_SPARSE_WRITABLE 0x00000800 +#define PXE_ROMID_IMP_NVDATA_READ_ONLY 0x00000400 +#define PXE_ROMID_IMP_NVDATA_NOT_AVAILABLE 0x00000000 +#define PXE_ROMID_IMP_STATISTICS_SUPPORTED 0x00000200 +#define PXE_ROMID_IMP_STATION_ADDR_SETTABLE 0x00000100 +#define PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED 0x00000080 +#define PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED 0x00000040 +#define PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED 0x00000020 +#define PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED 0x00000010 +#define PXE_ROMID_IMP_SOFTWARE_INT_SUPPORTED 0x00000008 +#define PXE_ROMID_IMP_TX_COMPLETE_INT_SUPPORTED 0x00000004 +#define PXE_ROMID_IMP_PACKET_RX_INT_SUPPORTED 0x00000002 +#define PXE_ROMID_IMP_CMD_COMPLETE_INT_SUPPORTED 0x00000001 + +typedef struct s_pxe_cdb { + PXE_OPCODE OpCode; + PXE_OPFLAGS OpFlags; + PXE_UINT16 CPBsize; + PXE_UINT16 DBsize; + PXE_UINT64 CPBaddr; + PXE_UINT64 DBaddr; + PXE_STATCODE StatCode; + PXE_STATFLAGS StatFlags; + PXE_UINT16 IFnum; + PXE_CONTROL Control; +} PXE_CDB; + +typedef union u_pxe_ip_addr { + PXE_IPV6 IPv6; + PXE_IPV4 IPv4; +} PXE_IP_ADDR; + +typedef union pxe_device { + // + // PCI and PC Card NICs are both identified using bus, device + // and function numbers. For PC Card, this may require PC + // Card services to be loaded in the BIOS or preboot + // environment. + // + struct { + // + // See S/W UNDI ROMID structure definition for PCI and + // PCC BusType definitions. + // + PXE_UINT32 BusType; + + // + // Bus, device & function numbers that locate this device. + // + PXE_UINT16 Bus; + PXE_UINT8 Device; + PXE_UINT8 Function; + } + PCI, PCC; + + // + // %%TBD - More information is needed about enumerating + // USB and 1394 devices. + // + struct { + PXE_UINT32 BusType; + PXE_UINT32 tdb; + } + USB, _1394; +} PXE_DEVICE; + +// +// cpb and db definitions +// +#define MAX_PCI_CONFIG_LEN 64 // # of dwords +#define MAX_EEPROM_LEN 128 // #of dwords +#define MAX_XMIT_BUFFERS 32 // recycling Q length for xmit_done +#define MAX_MCAST_ADDRESS_CNT 8 + +typedef struct s_pxe_cpb_start_30 { + // + // PXE_VOID Delay(UINTN microseconds); + // + // UNDI will never request a delay smaller than 10 microseconds + // and will always request delays in increments of 10 microseconds. + // The Delay() CallBack routine must delay between n and n + 10 + // microseconds before returning control to the UNDI. + // + // This field cannot be set to zero. + // + UINT64 Delay; + + // + // PXE_VOID Block(UINT32 enable); + // + // UNDI may need to block multi-threaded/multi-processor access to + // critical code sections when programming or accessing the network + // device. To this end, a blocking service is needed by the UNDI. + // When UNDI needs a block, it will call Block() passing a non-zero + // value. When UNDI no longer needs a block, it will call Block() + // with a zero value. When called, if the Block() is already enabled, + // do not return control to the UNDI until the previous Block() is + // disabled. + // + // This field cannot be set to zero. + // + UINT64 Block; + + // + // PXE_VOID Virt2Phys(UINT64 virtual, UINT64 physical_ptr); + // + // UNDI will pass the virtual address of a buffer and the virtual + // address of a 64-bit physical buffer. Convert the virtual address + // to a physical address and write the result to the physical address + // buffer. If virtual and physical addresses are the same, just + // copy the virtual address to the physical address buffer. + // + // This field can be set to zero if virtual and physical addresses + // are equal. + // + UINT64 Virt2Phys; + // + // PXE_VOID Mem_IO(UINT8 read_write, UINT8 len, UINT64 port, + // UINT64 buf_addr); + // + // UNDI will read or write the device io space using this call back + // function. It passes the number of bytes as the len parameter and it + // will be either 1,2,4 or 8. + // + // This field can not be set to zero. + // + UINT64 Mem_IO; +} PXE_CPB_START_30; + +typedef struct s_pxe_cpb_start_31 { + // + // PXE_VOID Delay(UINT64 UnqId, UINTN microseconds); + // + // UNDI will never request a delay smaller than 10 microseconds + // and will always request delays in increments of 10 microseconds. + // The Delay() CallBack routine must delay between n and n + 10 + // microseconds before returning control to the UNDI. + // + // This field cannot be set to zero. + // + UINT64 Delay; + + // + // PXE_VOID Block(UINT64 unq_id, UINT32 enable); + // + // UNDI may need to block multi-threaded/multi-processor access to + // critical code sections when programming or accessing the network + // device. To this end, a blocking service is needed by the UNDI. + // When UNDI needs a block, it will call Block() passing a non-zero + // value. When UNDI no longer needs a block, it will call Block() + // with a zero value. When called, if the Block() is already enabled, + // do not return control to the UNDI until the previous Block() is + // disabled. + // + // This field cannot be set to zero. + // + UINT64 Block; + + // + // PXE_VOID Virt2Phys(UINT64 UnqId, UINT64 virtual, UINT64 physical_ptr); + // + // UNDI will pass the virtual address of a buffer and the virtual + // address of a 64-bit physical buffer. Convert the virtual address + // to a physical address and write the result to the physical address + // buffer. If virtual and physical addresses are the same, just + // copy the virtual address to the physical address buffer. + // + // This field can be set to zero if virtual and physical addresses + // are equal. + // + UINT64 Virt2Phys; + // + // PXE_VOID Mem_IO(UINT64 UnqId, UINT8 read_write, UINT8 len, UINT64 port, + // UINT64 buf_addr); + // + // UNDI will read or write the device io space using this call back + // function. It passes the number of bytes as the len parameter and it + // will be either 1,2,4 or 8. + // + // This field can not be set to zero. + // + UINT64 Mem_IO; + // + // PXE_VOID Map_Mem(UINT64 unq_id, UINT64 virtual_addr, UINT32 size, + // UINT32 Direction, UINT64 mapped_addr); + // + // UNDI will pass the virtual address of a buffer, direction of the data + // flow from/to the mapped buffer (the constants are defined below) + // and a place holder (pointer) for the mapped address. + // This call will Map the given address to a physical DMA address and write + // the result to the mapped_addr pointer. If there is no need to + // map the given address to a lower address (i.e. the given address is + // associated with a physical address that is already compatible to be + // used with the DMA, it converts the given virtual address to it's + // physical address and write that in the mapped address pointer. + // + // This field can be set to zero if there is no mapping service available + // + UINT64 Map_Mem; + + // + // PXE_VOID UnMap_Mem(UINT64 unq_id, UINT64 virtual_addr, UINT32 size, + // UINT32 Direction, UINT64 mapped_addr); + // + // UNDI will pass the virtual and mapped addresses of a buffer + // This call will un map the given address + // + // This field can be set to zero if there is no unmapping service available + // + UINT64 UnMap_Mem; + + // + // PXE_VOID Sync_Mem(UINT64 unq_id, UINT64 virtual, + // UINT32 size, UINT32 Direction, UINT64 mapped_addr); + // + // UNDI will pass the virtual and mapped addresses of a buffer + // This call will synchronize the contents of both the virtual and mapped + // buffers for the given Direction. + // + // This field can be set to zero if there is no service available + // + UINT64 Sync_Mem; + + // + // protocol driver can provide anything for this Unique_ID, UNDI remembers + // that as just a 64bit value assocaited to the interface specified by + // the ifnum and gives it back as a parameter to all the call-back routines + // when calling for that interface! + // + UINT64 Unique_ID; + // +} PXE_CPB_START_31; + +#define TO_AND_FROM_DEVICE 0 +#define FROM_DEVICE 1 +#define TO_DEVICE 2 + +#define PXE_DELAY_MILLISECOND 1000 +#define PXE_DELAY_SECOND 1000000 +#define PXE_IO_READ 0 +#define PXE_IO_WRITE 1 +#define PXE_MEM_READ 2 +#define PXE_MEM_WRITE 4 + +typedef struct s_pxe_db_get_init_info { + // + // Minimum length of locked memory buffer that must be given to + // the Initialize command. Giving UNDI more memory will generally + // give better performance. + // + // If MemoryRequired is zero, the UNDI does not need and will not + // use system memory to receive and transmit packets. + // + PXE_UINT32 MemoryRequired; + + // + // Maximum frame data length for Tx/Rx excluding the media header. + // + PXE_UINT32 FrameDataLen; + + // + // Supported link speeds are in units of mega bits. Common ethernet + // values are 10, 100 and 1000. Unused LinkSpeeds[] entries are zero + // filled. + // + PXE_UINT32 LinkSpeeds[4]; + + // + // Number of non-volatile storage items. + // + PXE_UINT32 NvCount; + + // + // Width of non-volatile storage item in bytes. 0, 1, 2 or 4 + // + PXE_UINT16 NvWidth; + + // + // Media header length. This is the typical media header length for + // this UNDI. This information is needed when allocating receive + // and transmit buffers. + // + PXE_UINT16 MediaHeaderLen; + + // + // Number of bytes in the NIC hardware (MAC) address. + // + PXE_UINT16 HWaddrLen; + + // + // Maximum number of multicast MAC addresses in the multicast + // MAC address filter list. + // + PXE_UINT16 MCastFilterCnt; + + // + // Default number and size of transmit and receive buffers that will + // be allocated by the UNDI. If MemoryRequired is non-zero, this + // allocation will come out of the memory buffer given to the Initialize + // command. If MemoryRequired is zero, this allocation will come out of + // memory on the NIC. + // + PXE_UINT16 TxBufCnt; + PXE_UINT16 TxBufSize; + PXE_UINT16 RxBufCnt; + PXE_UINT16 RxBufSize; + + // + // Hardware interface types defined in the Assigned Numbers RFC + // and used in DHCP and ARP packets. + // See the PXE_IFTYPE typedef and PXE_IFTYPE_xxx macros. + // + PXE_UINT8 IFtype; + + // + // Supported duplex. See PXE_DUPLEX_xxxxx #defines below. + // + PXE_UINT8 SupportedDuplexModes; + + // + // Supported loopback options. See PXE_LOOPBACK_xxxxx #defines below. + // + PXE_UINT8 SupportedLoopBackModes; +} PXE_DB_GET_INIT_INFO; + +#define PXE_MAX_TXRX_UNIT_ETHER 1500 + +#define PXE_HWADDR_LEN_ETHER 0x0006 +#define PXE_MAC_HEADER_LEN_ETHER 0x000E + +#define PXE_DUPLEX_ENABLE_FULL_SUPPORTED 1 +#define PXE_DUPLEX_FORCE_FULL_SUPPORTED 2 + +#define PXE_LOOPBACK_INTERNAL_SUPPORTED 1 +#define PXE_LOOPBACK_EXTERNAL_SUPPORTED 2 + +typedef struct s_pxe_pci_config_info { + // + // This is the flag field for the PXE_DB_GET_CONFIG_INFO union. + // For PCI bus devices, this field is set to PXE_BUSTYPE_PCI. + // + UINT32 BusType; + + // + // This identifies the PCI network device that this UNDI interface + // is bound to. + // + UINT16 Bus; + UINT8 Device; + UINT8 Function; + + // + // This is a copy of the PCI configuration space for this + // network device. + // + union { + UINT8 Byte[256]; + UINT16 Word[128]; + UINT32 Dword[64]; + } Config; +} PXE_PCI_CONFIG_INFO; + +typedef struct s_pxe_pcc_config_info { + // + // This is the flag field for the PXE_DB_GET_CONFIG_INFO union. + // For PCC bus devices, this field is set to PXE_BUSTYPE_PCC. + // + PXE_UINT32 BusType; + + // + // This identifies the PCC network device that this UNDI interface + // is bound to. + // + PXE_UINT16 Bus; + PXE_UINT8 Device; + PXE_UINT8 Function; + + // + // This is a copy of the PCC configuration space for this + // network device. + // + union { + PXE_UINT8 Byte[256]; + PXE_UINT16 Word[128]; + PXE_UINT32 Dword[64]; + } Config; +} PXE_PCC_CONFIG_INFO; + +typedef union u_pxe_db_get_config_info { + PXE_PCI_CONFIG_INFO pci; + PXE_PCC_CONFIG_INFO pcc; +} PXE_DB_GET_CONFIG_INFO; + +typedef struct s_pxe_cpb_initialize { + // + // Address of first (lowest) byte of the memory buffer. This buffer must + // be in contiguous physical memory and cannot be swapped out. The UNDI + // will be using this for transmit and receive buffering. + // + PXE_UINT64 MemoryAddr; + + // + // MemoryLength must be greater than or equal to MemoryRequired + // returned by the Get Init Info command. + // + PXE_UINT32 MemoryLength; + + // + // Desired link speed in Mbit/sec. Common ethernet values are 10, 100 + // and 1000. Setting a value of zero will auto-detect and/or use the + // default link speed (operation depends on UNDI/NIC functionality). + // + PXE_UINT32 LinkSpeed; + + // + // Suggested number and size of receive and transmit buffers to + // allocate. If MemoryAddr and MemoryLength are non-zero, this + // allocation comes out of the supplied memory buffer. If MemoryAddr + // and MemoryLength are zero, this allocation comes out of memory + // on the NIC. + // + // If these fields are set to zero, the UNDI will allocate buffer + // counts and sizes as it sees fit. + // + PXE_UINT16 TxBufCnt; + PXE_UINT16 TxBufSize; + PXE_UINT16 RxBufCnt; + PXE_UINT16 RxBufSize; + + // + // The following configuration parameters are optional and must be zero + // to use the default values. + // + PXE_UINT8 DuplexMode; + + PXE_UINT8 LoopBackMode; +} PXE_CPB_INITIALIZE; + +#define PXE_DUPLEX_DEFAULT 0x00 +#define PXE_FORCE_FULL_DUPLEX 0x01 +#define PXE_ENABLE_FULL_DUPLEX 0x02 +#define PXE_FORCE_HALF_DUPLEX 0x04 +#define PXE_DISABLE_FULL_DUPLEX 0x08 + +#define LOOPBACK_NORMAL 0 +#define LOOPBACK_INTERNAL 1 +#define LOOPBACK_EXTERNAL 2 + +typedef struct s_pxe_db_initialize { + // + // Actual amount of memory used from the supplied memory buffer. This + // may be less that the amount of memory suppllied and may be zero if + // the UNDI and network device do not use external memory buffers. + // + // Memory used by the UNDI and network device is allocated from the + // lowest memory buffer address. + // + PXE_UINT32 MemoryUsed; + + // + // Actual number and size of receive and transmit buffers that were + // allocated. + // + PXE_UINT16 TxBufCnt; + PXE_UINT16 TxBufSize; + PXE_UINT16 RxBufCnt; + PXE_UINT16 RxBufSize; +} PXE_DB_INITIALIZE; + +typedef struct s_pxe_cpb_receive_filters { + // + // List of multicast MAC addresses. This list, if present, will + // replace the existing multicast MAC address filter list. + // + PXE_MAC_ADDR MCastList[MAX_MCAST_ADDRESS_CNT]; +} PXE_CPB_RECEIVE_FILTERS; + +typedef struct s_pxe_db_receive_filters { + // + // Filtered multicast MAC address list. + // + PXE_MAC_ADDR MCastList[MAX_MCAST_ADDRESS_CNT]; +} PXE_DB_RECEIVE_FILTERS; + +typedef struct s_pxe_cpb_station_address { + // + // If supplied and supported, the current station MAC address + // will be changed. + // + PXE_MAC_ADDR StationAddr; +} PXE_CPB_STATION_ADDRESS; + +typedef struct s_pxe_dpb_station_address { + // + // Current station MAC address. + // + PXE_MAC_ADDR StationAddr; + + // + // Station broadcast MAC address. + // + PXE_MAC_ADDR BroadcastAddr; + + // + // Permanent station MAC address. + // + PXE_MAC_ADDR PermanentAddr; +} PXE_DB_STATION_ADDRESS; + +typedef struct s_pxe_db_statistics { + // + // Bit field identifying what statistic data is collected by the + // UNDI/NIC. + // If bit 0x00 is set, Data[0x00] is collected. + // If bit 0x01 is set, Data[0x01] is collected. + // If bit 0x20 is set, Data[0x20] is collected. + // If bit 0x21 is set, Data[0x21] is collected. + // Etc. + // + PXE_UINT64 Supported; + + // + // Statistic data. + // + PXE_UINT64 Data[64]; +} PXE_DB_STATISTICS; + +// +// Total number of frames received. Includes frames with errors and +// dropped frames. +// +#define PXE_STATISTICS_RX_TOTAL_FRAMES 0x00 + +// +// Number of valid frames received and copied into receive buffers. +// +#define PXE_STATISTICS_RX_GOOD_FRAMES 0x01 + +// +// Number of frames below the minimum length for the media. +// This would be <64 for ethernet. +// +#define PXE_STATISTICS_RX_UNDERSIZE_FRAMES 0x02 + +// +// Number of frames longer than the maxminum length for the +// media. This would be >1500 for ethernet. +// +#define PXE_STATISTICS_RX_OVERSIZE_FRAMES 0x03 + +// +// Valid frames that were dropped because receive buffers were full. +// +#define PXE_STATISTICS_RX_DROPPED_FRAMES 0x04 + +// +// Number of valid unicast frames received and not dropped. +// +#define PXE_STATISTICS_RX_UNICAST_FRAMES 0x05 + +// +// Number of valid broadcast frames received and not dropped. +// +#define PXE_STATISTICS_RX_BROADCAST_FRAMES 0x06 + +// +// Number of valid mutlicast frames received and not dropped. +// +#define PXE_STATISTICS_RX_MULTICAST_FRAMES 0x07 + +// +// Number of frames w/ CRC or alignment errors. +// +#define PXE_STATISTICS_RX_CRC_ERROR_FRAMES 0x08 + +// +// Total number of bytes received. Includes frames with errors +// and dropped frames. +// +#define PXE_STATISTICS_RX_TOTAL_BYTES 0x09 + +// +// Transmit statistics. +// +#define PXE_STATISTICS_TX_TOTAL_FRAMES 0x0A +#define PXE_STATISTICS_TX_GOOD_FRAMES 0x0B +#define PXE_STATISTICS_TX_UNDERSIZE_FRAMES 0x0C +#define PXE_STATISTICS_TX_OVERSIZE_FRAMES 0x0D +#define PXE_STATISTICS_TX_DROPPED_FRAMES 0x0E +#define PXE_STATISTICS_TX_UNICAST_FRAMES 0x0F +#define PXE_STATISTICS_TX_BROADCAST_FRAMES 0x10 +#define PXE_STATISTICS_TX_MULTICAST_FRAMES 0x11 +#define PXE_STATISTICS_TX_CRC_ERROR_FRAMES 0x12 +#define PXE_STATISTICS_TX_TOTAL_BYTES 0x13 + +// +// Number of collisions detection on this subnet. +// +#define PXE_STATISTICS_COLLISIONS 0x14 + +// +// Number of frames destined for unsupported protocol. +// +#define PXE_STATISTICS_UNSUPPORTED_PROTOCOL 0x15 + +typedef struct s_pxe_cpb_mcast_ip_to_mac { + // + // Multicast IP address to be converted to multicast MAC address. + // + PXE_IP_ADDR IP; +} PXE_CPB_MCAST_IP_TO_MAC; + +typedef struct s_pxe_db_mcast_ip_to_mac { + // + // Multicast MAC address. + // + PXE_MAC_ADDR MAC; +} PXE_DB_MCAST_IP_TO_MAC; + +typedef struct s_pxe_cpb_nvdata_sparse { + // + // NvData item list. Only items in this list will be updated. + // + struct { + // + // Non-volatile storage address to be changed. + // + PXE_UINT32 Addr; + + // + // Data item to write into above storage address. + // + union { + PXE_UINT8 Byte; + PXE_UINT16 Word; + PXE_UINT32 Dword; + } Data; + } Item[MAX_EEPROM_LEN]; +} +PXE_CPB_NVDATA_SPARSE; + +// +// When using bulk update, the size of the CPB structure must be +// the same size as the non-volatile NIC storage. +// +typedef union u_pxe_cpb_nvdata_bulk { + // + // Array of byte-wide data items. + // + PXE_UINT8 Byte[MAX_EEPROM_LEN << 2]; + + // + // Array of word-wide data items. + // + PXE_UINT16 Word[MAX_EEPROM_LEN << 1]; + + // + // Array of dword-wide data items. + // + PXE_UINT32 Dword[MAX_EEPROM_LEN]; +} PXE_CPB_NVDATA_BULK; + +typedef struct s_pxe_db_nvdata { + // + // Arrays of data items from non-volatile storage. + // + union { + // + // Array of byte-wide data items. + // + PXE_UINT8 Byte[MAX_EEPROM_LEN << 2]; + + // + // Array of word-wide data items. + // + PXE_UINT16 Word[MAX_EEPROM_LEN << 1]; + + // + // Array of dword-wide data items. + // + PXE_UINT32 Dword[MAX_EEPROM_LEN]; + } Data; +} PXE_DB_NVDATA; + +typedef struct s_pxe_db_get_status { + // + // Length of next receive frame (header + data). If this is zero, + // there is no next receive frame available. + // + PXE_UINT32 RxFrameLen; + + // + // Reserved, set to zero. + // + PXE_UINT32 reserved; + + // + // Addresses of transmitted buffers that need to be recycled. + // + PXE_UINT64 TxBuffer[MAX_XMIT_BUFFERS]; +} PXE_DB_GET_STATUS; + +typedef struct s_pxe_cpb_fill_header { + // + // Source and destination MAC addresses. These will be copied into + // the media header without doing byte swapping. + // + PXE_MAC_ADDR SrcAddr; + PXE_MAC_ADDR DestAddr; + + // + // Address of first byte of media header. The first byte of packet data + // follows the last byte of the media header. + // + PXE_UINT64 MediaHeader; + + // + // Length of packet data in bytes (not including the media header). + // + PXE_UINT32 PacketLen; + + // + // Protocol type. This will be copied into the media header without + // doing byte swapping. Protocol type numbers can be obtained from + // the Assigned Numbers RFC 1700. + // + PXE_UINT16 Protocol; + + // + // Length of the media header in bytes. + // + PXE_UINT16 MediaHeaderLen; +} PXE_CPB_FILL_HEADER; + +#define PXE_PROTOCOL_ETHERNET_IP 0x0800 +#define PXE_PROTOCOL_ETHERNET_ARP 0x0806 +#define MAX_XMIT_FRAGMENTS 16 + +typedef struct s_pxe_cpb_fill_header_fragmented { + // + // Source and destination MAC addresses. These will be copied into + // the media header without doing byte swapping. + // + PXE_MAC_ADDR SrcAddr; + PXE_MAC_ADDR DestAddr; + + // + // Length of packet data in bytes (not including the media header). + // + PXE_UINT32 PacketLen; + + // + // Protocol type. This will be copied into the media header without + // doing byte swapping. Protocol type numbers can be obtained from + // the Assigned Numbers RFC 1700. + // + PXE_MEDIA_PROTOCOL Protocol; + + // + // Length of the media header in bytes. + // + PXE_UINT16 MediaHeaderLen; + + // + // Number of packet fragment descriptors. + // + PXE_UINT16 FragCnt; + + // + // Reserved, must be set to zero. + // + PXE_UINT16 reserved; + + // + // Array of packet fragment descriptors. The first byte of the media + // header is the first byte of the first fragment. + // + struct { + // + // Address of this packet fragment. + // + PXE_UINT64 FragAddr; + + // + // Length of this packet fragment. + // + PXE_UINT32 FragLen; + + // + // Reserved, must be set to zero. + // + PXE_UINT32 reserved; + } FragDesc[MAX_XMIT_FRAGMENTS]; +} +PXE_CPB_FILL_HEADER_FRAGMENTED; + +typedef struct s_pxe_cpb_transmit { + // + // Address of first byte of frame buffer. This is also the first byte + // of the media header. + // + PXE_UINT64 FrameAddr; + + // + // Length of the data portion of the frame buffer in bytes. Do not + // include the length of the media header. + // + PXE_UINT32 DataLen; + + // + // Length of the media header in bytes. + // + PXE_UINT16 MediaheaderLen; + + // + // Reserved, must be zero. + // + PXE_UINT16 reserved; +} PXE_CPB_TRANSMIT; + +typedef struct s_pxe_cpb_transmit_fragments { + // + // Length of packet data in bytes (not including the media header). + // + PXE_UINT32 FrameLen; + + // + // Length of the media header in bytes. + // + PXE_UINT16 MediaheaderLen; + + // + // Number of packet fragment descriptors. + // + PXE_UINT16 FragCnt; + + // + // Array of frame fragment descriptors. The first byte of the first + // fragment is also the first byte of the media header. + // + struct { + // + // Address of this frame fragment. + // + PXE_UINT64 FragAddr; + + // + // Length of this frame fragment. + // + PXE_UINT32 FragLen; + + // + // Reserved, must be set to zero. + // + PXE_UINT32 reserved; + } FragDesc[MAX_XMIT_FRAGMENTS]; +} +PXE_CPB_TRANSMIT_FRAGMENTS; + +typedef struct s_pxe_cpb_receive { + // + // Address of first byte of receive buffer. This is also the first byte + // of the frame header. + // + PXE_UINT64 BufferAddr; + + // + // Length of receive buffer. This must be large enough to hold the + // received frame (media header + data). If the length of smaller than + // the received frame, data will be lost. + // + PXE_UINT32 BufferLen; + + // + // Reserved, must be set to zero. + // + PXE_UINT32 reserved; +} PXE_CPB_RECEIVE; + +typedef struct s_pxe_db_receive { + // + // Source and destination MAC addresses from media header. + // + PXE_MAC_ADDR SrcAddr; + PXE_MAC_ADDR DestAddr; + + // + // Length of received frame. May be larger than receive buffer size. + // The receive buffer will not be overwritten. This is how to tell + // if data was lost because the receive buffer was too small. + // + PXE_UINT32 FrameLen; + + // + // Protocol type from media header. + // + PXE_MEDIA_PROTOCOL Protocol; + + // + // Length of media header in received frame. + // + PXE_UINT16 MediaHeaderLen; + + // + // Type of receive frame. + // + PXE_FRAME_TYPE Type; + + // + // Reserved, must be zero. + // + PXE_UINT8 reserved[7]; + +} PXE_DB_RECEIVE; + +// +// Packet definitions +// +typedef struct { + UINT8 BootpOpcode; + UINT8 BootpHwType; + UINT8 BootpHwAddrLen; + UINT8 BootpGateHops; + UINT32 BootpIdent; + UINT16 BootpSeconds; + UINT16 BootpFlags; + UINT8 BootpCiAddr[4]; + UINT8 BootpYiAddr[4]; + UINT8 BootpSiAddr[4]; + UINT8 BootpGiAddr[4]; + UINT8 BootpHwAddr[16]; + UINT8 BootpSrvName[64]; + UINT8 BootpBootFile[128]; + UINT32 DhcpMagik; + UINT8 DhcpOptions[56]; +} EFI_PXE_BASE_CODE_DHCPV4_PACKET; + +typedef union { + UINT8 Raw[1472]; + EFI_PXE_BASE_CODE_DHCPV4_PACKET Dhcpv4; + + // + // EFI_PXE_BASE_CODE_DHCPV6_PACKET Dhcpv6; + // +} EFI_PXE_BASE_CODE_PACKET; + + + +#pragma pack() + +#endif diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiSpec.h b/gpxe/src/include/gpxe/efi/Uefi/UefiSpec.h new file mode 100644 index 00000000..54c3ace7 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Uefi/UefiSpec.h @@ -0,0 +1,1780 @@ +/** @file + Include file that supportes UEFI. + + This include file must only contain things defined in the UEFI 2.0 specification. + If a code construct is defined in the UEFI 2.0 specification it must be included + by this include file. + + Copyright (c) 2006 - 2007, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __UEFI_SPEC_H__ +#define __UEFI_SPEC_H__ + +#include + +#include +#include +#include + +/// +/// Enumeration of memory allocation. +/// +typedef enum { + AllocateAnyPages, + AllocateMaxAddress, + AllocateAddress, + MaxAllocateType +} EFI_ALLOCATE_TYPE; + +// +// Bit definitions for EFI_TIME.Daylight +// +#define EFI_TIME_ADJUST_DAYLIGHT 0x01 +#define EFI_TIME_IN_DAYLIGHT 0x02 + +/// +/// Value definition for EFI_TIME.TimeZone +/// +#define EFI_UNSPECIFIED_TIMEZONE 0x07FF + +// +// possible caching types for the memory range +// +#define EFI_MEMORY_UC 0x0000000000000001ULL +#define EFI_MEMORY_WC 0x0000000000000002ULL +#define EFI_MEMORY_WT 0x0000000000000004ULL +#define EFI_MEMORY_WB 0x0000000000000008ULL +#define EFI_MEMORY_UCE 0x0000000000000010ULL + +// +// physical memory protection on range +// +#define EFI_MEMORY_WP 0x0000000000001000ULL +#define EFI_MEMORY_RP 0x0000000000002000ULL +#define EFI_MEMORY_XP 0x0000000000004000ULL + +/// +/// range requires a runtime mapping +/// +#define EFI_MEMORY_RUNTIME 0x8000000000000000ULL + +#define EFI_MEMORY_DESCRIPTOR_VERSION 1 +typedef struct { + UINT32 Type; + EFI_PHYSICAL_ADDRESS PhysicalStart; + EFI_VIRTUAL_ADDRESS VirtualStart; + UINT64 NumberOfPages; + UINT64 Attribute; +} EFI_MEMORY_DESCRIPTOR; + +/// +/// Build macros to find next EFI_MEMORY_DESCRIPTOR. +/// +#define NextMemoryDescriptor(_Ptr, _Size) ((EFI_MEMORY_DESCRIPTOR *) (((UINT8 *) (_Ptr)) + (_Size))) +#define NEXT_MEMORY_DESCRIPTOR(_Ptr, _Size) NextMemoryDescriptor (_Ptr, _Size) + +/// +/// Declare forward referenced data structures +/// +typedef struct _EFI_SYSTEM_TABLE EFI_SYSTEM_TABLE; + +/** + Allocates memory pages from the system. + + @param Type The type of allocation to perform. + @param MemoryType The type of memory to allocate. + @param Pages The number of contiguous 4 KB pages to allocate. + @param Memory Pointer to a physical address. On input, the way in which the address is + used depends on the value of Type. + + @retval EFI_SUCCESS The requested pages were allocated. + @retval EFI_INVALID_PARAMETER 1) Type is not AllocateAnyPages or + AllocateMaxAddress or AllocateAddress. + 2) MemoryType is in the range + EfiMaxMemoryType..0x7FFFFFFF. + @retval EFI_OUT_OF_RESOURCES The pages could not be allocated. + @retval EFI_NOT_FOUND The requested pages could not be found. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ALLOCATE_PAGES)( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN OUT EFI_PHYSICAL_ADDRESS *Memory + ); + +/** + Frees memory pages. + + @param Memory The base physical address of the pages to be freed. + @param Pages The number of contiguous 4 KB pages to free. + + @retval EFI_SUCCESS The requested pages were freed. + @retval EFI_INVALID_PARAMETER Memory is not a page-aligned address or Pages is invalid. + @retval EFI_NOT_FOUND The requested memory pages were not allocated with + AllocatePages(). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FREE_PAGES)( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN Pages + ); + +/** + Returns the current memory map. + + @param MemoryMapSize A pointer to the size, in bytes, of the MemoryMap buffer. + @param MemoryMap A pointer to the buffer in which firmware places the current memory + map. + @param MapKey A pointer to the location in which firmware returns the key for the + current memory map. + @param DescriptorSize A pointer to the location in which firmware returns the size, in bytes, of + an individual EFI_MEMORY_DESCRIPTOR. + @param DescriptorVersion A pointer to the location in which firmware returns the version number + associated with the EFI_MEMORY_DESCRIPTOR. + + @retval EFI_SUCCESS The memory map was returned in the MemoryMap buffer. + @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current buffer size + needed to hold the memory map is returned in MemoryMapSize. + @retval EFI_INVALID_PARAMETER 1) MemoryMapSize is NULL. + 2) The MemoryMap buffer is not too small and MemoryMap is + NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_MEMORY_MAP)( + IN OUT UINTN *MemoryMapSize, + IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, + OUT UINTN *MapKey, + OUT UINTN *DescriptorSize, + OUT UINT32 *DescriptorVersion + ); + +/** + Allocates pool memory. + + @param PoolType The type of pool to allocate. + @param Size The number of bytes to allocate from the pool. + @param Buffer A pointer to a pointer to the allocated buffer if the call succeeds; + undefined otherwise. + + @retval EFI_SUCCESS The requested number of bytes was allocated. + @retval EFI_OUT_OF_RESOURCES The pool requested could not be allocated. + @retval EFI_INVALID_PARAMETER PoolType was invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ALLOCATE_POOL)( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size, + OUT VOID **Buffer + ); + +/** + Returns pool memory to the system. + + @param Buffer Pointer to the buffer to free. + + @retval EFI_SUCCESS The memory was returned to the system. + @retval EFI_INVALID_PARAMETER Buffer was invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FREE_POOL)( + IN VOID *Buffer + ); + +/** + Changes the runtime addressing mode of EFI firmware from physical to virtual. + + @param MemoryMapSize The size in bytes of VirtualMap. + @param DescriptorSize The size in bytes of an entry in the VirtualMap. + @param DescriptorVersion The version of the structure entries in VirtualMap. + @param VirtualMap An array of memory descriptors which contain new virtual + address mapping information for all runtime ranges. + + @retval EFI_SUCCESS The virtual address map has been applied. + @retval EFI_UNSUPPORTED EFI firmware is not at runtime, or the EFI firmware is already in + virtual address mapped mode. + @retval EFI_INVALID_PARAMETER DescriptorSize or DescriptorVersion is invalid. + @retval EFI_NO_MAPPING A virtual address was not supplied for a range in the memory + map that requires a mapping. + @retval EFI_NOT_FOUND A virtual address was supplied for an address that is not found + in the memory map. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SET_VIRTUAL_ADDRESS_MAP)( + IN UINTN MemoryMapSize, + IN UINTN DescriptorSize, + IN UINT32 DescriptorVersion, + IN EFI_MEMORY_DESCRIPTOR *VirtualMap + ); + +/** + Connects one or more drivers to a controller. + + @param ControllerHandle The handle of the controller to which driver(s) are to be connected. + @param DriverImageHandle A pointer to an ordered list handles that support the + EFI_DRIVER_BINDING_PROTOCOL. + @param RemainingDevicePath A pointer to the device path that specifies a child of the + controller specified by ControllerHandle. + @param Recursive If TRUE, then ConnectController() is called recursively + until the entire tree of controllers below the controller specified + by ControllerHandle have been created. If FALSE, then + the tree of controllers is only expanded one level. + + @retval EFI_SUCCESS 1) One or more drivers were connected to ControllerHandle. + 2) No drivers were connected to ControllerHandle, but + RemainingDevicePath is not NULL, and it is an End Device + Path Node. + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + @retval EFI_NOT_FOUND 1) There are no EFI_DRIVER_BINDING_PROTOCOL instances + present in the system. + 2) No drivers were connected to ControllerHandle. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CONNECT_CONTROLLER)( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE *DriverImageHandle, OPTIONAL + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath, OPTIONAL + IN BOOLEAN Recursive + ); + +/** + Disconnects one or more drivers from a controller. + + @param ControllerHandle The handle of the controller from which driver(s) are to be disconnected. + @param DriverImageHandle The driver to disconnect from ControllerHandle. + @param ChildHandle The handle of the child to destroy. + + @retval EFI_SUCCESS 1) One or more drivers were disconnected from the controller. + 2) On entry, no drivers are managing ControllerHandle. + 3) DriverImageHandle is not NULL, and on entry + DriverImageHandle is not managing ControllerHandle. + + @retval EFI_INVALID_PARAMETER One ore more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to disconnect any drivers from + ControllerHandle. + @retval EFI_DEVICE_ERROR The controller could not be disconnected because of a device error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DISCONNECT_CONTROLLER)( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE DriverImageHandle, OPTIONAL + IN EFI_HANDLE ChildHandle OPTIONAL + ); + + + +// +// ConvertPointer DebugDisposition type. +// +#define EFI_OPTIONAL_PTR 0x00000001 +#define EFI_OPTIONAL_POINTER EFI_OPTIONAL_PTR + +/** + Determines the new virtual address that is to be used on subsequent memory accesses. + + @param DebugDisposition Supplies type information for the pointer being converted. + @param Address A pointer to a pointer that is to be fixed to be the value needed + for the new virtual address mappings being applied. + + @retval EFI_SUCCESS The pointer pointed to by Address was modified. + @retval EFI_INVALID_PARAMETER 1) Address is NULL. + 2) *Address is NULL and DebugDisposition does + not have the EFI_OPTIONAL_PTR bit set. + @retval EFI_NOT_FOUND The pointer pointed to by Address was not found to be part + of the current memory map. This is normally fatal. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CONVERT_POINTER)( + IN UINTN DebugDisposition, + IN OUT VOID **Address + ); + + +// +// These types can be ORed together as needed - for example, +// EVT_TIMER might be Ored with EVT_NOTIFY_WAIT or +// EVT_NOTIFY_SIGNAL. +// +#define EVT_TIMER 0x80000000 +#define EVT_RUNTIME 0x40000000 +#define EVT_NOTIFY_WAIT 0x00000100 +#define EVT_NOTIFY_SIGNAL 0x00000200 + +#define EVT_SIGNAL_EXIT_BOOT_SERVICES 0x00000201 +#define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202 + +// +// The event's NotifyContext pointer points to a runtime memory +// address. +// The event is deprecated in UEFI2.0 and later specifications. +// +#define EVT_RUNTIME_CONTEXT 0x20000000 + + +/** + Invoke a notification event + + @param Event Event whose notification function is being invoked. + @param Context Pointer to the notification function's context, + which is implementation-dependent. + +**/ +typedef +VOID +(EFIAPI *EFI_EVENT_NOTIFY)( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Creates an event. + + @param Type The type of event to create and its mode and attributes. + @param NotifyTpl Pointer to the notification function's context. + @param NotifyFunction Pointer to the event's notification function, if any. + @param NotifyContext Pointer to the notification function's context; corresponds to parameter + Context in the notification function. + @param Event Pointer to the newly created event if the call succeeds; undefined + otherwise. + + @retval EFI_SUCCESS The event structure was created. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The event could not be allocated. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CREATE_EVENT)( + IN UINT32 Type, + IN EFI_TPL NotifyTpl, + IN EFI_EVENT_NOTIFY NotifyFunction, + IN VOID *NotifyContext, + OUT EFI_EVENT *Event + ); + +/** + Creates an event in a group. + + @param Type The type of event to create and its mode and attributes. + @param NotifyTpl Pointer to the notification function's context. + @param NotifyFunction Pointer to the event's notification function, if any. + @param NotifyContext Pointer to the notification function's context; corresponds to parameter + Context in the notification function. + @param EventGroup Pointer to the unique identifier of the group to which this event belongs. + @param Event Pointer to the newly created event if the call succeeds; undefined + otherwise. + + @retval EFI_SUCCESS The event structure was created. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The event could not be allocated. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CREATE_EVENT_EX)( + IN UINT32 Type, + IN EFI_TPL NotifyTpl OPTIONAL, + IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL, + IN CONST VOID *NotifyContext OPTIONAL, + IN CONST EFI_GUID *EventGroup OPTIONAL, + OUT EFI_EVENT *Event + ); + +typedef enum { + TimerCancel, + TimerPeriodic, + TimerRelative +} EFI_TIMER_DELAY; + +/** + Sets the type of timer and the trigger time for a timer event. + + @param Event The timer event that is to be signaled at the specified time. + @param Type The type of time that is specified in TriggerTime. + @param TriggerTime The number of 100ns units until the timer expires. + + @retval EFI_SUCCESS The event has been set to be signaled at the requested time. + @retval EFI_INVALID_PARAMETER Event or Type is not valid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SET_TIMER)( + IN EFI_EVENT Event, + IN EFI_TIMER_DELAY Type, + IN UINT64 TriggerTime + ); + +/** + Signals an event. + + @param Event The event to signal. + + @retval EFI_SUCCESS The event has been signaled. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIGNAL_EVENT)( + IN EFI_EVENT Event + ); + +/** + Stops execution until an event is signaled. + + @param NumberOfEvents The number of events in the Event array. + @param Event An array of EFI_EVENT. + @param Index Pointer to the index of the event which satisfied the wait condition. + + @retval EFI_SUCCESS The event indicated by Index was signaled. + @retval EFI_INVALID_PARAMETER 1) NumberOfEvents is 0. + 2) The event indicated by Index is of type + EVT_NOTIFY_SIGNAL. + @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_WAIT_FOR_EVENT)( + IN UINTN NumberOfEvents, + IN EFI_EVENT *Event, + OUT UINTN *Index + ); + +/** + Closes an event. + + @param Event The event to close. + + @retval EFI_SUCCESS The event has been closed. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CLOSE_EVENT)( + IN EFI_EVENT Event + ); + +/** + Checks whether an event is in the signaled state. + + @param Event The event to check. + + @retval EFI_SUCCESS The event is in the signaled state. + @retval EFI_NOT_READY The event is not in the signaled state. + @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CHECK_EVENT)( + IN EFI_EVENT Event + ); + + +// +// Task priority level (name defined in spec). +// +#define TPL_APPLICATION 4 +#define TPL_CALLBACK 8 +#define TPL_NOTIFY 16 +#define TPL_HIGH_LEVEL 31 + + +/** + Raises a task's priority level and returns its previous level. + + @param NewTpl The new task priority level. + + @retval Previous task priority level + +**/ +typedef +EFI_TPL +(EFIAPI *EFI_RAISE_TPL)( + IN EFI_TPL NewTpl + ); + +/** + Restores a task's priority level to its previous value. + + @param OldTpl The previous task priority level to restore + +**/ +typedef +VOID +(EFIAPI *EFI_RESTORE_TPL)( + IN EFI_TPL OldTpl + ); + +/** + Returns the value of a variable. + + @param VariableName A Null-terminated Unicode string that is the name of the + vendor's variable. + @param VendorGuid A unique identifier for the vendor. + @param Attributes If not NULL, a pointer to the memory location to return the + attributes bitmask for the variable. + @param DataSize On input, the size in bytes of the return Data buffer. + On output the size of data returned in Data. + @param Data The buffer to return the contents of the variable. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The variable was not found. + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_VARIABLE)( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes, OPTIONAL + IN OUT UINTN *DataSize, + OUT VOID *Data + ); + +/** + Enumerates the current variable names. + + @param VariableNameSize The size of the VariableName buffer. + @param VariableName On input, supplies the last VariableName that was returned + by GetNextVariableName(). On output, returns the Nullterminated + Unicode string of the current variable. + @param VendorGuid On input, supplies the last VendorGuid that was returned by + GetNextVariableName(). On output, returns the + VendorGuid of the current variable. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The next variable was not found. + @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the result. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_NEXT_VARIABLE_NAME)( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ); + +/** + Sets the value of a variable. + + @param VariableName A Null-terminated Unicode string that is the name of the + vendor's variable. + @param VendorGuid A unique identifier for the vendor. + @param Attributes Attributes bitmask to set for the variable. + @param DataSize The size in bytes of the Data buffer. + @param Data The contents for the variable. + + @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as + defined by the Attributes. + @retval EFI_WRITE_PROTECTED The variable in question is read-only. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SET_VARIABLE)( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ); + + +// +// This provides the capabilities of the +// real time clock device as exposed through the EFI interfaces. +// +typedef struct { + UINT32 Resolution; + UINT32 Accuracy; + BOOLEAN SetsToZero; +} EFI_TIME_CAPABILITIES; + +/** + Returns the current time and date information, and the time-keeping capabilities + of the hardware platform. + + @param Time A pointer to storage to receive a snapshot of the current time. + @param Capabilities An optional pointer to a buffer to receive the real time clock + device's capabilities. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER Time is NULL. + @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_TIME)( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL + ); + +/** + Sets the current local time and date information. + + @param Time A pointer to the current time. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SET_TIME)( + IN EFI_TIME *Time + ); + +/** + Returns the current wakeup alarm clock setting. + + @param Enabled Indicates if the alarm is currently enabled or disabled. + @param Pending Indicates if the alarm signal is pending and requires acknowledgement. + @param Time The current alarm setting. + + @retval EFI_SUCCESS The alarm settings were returned. + @retval EFI_INVALID_PARAMETER Any parameter is NULL. + @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_WAKEUP_TIME)( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ); + +/** + Sets the system wakeup alarm clock time. + + @param Enabled Enable or disable the wakeup alarm. + @param Time If Enable is TRUE, the time to set the wakeup alarm for. + + @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. If + Enable is FALSE, then the wakeup alarm was disabled. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error. + @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SET_WAKEUP_TIME)( + IN BOOLEAN Enable, + IN EFI_TIME *Time OPTIONAL + ); + +/** + This is the declaration of an EFI image entry point. This can be the entry point to an application + written to this specification, an EFI boot service driver, or an EFI runtime driver. + + @param ImageHandle Handle that identifies the loaded image. + @param SystemTable System Table for this image. + + @retval EFI_SUCCESS The operation completed successfully. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IMAGE_ENTRY_POINT)( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Loads an EFI image into memory. + + @param BootPolicy If TRUE, indicates that the request originates from the boot + manager, and that the boot manager is attempting to load + FilePath as a boot selection. Ignored if SourceBuffer is + not NULL. + @param ParentImageHandle The caller's image handle. + @param FilePath The DeviceHandle specific file path from which the image is + loaded. + @param SourceBuffer If not NULL, a pointer to the memory location containing a copy + of the image to be loaded. + @param SourceSize The size in bytes of SourceBuffer. + @param ImageHandle Pointer to the returned image handle that is created when the + image is successfully loaded. + + @retval EFI_SUCCESS Image was loaded into memory correctly. + @retval EFI_NOT_FOUND Both SourceBuffer and FilePath are NULL. + @retval EFI_INVALID_PARAMETER One or more parametes are invalid. + @retval EFI_UNSUPPORTED The image type is not supported. + @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient resources. + @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not + understood. + @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IMAGE_LOAD)( + IN BOOLEAN BootPolicy, + IN EFI_HANDLE ParentImageHandle, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN VOID *SourceBuffer OPTIONAL, + IN UINTN SourceSize, + OUT EFI_HANDLE *ImageHandle + ); + +/** + Transfers control to a loaded image's entry point. + + @param ImageHandle Handle of image to be started. + @param ExitDataSize Pointer to the size, in bytes, of ExitData. + @param ExitData Pointer to a pointer to a data buffer that includes a Null-terminated + Unicode string, optionally followed by additional binary data. + + @retval EFI_INVALID_PARAMETER ImageHandle is either an invalid image handle or the image + has already been initialized with StartImage + @retval Exit code from image Exit code from image + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IMAGE_START)( + IN EFI_HANDLE ImageHandle, + OUT UINTN *ExitDataSize, + OUT CHAR16 **ExitData OPTIONAL + ); + +/** + Terminates a loaded EFI image and returns control to boot services. + + @param ImageHandle Handle that identifies the image. + @param ExitStatus The image's exit code. + @param ExitDataSize The size, in bytes, of ExitData. + @param ExitData Pointer to a data buffer that includes a Null-terminated Unicode string, + optionally followed by additional binary data. + + @retval EFI_SUCCESS The image specified by ImageHandle was unloaded. + @retval EFI_INVALID_PARAMETER The image specified by ImageHandle has been loaded and + started with LoadImage() and StartImage(), but the + image is not the currently executing image. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_EXIT)( + IN EFI_HANDLE ImageHandle, + IN EFI_STATUS ExitStatus, + IN UINTN ExitDataSize, + IN CHAR16 *ExitData OPTIONAL + ); + +/** + Unloads an image. + + @param ImageHandle Handle that identifies the image to be unloaded. + + @retval EFI_SUCCESS The image has been unloaded. + @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle. + @retval EFI_UNSUPPORTED The image has been started, and does not support unload. + @retval Exit code from the image's unload handler + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IMAGE_UNLOAD)( + IN EFI_HANDLE ImageHandle + ); + +/** + Terminates all boot services. + + @param ImageHandle Handle that identifies the exiting image. + @param MapKey Key to the latest memory map. + + @retval EFI_SUCCESS Boot services have been terminated. + @retval EFI_INVALID_PARAMETER MapKey is incorrect. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_EXIT_BOOT_SERVICES)( + IN EFI_HANDLE ImageHandle, + IN UINTN MapKey + ); + +/** + Induces a fine-grained stall. + + @param Microseconds The number of microseconds to stall execution. + + @retval EFI_SUCCESS Execution was stalled at least the requested number of + Microseconds. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_STALL)( + IN UINTN Microseconds + ); + +/** + Sets the system's watchdog timer. + + @param Timeout The number of seconds to set the watchdog timer to. + @param WatchdogCode The numeric code to log on a watchdog timer timeout event. + @param DataSize The size, in bytes, of WatchdogData. + @param WatchdogData A data buffer that includes a Null-terminated Unicode string, optionally + followed by additional binary data. + + @retval EFI_SUCCESS The timeout has been set. + @retval EFI_INVALID_PARAMETER The supplied WatchdogCode is invalid. + @retval EFI_UNSUPPORTED The system does not have a watchdog timer. + @retval EFI_DEVICE_ERROR The watch dog timer could not be programmed due to a hardware + error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SET_WATCHDOG_TIMER)( + IN UINTN Timeout, + IN UINT64 WatchdogCode, + IN UINTN DataSize, + IN CHAR16 *WatchdogData OPTIONAL + ); + +// +// Enumeration of reset types. +// +typedef enum { + EfiResetCold, + EfiResetWarm, + EfiResetShutdown, + EfiResetUpdate +} EFI_RESET_TYPE; + +/** + Resets the entire platform. + + @param ResetType The type of reset to perform. + @param ResetStatus The status code for the reset. + @param DataSize The size, in bytes, of WatchdogData. + @param ResetData For a ResetType of EfiResetCold, EfiResetWarm, or + EfiResetShutdown the data buffer starts with a Null-terminated + Unicode string, optionally followed by additional binary data. + +**/ +typedef +VOID +(EFIAPI *EFI_RESET_SYSTEM)( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN CHAR16 *ResetData OPTIONAL + ); + +/** + Returns a monotonically increasing count for the platform. + + @param Count Pointer to returned value. + + @retval EFI_SUCCESS The next monotonic count was returned. + @retval EFI_INVALID_PARAMETER Count is NULL. + @retval EFI_DEVICE_ERROR The device is not functioning properly. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_NEXT_MONOTONIC_COUNT)( + OUT UINT64 *Count + ); + +/** + Returns the next high 32 bits of the platform's monotonic counter. + + @param HighCount Pointer to returned value. + + @retval EFI_SUCCESS The next high monotonic count was returned. + @retval EFI_INVALID_PARAMETER HighCount is NULL. + @retval EFI_DEVICE_ERROR The device is not functioning properly. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_NEXT_HIGH_MONO_COUNT)( + OUT UINT32 *HighCount + ); + +/** + Computes and returns a 32-bit CRC for a data buffer. + + @param Data A pointer to the buffer on which the 32-bit CRC is to be computed. + @param DataSize The number of bytes in the buffer Data. + @param Crc32 The 32-bit CRC that was computed for the data buffer specified by Data + and DataSize. + + @retval EFI_SUCCESS The 32-bit CRC was computed for the data buffer and returned in + Crc32. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CALCULATE_CRC32)( + IN VOID *Data, + IN UINTN DataSize, + OUT UINT32 *Crc32 + ); + +/** + Copies the contents of one buffer to another buffer. + + @param Destination Pointer to the destination buffer of the memory copy. + @param Source Pointer to the source buffer of the memory copy. + @param Length Number of bytes to copy from Source to Destination. + +**/ +typedef +VOID +(EFIAPI *EFI_COPY_MEM)( + IN VOID *Destination, + IN VOID *Source, + IN UINTN Length + ); + +/** + The SetMem() function fills a buffer with a specified value. + + @param Buffer Pointer to the buffer to fill. + @param Size Number of bytes in Buffer to fill. + @param Value Value to fill Buffer with. + +**/ +typedef +VOID +(EFIAPI *EFI_SET_MEM)( + IN VOID *Buffer, + IN UINTN Size, + IN UINT8 Value + ); + + +// +// Protocol handler functions +// +typedef enum { + EFI_NATIVE_INTERFACE +} EFI_INTERFACE_TYPE; + +/** + Installs a protocol interface on a device handle. If the handle does not exist, it is created and added + to the list of handles in the system. InstallMultipleProtocolInterfaces() performs + more error checking than InstallProtocolInterface(), so it is recommended that + InstallMultipleProtocolInterfaces() be used in place of + InstallProtocolInterface() + + @param Handle A pointer to the EFI_HANDLE on which the interface is to be installed. + @param Protocol The numeric ID of the protocol interface. + @param InterfaceType Indicates whether Interface is supplied in native form. + @param Interface A pointer to the protocol interface. + + @retval EFI_SUCCESS The protocol interface was installed. + @retval EFI_OUT_OF_RESOURCES Space for a new handle could not be allocated. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_INSTALL_PROTOCOL_INTERFACE)( + IN OUT EFI_HANDLE *Handle, + IN EFI_GUID *Protocol, + IN EFI_INTERFACE_TYPE InterfaceType, + IN VOID *Interface + ); + +/** + Installs one or more protocol interfaces into the boot services environment. + + @param Handle The handle to install the new protocol interfaces on, or NULL if a new + handle is to be allocated. + @param ... A variable argument list containing pairs of protocol GUIDs and protocol + interfaces. + + @retval EFI_SUCCESS All the protocol interface was installed. + @retval EFI_OUT_OF_RESOURCES There was not enough memory in pool to install all the protocols. + @retval EFI_ALREADY_STARTED A Device Path Protocol instance was passed in that is already present in + the handle database. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES)( + IN OUT EFI_HANDLE *Handle, + ... + ); + +/** + Reinstalls a protocol interface on a device handle. + + @param Handle Handle on which the interface is to be reinstalled. + @param Protocol The numeric ID of the interface. + @param OldInterface A pointer to the old interface. NULL can be used if a structure is not + associated with Protocol. + @param NewInterface A pointer to the new interface. + + @retval EFI_SUCCESS The protocol interface was reinstalled. + @retval EFI_NOT_FOUND The OldInterface on the handle was not found. + @retval EFI_ACCESS_DENIED The protocol interface could not be reinstalled, + because OldInterface is still being used by a + driver that will not release it. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_REINSTALL_PROTOCOL_INTERFACE)( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + IN VOID *OldInterface, + IN VOID *NewInterface + ); + +/** + Removes a protocol interface from a device handle. It is recommended that + UninstallMultipleProtocolInterfaces() be used in place of + UninstallProtocolInterface(). + + @param Handle The handle on which the interface was installed. + @param Protocol The numeric ID of the interface. + @param Interface A pointer to the interface. + + @retval EFI_SUCCESS The interface was removed. + @retval EFI_NOT_FOUND The interface was not found. + @retval EFI_ACCESS_DENIED The interface was not removed because the interface + is still being used by a driver. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UNINSTALL_PROTOCOL_INTERFACE)( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + IN VOID *Interface + ); + +/** + Removes one or more protocol interfaces into the boot services environment. + + @param Handle The handle to remove the protocol interfaces from. + @param ... A variable argument list containing pairs of protocol GUIDs and + protocol interfaces. + + @retval EFI_SUCCESS All the protocol interfaces were removed. + @retval EFI_INVALID_PARAMETER One of the protocol interfaces was not previously installed on Handle. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES)( + IN EFI_HANDLE Handle, + ... + ); + +/** + Queries a handle to determine if it supports a specified protocol. + + @param Handle The handle being queried. + @param Protocol The published unique identifier of the protocol. + @param Interface Supplies the address where a pointer to the corresponding Protocol + Interface is returned. + @retval EFI_SUCCESS The interface information for the specified protocol was returned. + @retval EFI_UNSUPPORTED The device does not support the specified protocol. + @retval EFI_INVALID_PARAMETER One of the protocol interfaces was not previously installed on Handle. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HANDLE_PROTOCOL)( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + OUT VOID **Interface + ); + +#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x00000001 +#define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002 +#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL 0x00000004 +#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 0x00000008 +#define EFI_OPEN_PROTOCOL_BY_DRIVER 0x00000010 +#define EFI_OPEN_PROTOCOL_EXCLUSIVE 0x00000020 + +/** + Queries a handle to determine if it supports a specified protocol. If the protocol is supported by the + handle, it opens the protocol on behalf of the calling agent. + + @param Handle The handle for the protocol interface that is being opened. + @param Protocol The published unique identifier of the protocol. + @param Interface Supplies the address where a pointer to the corresponding Protocol + Interface is returned. + @param AgentHandle The handle of the agent that is opening the protocol interface + specified by Protocol and Interface. + @param ControllerHandle If the agent that is opening a protocol is a driver that follows the + UEFI Driver Model, then this parameter is the controller handle + that requires the protocol interface. If the agent does not follow + the UEFI Driver Model, then this parameter is optional and may + be NULL. + @param Attributes The open mode of the protocol interface specified by Handle + and Protocol. + + @retval EFI_SUCCESS An item was added to the open list for the protocol interface, and the + protocol interface was returned in Interface. + @retval EFI_UNSUPPORTED Handle does not support Protocol. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_ACCESS_DENIED Required attributes can't be supported in current environment. + @retval EFI_ALREADY_STARTED Item on the open list already has requierd attributes whose agent + handle is the same as AgentHandle. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_OPEN_PROTOCOL)( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + OUT VOID **Interface, + IN EFI_HANDLE AgentHandle, + IN EFI_HANDLE ControllerHandle, OPTIONAL + IN UINT32 Attributes + ); + + +/** + Closes a protocol on a handle that was opened using OpenProtocol(). + + @param Handle The handle for the protocol interface that was previously opened + with OpenProtocol(), and is now being closed. + @param Protocol The published unique identifier of the protocol. + @param Interface Supplies the address where a pointer to the corresponding Protocol + Interface is returned. + @param AgentHandle The handle of the agent that is closing the protocol interface. + @param ControllerHandle If the agent that opened a protocol is a driver that follows the + UEFI Driver Model, then this parameter is the controller handle + that required the protocol interface. + + @retval EFI_SUCCESS The protocol instance was closed. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_NOT_FOUND 1) Handle does not support the protocol specified by Protocol. + 2) The protocol interface specified by Handle and Protocol is not + currently open by AgentHandle and ControllerHandle. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CLOSE_PROTOCOL)( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + IN EFI_HANDLE AgentHandle, + IN EFI_HANDLE ControllerHandle + ); + + +typedef struct { + EFI_HANDLE AgentHandle; + EFI_HANDLE ControllerHandle; + UINT32 Attributes; + UINT32 OpenCount; +} EFI_OPEN_PROTOCOL_INFORMATION_ENTRY; + +/** + Retrieves the list of agents that currently have a protocol interface opened. + + @param Handle The handle for the protocol interface that is being queried. + @param Protocol The published unique identifier of the protocol. + @param EntryBuffer A pointer to a buffer of open protocol information in the form of + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY structures. + @param EntryCount A pointer to the number of entries in EntryBuffer. + + @retval EFI_SUCCESS The open protocol information was returned in EntryBuffer, and the + number of entries was returned EntryCount. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate EntryBuffer. + @retval EFI_NOT_FOUND Handle does not support the protocol specified by Protocol. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_OPEN_PROTOCOL_INFORMATION)( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + IN EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer, + OUT UINTN *EntryCount + ); + +/** + Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated + from pool. + + @param Handle The handle from which to retrieve the list of protocol interface + GUIDs. + @param ProtocolBuffer A pointer to the list of protocol interface GUID pointers that are + installed on Handle. + @param ProtocolBufferCount A pointer to the number of GUID pointers present in + ProtocolBuffer. + + @retval EFI_SUCCESS The list of protocol interface GUIDs installed on Handle was returned in + ProtocolBuffer. The number of protocol interface GUIDs was + returned in ProtocolBufferCount. + @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the results. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PROTOCOLS_PER_HANDLE)( + IN EFI_HANDLE Handle, + OUT EFI_GUID ***ProtocolBuffer, + OUT UINTN *ProtocolBufferCount + ); + +/** + Creates an event that is to be signaled whenever an interface is installed for a specified protocol. + + @param Protocol The numeric ID of the protocol for which the event is to be registered. + @param Event Event that is to be signaled whenever a protocol interface is registered + for Protocol. + @param Registration A pointer to a memory location to receive the registration value. + + @retval EFI_SUCCESS The notification event has been registered. + @retval EFI_OUT_OF_RESOURCES Space for the notification event could not be allocated. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_REGISTER_PROTOCOL_NOTIFY)( + IN EFI_GUID *Protocol, + IN EFI_EVENT Event, + OUT VOID **Registration + ); + + +typedef enum { + AllHandles, + ByRegisterNotify, + ByProtocol +} EFI_LOCATE_SEARCH_TYPE; + +/** + Returns an array of handles that support a specified protocol. + + @param SearchType Specifies which handle(s) are to be returned. + @param Protocol Specifies the protocol to search by. + @param SearchKey Specifies the search key. + @param BufferSize On input, the size in bytes of Buffer. On output, the size in bytes of + the array returned in Buffer (if the buffer was large enough) or the + size, in bytes, of the buffer needed to obtain the array (if the buffer was + not large enough). + @param Buffer The buffer in which the array is returned. + + @retval EFI_SUCCESS The array of handles was returned. + @retval EFI_NOT_FOUND No handles match the search. + @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small for the result. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LOCATE_HANDLE)( + IN EFI_LOCATE_SEARCH_TYPE SearchType, + IN EFI_GUID *Protocol, OPTIONAL + IN VOID *SearchKey, OPTIONAL + IN OUT UINTN *BufferSize, + OUT EFI_HANDLE *Buffer + ); + +/** + Locates the handle to a device on the device path that supports the specified protocol. + + @param Protocol Specifies the protocol to search for. + @param DevicePath On input, a pointer to a pointer to the device path. On output, the device + path pointer is modified to point to the remaining part of the device + path. + @param Device A pointer to the returned device handle. + + @retval EFI_SUCCESS The resulting handle was returned. + @retval EFI_NOT_FOUND No handles match the search. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LOCATE_DEVICE_PATH)( + IN EFI_GUID *Protocol, + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, + OUT EFI_HANDLE *Device + ); + +/** + Adds, updates, or removes a configuration table entry from the EFI System Table. + + @param Guid A pointer to the GUID for the entry to add, update, or remove. + @param Table A pointer to the configuration table for the entry to add, update, or + remove. May be NULL. + + @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed. + @retval EFI_NOT_FOUND An attempt was made to delete a nonexistent entry. + @retval EFI_INVALID_PARAMETER Guid is not valid. + @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_INSTALL_CONFIGURATION_TABLE)( + IN EFI_GUID *Guid, + IN VOID *Table + ); + + +/** + Returns an array of handles that support the requested protocol in a buffer allocated from pool. + + @param SearchType Specifies which handle(s) are to be returned. + @param Protocol Specifies the protocol to search by. + @param SearchKey Supplies the search key depending on the SearchType. + @param NoHandles The number of handles returned in Buffer. + @param Buffer A pointer to the buffer to return the requested array of handles that + support Protocol. + + @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of + handles in Buffer was returned in NoHandles. + @retval EFI_NOT_FOUND No handles match the search. + @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LOCATE_HANDLE_BUFFER)( + IN EFI_LOCATE_SEARCH_TYPE SearchType, + IN EFI_GUID *Protocol, OPTIONAL + IN VOID *SearchKey, OPTIONAL + IN OUT UINTN *NoHandles, + OUT EFI_HANDLE **Buffer + ); + +/** + Returns the first protocol instance that matches the given protocol. + + @param Protocol Provides the protocol to search for. + @param Registration Optional registration key returned from + RegisterProtocolNotify(). + @param Interface On return, a pointer to the first interface that matches Protocol and + Registration. + + @retval EFI_SUCCESS A protocol instance matching Protocol was found and returned in + Interface. + @retval EFI_NOT_FOUND No protocol instances were found that match Protocol and + Registration. + @retval EFI_INVALID_PARAMETER Interface is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LOCATE_PROTOCOL)( + IN EFI_GUID *Protocol, + IN VOID *Registration, OPTIONAL + OUT VOID **Interface + ); + +typedef struct { + UINT64 Length; + union { + EFI_PHYSICAL_ADDRESS DataBlock; + EFI_PHYSICAL_ADDRESS ContinuationPointer; + } Union; +} EFI_CAPSULE_BLOCK_DESCRIPTOR; + +typedef struct { + EFI_GUID CapsuleGuid; + UINT32 HeaderSize; + UINT32 Flags; + UINT32 CapsuleImageSize; +} EFI_CAPSULE_HEADER; + +typedef struct { + UINT32 CapsuleArrayNumber; + VOID* CapsulePtr[1]; +} EFI_CAPSULE_TABLE; + +#define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000 +#define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000 + +/** + Passes capsules to the firmware with both virtual and physical mapping. Depending on the intended + consumption, the firmware may process the capsule immediately. If the payload should persist + across a system reset, the reset value returned from EFI_QueryCapsuleCapabilities must + be passed into ResetSystem() and will cause the capsule to be processed by the firmware as + part of the reset process. + + @param CapsuleHeaderArray Virtual pointer to an array of virtual pointers to the capsules + being passed into update capsule. + @param CapsuleCount Number of pointers to EFI_CAPSULE_HEADER in + CaspuleHeaderArray. + @param ScatterGatherList Physical pointer to a set of + EFI_CAPSULE_BLOCK_DESCRIPTOR that describes the + location in physical memory of a set of capsules. + + @retval EFI_SUCCESS Valid capsule was passed. If + CAPSULE_FLAGS_PERSIT_ACROSS_RESET is not set, the + capsule has been successfully processed by the firmware. + @retval EFI_DEVICE_ERROR The capsule update was started, but failed due to a device error. + @retval EFI_INVALID_PARAMETER CapsuleSize is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UPDATE_CAPSULE)( + IN EFI_CAPSULE_HEADER **CapsuleHeaderArray, + IN UINTN CapsuleCount, + IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL + ); + +/** + Returns if the capsule can be supported via UpdateCapsule(). + + @param CapsuleHeaderArray Virtual pointer to an array of virtual pointers to the capsules + being passed into update capsule. + @param CapsuleCount Number of pointers to EFI_CAPSULE_HEADER in + CaspuleHeaderArray. + @param MaxiumCapsuleSize On output the maximum size that UpdateCapsule() can + support as an argument to UpdateCapsule() via + CapsuleHeaderArray and ScatterGatherList. + @param ResetType Returns the type of reset required for the capsule update. + + @retval EFI_SUCCESS Valid answer returned. + @retval EFI_UNSUPPORTED The capsule type is not supported on this platform, and + MaximumCapsuleSize and ResetType are undefined. + @retval EFI_INVALID_PARAMETER MaximumCapsuleSize is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_QUERY_CAPSULE_CAPABILITIES)( + IN EFI_CAPSULE_HEADER **CapsuleHeaderArray, + IN UINTN CapsuleCount, + OUT UINT64 *MaximumCapsuleSize, + OUT EFI_RESET_TYPE *ResetType + ); + +/** + Returns information about the EFI variables. + + @param Attributes Attributes bitmask to specify the type of variables on + which to return information. + @param MaximumVariableStorageSize On output the maximum size of the storage space + available for the EFI variables associated with the + attributes specified. + @param RemainingVariableStorageSize Returns the remaining size of the storage space + available for the EFI variables associated with the + attributes specified. + @param MaximumVariableSize Returns the maximum size of the individual EFI + variables associated with the attributes specified. + + @retval EFI_SUCCESS Valid answer returned. + @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied + @retval EFI_UNSUPPORTED The attribute is not supported on this platform, and the + MaximumVariableStorageSize, + RemainingVariableStorageSize, MaximumVariableSize + are undefined. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_QUERY_VARIABLE_INFO)( + IN UINT32 Attributes, + OUT UINT64 *MaximumVariableStorageSize, + OUT UINT64 *RemainingVariableStorageSize, + OUT UINT64 *MaximumVariableSize + ); + + +// +// EFI Runtime Services Table +// +#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249ULL +#define EFI_SYSTEM_TABLE_REVISION ((2<<16) | (10)) +#define EFI_2_10_SYSTEM_TABLE_REVISION ((2<<16) | (10)) +#define EFI_2_00_SYSTEM_TABLE_REVISION ((2<<16) | (00)) +#define EFI_1_10_SYSTEM_TABLE_REVISION ((1<<16) | (10)) +#define EFI_1_02_SYSTEM_TABLE_REVISION ((1<<16) | (02)) + +#define EFI_RUNTIME_SERVICES_SIGNATURE 0x56524553544e5552ULL +#define EFI_RUNTIME_SERVICES_REVISION EFI_2_10_SYSTEM_TABLE_REVISION + +typedef struct { + EFI_TABLE_HEADER Hdr; + + // + // Time Services + // + EFI_GET_TIME GetTime; + EFI_SET_TIME SetTime; + EFI_GET_WAKEUP_TIME GetWakeupTime; + EFI_SET_WAKEUP_TIME SetWakeupTime; + + // + // Virtual Memory Services + // + EFI_SET_VIRTUAL_ADDRESS_MAP SetVirtualAddressMap; + EFI_CONVERT_POINTER ConvertPointer; + + // + // Variable Services + // + EFI_GET_VARIABLE GetVariable; + EFI_GET_NEXT_VARIABLE_NAME GetNextVariableName; + EFI_SET_VARIABLE SetVariable; + + // + // Miscellaneous Services + // + EFI_GET_NEXT_HIGH_MONO_COUNT GetNextHighMonotonicCount; + EFI_RESET_SYSTEM ResetSystem; + + // + // UEFI 2.0 Capsule Services + // + EFI_UPDATE_CAPSULE UpdateCapsule; + EFI_QUERY_CAPSULE_CAPABILITIES QueryCapsuleCapabilities; + + // + // Miscellaneous UEFI 2.0 Service + // + EFI_QUERY_VARIABLE_INFO QueryVariableInfo; +} EFI_RUNTIME_SERVICES; + + +#define EFI_BOOT_SERVICES_SIGNATURE 0x56524553544f4f42ULL +#define EFI_BOOT_SERVICES_REVISION EFI_2_10_SYSTEM_TABLE_REVISION + +typedef struct { + EFI_TABLE_HEADER Hdr; + + // + // Task Priority Services + // + EFI_RAISE_TPL RaiseTPL; + EFI_RESTORE_TPL RestoreTPL; + + // + // Memory Services + // + EFI_ALLOCATE_PAGES AllocatePages; + EFI_FREE_PAGES FreePages; + EFI_GET_MEMORY_MAP GetMemoryMap; + EFI_ALLOCATE_POOL AllocatePool; + EFI_FREE_POOL FreePool; + + // + // Event & Timer Services + // + EFI_CREATE_EVENT CreateEvent; + EFI_SET_TIMER SetTimer; + EFI_WAIT_FOR_EVENT WaitForEvent; + EFI_SIGNAL_EVENT SignalEvent; + EFI_CLOSE_EVENT CloseEvent; + EFI_CHECK_EVENT CheckEvent; + + // + // Protocol Handler Services + // + EFI_INSTALL_PROTOCOL_INTERFACE InstallProtocolInterface; + EFI_REINSTALL_PROTOCOL_INTERFACE ReinstallProtocolInterface; + EFI_UNINSTALL_PROTOCOL_INTERFACE UninstallProtocolInterface; + EFI_HANDLE_PROTOCOL HandleProtocol; + VOID *Reserved; + EFI_REGISTER_PROTOCOL_NOTIFY RegisterProtocolNotify; + EFI_LOCATE_HANDLE LocateHandle; + EFI_LOCATE_DEVICE_PATH LocateDevicePath; + EFI_INSTALL_CONFIGURATION_TABLE InstallConfigurationTable; + + // + // Image Services + // + EFI_IMAGE_LOAD LoadImage; + EFI_IMAGE_START StartImage; + EFI_EXIT Exit; + EFI_IMAGE_UNLOAD UnloadImage; + EFI_EXIT_BOOT_SERVICES ExitBootServices; + + // + // Miscellaneous Services + // + EFI_GET_NEXT_MONOTONIC_COUNT GetNextMonotonicCount; + EFI_STALL Stall; + EFI_SET_WATCHDOG_TIMER SetWatchdogTimer; + + // + // DriverSupport Services + // + EFI_CONNECT_CONTROLLER ConnectController; + EFI_DISCONNECT_CONTROLLER DisconnectController; + + // + // Open and Close Protocol Services + // + EFI_OPEN_PROTOCOL OpenProtocol; + EFI_CLOSE_PROTOCOL CloseProtocol; + EFI_OPEN_PROTOCOL_INFORMATION OpenProtocolInformation; + + // + // Library Services + // + EFI_PROTOCOLS_PER_HANDLE ProtocolsPerHandle; + EFI_LOCATE_HANDLE_BUFFER LocateHandleBuffer; + EFI_LOCATE_PROTOCOL LocateProtocol; + EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES InstallMultipleProtocolInterfaces; + EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES UninstallMultipleProtocolInterfaces; + + // + // 32-bit CRC Services + // + EFI_CALCULATE_CRC32 CalculateCrc32; + + // + // Miscellaneous Services + // + EFI_COPY_MEM CopyMem; + EFI_SET_MEM SetMem; + + EFI_CREATE_EVENT_EX CreateEventEx; +} EFI_BOOT_SERVICES; + +// +// Contains a set of GUID/pointer pairs comprised of the ConfigurationTable field in the +// EFI System Table. +// +typedef struct{ + EFI_GUID VendorGuid; + VOID *VendorTable; +} EFI_CONFIGURATION_TABLE; + +struct _EFI_SYSTEM_TABLE { + EFI_TABLE_HEADER Hdr; + CHAR16 *FirmwareVendor; + UINT32 FirmwareRevision; + EFI_HANDLE ConsoleInHandle; + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn; + EFI_HANDLE ConsoleOutHandle; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut; + EFI_HANDLE StandardErrorHandle; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr; + EFI_RUNTIME_SERVICES *RuntimeServices; + EFI_BOOT_SERVICES *BootServices; + UINTN NumberOfTableEntries; + EFI_CONFIGURATION_TABLE *ConfigurationTable; +}; + +// +// EFI Load Options Attributes +// +#define LOAD_OPTION_ACTIVE 0x00000001 +#define LOAD_OPTION_FORCE_RECONNECT 0x00000002 +#define LOAD_OPTION_HIDDEN 0x00000008 +#define LOAD_OPTION_CATEGORY 0x00001F00 + +#define LOAD_OPTION_CATEGORY_BOOT 0x00000000 +#define LOAD_OPTION_CATEGORY_APP 0x00000100 + +#define EFI_BOOT_OPTION_SUPPORT_KEY 0x00000001 +#define EFI_BOOT_OPTION_SUPPORT_APP 0x00000002 +#define EFI_BOOT_OPTION_SUPPORT_COUNT 0x00000300 + +typedef union { + struct { + UINT32 Revision : 8; + UINT32 ShiftPressed : 1; + UINT32 ControlPressed : 1; + UINT32 AltPressed : 1; + UINT32 LogoPressed : 1; + UINT32 MenuPressed : 1; + UINT32 SysReqPessed : 1; + UINT32 Reserved : 16; + UINT32 InputKeyCount : 2; + } Options; + UINT32 PackedValue; +} HOT_KEY_EFI_KEY_DATA; + +typedef struct { + HOT_KEY_EFI_KEY_DATA KeyOptions; + UINT32 BootOptionCrc; + UINT16 BootOption; +//EFI_INPUT_KEY Keys[]; +} EFI_KEY_OPTION; + +#define EFI_KEY_OPTION_SHIFT 0x00000001 +#define EFI_KEY_OPTION_CONTROL 0x00000002 +#define EFI_KEY_OPTION_ALT 0x00000004 +#define EFI_KEY_OPTION_LOGO 0x00000008 +#define EFI_KEY_OPTION_MENU 0x00000010 +#define EFI_KEY_OPTION_SYSREQ 0x00000020 +#define EFI_KEY_CODE_COUNT 0x00000300 + + +// +// EFI File location to boot from on removable media devices +// +#define EFI_REMOVABLE_MEDIA_FILE_NAME_IA32 L"\\EFI\\BOOT\\BOOTIA32.EFI" +#define EFI_REMOVABLE_MEDIA_FILE_NAME_IA64 L"\\EFI\\BOOT\\BOOTIA64.EFI" +#define EFI_REMOVABLE_MEDIA_FILE_NAME_X64 L"\\EFI\\BOOT\\BOOTX64.EFI" +#define EFI_REMOVABLE_MEDIA_FILE_NAME_EBC L"\\EFI\\BOOT\\BOOTEBC.EFI" + +#if defined (MDE_CPU_IA32) + #define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_IA32 +#elif defined (MDE_CPU_IPF) + #define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_IA64 +#elif defined (MDE_CPU_X64) + #define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_X64 +#elif defined (MDE_CPU_EBC) + #define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_EBC +#else + #error Unknown Processor Type +#endif + +#include +#include +#include + +#endif diff --git a/gpxe/src/include/gpxe/efi/efi.h b/gpxe/src/include/gpxe/efi/efi.h new file mode 100644 index 00000000..0643066f --- /dev/null +++ b/gpxe/src/include/gpxe/efi/efi.h @@ -0,0 +1,89 @@ +#ifndef _EFI_H +#define _EFI_H + +/** @file + * + * EFI API + * + * The intention is to include near-verbatim copies of the EFI headers + * required by gPXE. This is achieved using the import.pl script in + * this directory. Run the import script to update the local copies + * of the headers: + * + * ./import.pl /path/to/edk2/edk2 + * + * where /path/to/edk2/edk2 is the path to your local checkout of the + * EFI Development Kit. + * + * Note that import.pl will modify any #include lines in each imported + * header to reflect its new location within the gPXE tree. It will + * also tidy up the file by removing carriage return characters and + * trailing whitespace. + * + * + * At the time of writing, there are a few other modifications to + * these headers that are present in my personal edk2 tree, that are + * not yet committed back to the main edk2 repository. These + * modifications are fixes for compilation on case-dependent + * filesystems, compilation under -mrtd and -mregparm=3, etc. + */ + +/* Include the top-level EFI header file */ +#include + +/* Reset any trailing #pragma pack directives */ +#pragma pack() + +#include +#include + +/** An EFI protocol used by gPXE */ +struct efi_protocol { + union { + /** EFI protocol GUID */ + EFI_GUID guid; + /** UUID structure understood by gPXE */ + union uuid uuid; + } u; + /** Variable containing pointer to protocol structure */ + void **protocol; +}; + +/** Declare an EFI protocol used by gPXE */ +#define __efi_protocol \ + __table ( struct efi_protocol, efi_protocols, 01 ) + +/** Declare an EFI protocol to be required by gPXE + * + * @v _protocol EFI protocol name + * @v _ptr Pointer to protocol instance + */ +#define EFI_REQUIRE_PROTOCOL( _protocol, _ptr ) \ + struct efi_protocol __ ## _protocol __efi_protocol = { \ + .u.guid = _protocol ## _GUID, \ + .protocol = ( ( void ** ) ( void * ) \ + ( ( (_ptr) == ( ( _protocol ** ) NULL ) ) ? \ + (_ptr) : (_ptr) ) ), \ + } + +/** Convert a gPXE status code to an EFI status code + * + * FIXME: actually perform some kind of conversion. gPXE error codes + * will be detected as EFI error codes; both have the top bit set, and + * the success return code is zero for both. Anything that just + * reports a numerical error will be OK, anything attempting to + * interpret the value or to display a text equivalent will be + * screwed. + */ +#define RC_TO_EFIRC( rc ) (rc) + +/** Convert an EFI status code to a gPXE status code + * + * FIXME: as above + */ +#define EFIRC_TO_RC( efirc ) (efirc) + +extern EFI_HANDLE efi_image_handle; +extern EFI_SYSTEM_TABLE *efi_systab; + +#endif /* _EFI_H */ diff --git a/gpxe/src/include/gpxe/efi/efi_io.h b/gpxe/src/include/gpxe/efi/efi_io.h new file mode 100644 index 00000000..93f559db --- /dev/null +++ b/gpxe/src/include/gpxe/efi/efi_io.h @@ -0,0 +1,178 @@ +#ifndef _GPXE_EFI_IO_H +#define _GPXE_EFI_IO_H + +/** @file + * + * gPXE I/O API for EFI + * + * EFI runs with flat physical addressing, so the various mappings + * between virtual addresses, I/O addresses and bus addresses are all + * no-ops. I/O is handled using the EFI_CPU_IO_PROTOCOL. + */ + +#ifdef IOAPI_EFI +#define IOAPI_PREFIX_efi +#else +#define IOAPI_PREFIX_efi __efi_ +#endif + +extern unsigned long long efi_ioread ( volatile void *io_addr, + size_t size ); +extern void efi_iowrite ( unsigned long long data, volatile void *io_addr, + size_t size ); +extern void efi_ioreads ( volatile void *io_addr, void *data, + size_t size, unsigned int count ); +extern void efi_iowrites ( volatile void *io_addr, const void *data, + size_t size, unsigned int count ); + +/* + * Physical<->Bus and Bus<->I/O address mappings + * + * EFI runs with flat physical addressing, so these are all no-ops. + * + */ + +static inline __always_inline unsigned long +IOAPI_INLINE ( efi, phys_to_bus ) ( unsigned long phys_addr ) { + return phys_addr; +} + +static inline __always_inline unsigned long +IOAPI_INLINE ( efi, bus_to_phys ) ( unsigned long bus_addr ) { + return bus_addr; +} + +static inline __always_inline void * +IOAPI_INLINE ( efi, ioremap ) ( unsigned long bus_addr, size_t len __unused ) { + return ( ( void * ) bus_addr ); +} + +static inline __always_inline void +IOAPI_INLINE ( efi, iounmap ) ( volatile const void *io_addr __unused ) { + /* Nothing to do */ +} + +static inline __always_inline unsigned long +IOAPI_INLINE ( efi, io_to_bus ) ( volatile const void *io_addr ) { + return ( ( unsigned long ) io_addr ); +} + +/* + * I/O functions + * + */ + +static inline __always_inline uint8_t +IOAPI_INLINE ( efi, readb ) ( volatile uint8_t *io_addr ) { + return efi_ioread ( io_addr, sizeof ( *io_addr ) ); +} + +static inline __always_inline uint16_t +IOAPI_INLINE ( efi, readw ) ( volatile uint16_t *io_addr ) { + return efi_ioread ( io_addr, sizeof ( *io_addr ) ); +} + +static inline __always_inline uint32_t +IOAPI_INLINE ( efi, readl ) ( volatile uint32_t *io_addr ) { + return efi_ioread ( io_addr, sizeof ( *io_addr ) ); +} + +static inline __always_inline uint64_t +IOAPI_INLINE ( efi, readq ) ( volatile uint64_t *io_addr ) { + return efi_ioread ( io_addr, sizeof ( *io_addr ) ); +} + +static inline __always_inline void +IOAPI_INLINE ( efi, writeb ) ( uint8_t data, volatile uint8_t *io_addr ) { + efi_iowrite ( data, io_addr, sizeof ( *io_addr ) ); +} + +static inline __always_inline void +IOAPI_INLINE ( efi, writew ) ( uint16_t data, volatile uint16_t *io_addr ) { + efi_iowrite ( data, io_addr, sizeof ( *io_addr ) ); +} + +static inline __always_inline void +IOAPI_INLINE ( efi, writel ) ( uint32_t data, volatile uint32_t *io_addr ) { + efi_iowrite ( data, io_addr, sizeof ( *io_addr ) ); +} + +static inline __always_inline void +IOAPI_INLINE ( efi, writeq ) ( uint64_t data, volatile uint64_t *io_addr ) { + efi_iowrite ( data, io_addr, sizeof ( *io_addr ) ); +} + +static inline __always_inline uint8_t +IOAPI_INLINE ( efi, inb ) ( volatile uint8_t *io_addr ) { + return efi_ioread ( io_addr, sizeof ( *io_addr ) ); +} + +static inline __always_inline uint16_t +IOAPI_INLINE ( efi, inw ) ( volatile uint16_t *io_addr ) { + return efi_ioread ( io_addr, sizeof ( *io_addr ) ); +} + +static inline __always_inline uint32_t +IOAPI_INLINE ( efi, inl ) ( volatile uint32_t *io_addr ) { + return efi_ioread ( io_addr, sizeof ( *io_addr ) ); +} + +static inline __always_inline void +IOAPI_INLINE ( efi, outb ) ( uint8_t data, volatile uint8_t *io_addr ) { + efi_iowrite ( data, io_addr, sizeof ( *io_addr ) ); +} + +static inline __always_inline void +IOAPI_INLINE ( efi, outw ) ( uint16_t data, volatile uint16_t *io_addr ) { + efi_iowrite ( data, io_addr, sizeof ( *io_addr ) ); +} + +static inline __always_inline void +IOAPI_INLINE ( efi, outl ) ( uint32_t data, volatile uint32_t *io_addr ) { + efi_iowrite ( data, io_addr, sizeof ( *io_addr ) ); +} + +static inline __always_inline void +IOAPI_INLINE ( efi, insb ) ( volatile uint8_t *io_addr, uint8_t *data, + unsigned int count ) { + efi_ioreads ( io_addr, data, sizeof ( *io_addr ), count ); +} + +static inline __always_inline void +IOAPI_INLINE ( efi, insw ) ( volatile uint16_t *io_addr, uint16_t *data, + unsigned int count ) { + efi_ioreads ( io_addr, data, sizeof ( *io_addr ), count ); +} + +static inline __always_inline void +IOAPI_INLINE ( efi, insl ) ( volatile uint32_t *io_addr, uint32_t *data, + unsigned int count ) { + efi_ioreads ( io_addr, data, sizeof ( *io_addr ), count ); +} + +static inline __always_inline void +IOAPI_INLINE ( efi, outsb ) ( volatile uint8_t *io_addr, const uint8_t *data, + unsigned int count ) { + efi_iowrites ( io_addr, data, sizeof ( *io_addr ), count ); +} + +static inline __always_inline void +IOAPI_INLINE ( efi, outsw ) ( volatile uint16_t *io_addr, const uint16_t *data, + unsigned int count ) { + efi_iowrites ( io_addr, data, sizeof ( *io_addr ), count ); +} + +static inline __always_inline void +IOAPI_INLINE ( efi, outsl ) ( volatile uint32_t *io_addr, const uint32_t *data, + unsigned int count ) { + efi_iowrites ( io_addr, data, sizeof ( *io_addr ), count ); +} + +static inline __always_inline void +IOAPI_INLINE ( efi, mb ) ( void ) { + /* Do nothing; EFI readl()/writel() calls already act as + * memory barriers. + */ +} + +#endif /* _GPXE_EFI_IO_H */ diff --git a/gpxe/src/include/gpxe/efi/efi_pci.h b/gpxe/src/include/gpxe/efi/efi_pci.h new file mode 100644 index 00000000..8be331ab --- /dev/null +++ b/gpxe/src/include/gpxe/efi/efi_pci.h @@ -0,0 +1,146 @@ +#ifndef _GPXE_EFI_PCI_H +#define _GPXE_EFI_PCI_H + +/** @file + * + * gPXE PCI I/O API for EFI + * + */ + +#ifdef PCIAPI_EFI +#define PCIAPI_PREFIX_efi +#else +#define PCIAPI_PREFIX_efi __efi_ +#endif + +/* EFI PCI width codes defined by EFI spec */ +#define EFIPCI_WIDTH_BYTE 0 +#define EFIPCI_WIDTH_WORD 1 +#define EFIPCI_WIDTH_DWORD 2 + +#define EFIPCI_LOCATION( _offset, _width ) \ + ( (_offset) | ( (_width) << 16 ) ) +#define EFIPCI_OFFSET( _location ) ( (_location) & 0xffff ) +#define EFIPCI_WIDTH( _location ) ( (_location) >> 16 ) + +struct pci_device; + +extern int efipci_read ( struct pci_device *pci, unsigned long location, + void *value ); +extern int efipci_write ( struct pci_device *pci, unsigned long location, + unsigned long value ); + +/** + * Determine maximum PCI bus number within system + * + * @ret max_bus Maximum bus number + */ +static inline __always_inline int +PCIAPI_INLINE ( efi, pci_max_bus ) ( void ) { + /* No way to work this out via EFI */ + return 0xff; +} + +/** + * Read byte from PCI configuration space via EFI + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( efi, pci_read_config_byte ) ( struct pci_device *pci, + unsigned int where, + uint8_t *value ) { + return efipci_read ( pci, + EFIPCI_LOCATION ( where, EFIPCI_WIDTH_BYTE ), + value ); +} + +/** + * Read word from PCI configuration space via EFI + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( efi, pci_read_config_word ) ( struct pci_device *pci, + unsigned int where, + uint16_t *value ) { + return efipci_read ( pci, + EFIPCI_LOCATION ( where, EFIPCI_WIDTH_WORD ), + value ); +} + +/** + * Read dword from PCI configuration space via EFI + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( efi, pci_read_config_dword ) ( struct pci_device *pci, + unsigned int where, + uint32_t *value ) { + return efipci_read ( pci, + EFIPCI_LOCATION ( where, EFIPCI_WIDTH_DWORD ), + value ); +} + +/** + * Write byte to PCI configuration space via EFI + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( efi, pci_write_config_byte ) ( struct pci_device *pci, + unsigned int where, + uint8_t value ) { + return efipci_write ( pci, + EFIPCI_LOCATION ( where, EFIPCI_WIDTH_BYTE ), + value ); +} + +/** + * Write word to PCI configuration space via EFI + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( efi, pci_write_config_word ) ( struct pci_device *pci, + unsigned int where, + uint16_t value ) { + return efipci_write ( pci, + EFIPCI_LOCATION ( where, EFIPCI_WIDTH_WORD ), + value ); +} + +/** + * Write dword to PCI configuration space via EFI + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( efi, pci_write_config_dword ) ( struct pci_device *pci, + unsigned int where, + uint32_t value ) { + return efipci_write ( pci, + EFIPCI_LOCATION ( where, EFIPCI_WIDTH_DWORD ), + value ); +} + +#endif /* _GPXE_EFI_PCI_H */ diff --git a/gpxe/src/include/gpxe/efi/efi_timer.h b/gpxe/src/include/gpxe/efi/efi_timer.h new file mode 100644 index 00000000..c332c9d6 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/efi_timer.h @@ -0,0 +1,16 @@ +#ifndef _GPXE_EFI_TIMER_H +#define _GPXE_EFI_TIMER_H + +/** @file + * + * gPXE timer API for EFI + * + */ + +#ifdef TIMER_EFI +#define TIMER_PREFIX_efi +#else +#define TIMER_PREFIX_efi __efi_ +#endif + +#endif /* _GPXE_EFI_TIMER_H */ diff --git a/gpxe/src/include/gpxe/efi/efi_uaccess.h b/gpxe/src/include/gpxe/efi/efi_uaccess.h new file mode 100644 index 00000000..bae5fb41 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/efi_uaccess.h @@ -0,0 +1,88 @@ +#ifndef _GPXE_EFI_UACCESS_H +#define _GPXE_EFI_UACCESS_H + +/** @file + * + * gPXE user access API for EFI + * + * EFI runs with flat physical addressing, so the various mappings + * between virtual addresses, I/O addresses and bus addresses are all + * no-ops. + */ + +#ifdef UACCESS_EFI +#define UACCESS_PREFIX_efi +#else +#define UACCESS_PREFIX_efi __efi_ +#endif + +/** + * Convert physical address to user pointer + * + * @v phys_addr Physical address + * @ret userptr User pointer + */ +static inline __always_inline userptr_t +UACCESS_INLINE ( efi, phys_to_user ) ( unsigned long phys_addr ) { + return phys_addr; +} + +/** + * Convert user buffer to physical address + * + * @v userptr User pointer + * @v offset Offset from user pointer + * @ret phys_addr Physical address + */ +static inline __always_inline unsigned long +UACCESS_INLINE ( efi, user_to_phys ) ( userptr_t userptr, off_t offset ) { + return ( userptr + offset ); +} + +static inline __always_inline userptr_t +UACCESS_INLINE ( efi, virt_to_user ) ( volatile const void *addr ) { + return trivial_virt_to_user ( addr ); +} + +static inline __always_inline void * +UACCESS_INLINE ( efi, user_to_virt ) ( userptr_t userptr, off_t offset ) { + return trivial_user_to_virt ( userptr, offset ); +} + +static inline __always_inline userptr_t +UACCESS_INLINE ( efi, userptr_add ) ( userptr_t userptr, off_t offset ) { + return trivial_userptr_add ( userptr, offset ); +} + +static inline __always_inline void +UACCESS_INLINE ( efi, memcpy_user ) ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, + size_t len ) { + trivial_memcpy_user ( dest, dest_off, src, src_off, len ); +} + +static inline __always_inline void +UACCESS_INLINE ( efi, memmove_user ) ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, + size_t len ) { + trivial_memmove_user ( dest, dest_off, src, src_off, len ); +} + +static inline __always_inline void +UACCESS_INLINE ( efi, memset_user ) ( userptr_t buffer, off_t offset, + int c, size_t len ) { + trivial_memset_user ( buffer, offset, c, len ); +} + +static inline __always_inline size_t +UACCESS_INLINE ( efi, strlen_user ) ( userptr_t buffer, off_t offset ) { + return trivial_strlen_user ( buffer, offset ); +} + +static inline __always_inline off_t +UACCESS_INLINE ( efi, memchr_user ) ( userptr_t buffer, off_t offset, + int c, size_t len ) { + return trivial_memchr_user ( buffer, offset, c, len ); +} + +#endif /* _GPXE_EFI_UACCESS_H */ diff --git a/gpxe/src/include/gpxe/efi/efi_umalloc.h b/gpxe/src/include/gpxe/efi/efi_umalloc.h new file mode 100644 index 00000000..def17b2d --- /dev/null +++ b/gpxe/src/include/gpxe/efi/efi_umalloc.h @@ -0,0 +1,16 @@ +#ifndef _GPXE_EFI_UMALLOC_H +#define _GPXE_EFI_UMALLOC_H + +/** @file + * + * gPXE user memory allocation API for EFI + * + */ + +#ifdef UMALLOC_EFI +#define UMALLOC_PREFIX_efi +#else +#define UMALLOC_PREFIX_efi __efi_ +#endif + +#endif /* _GPXE_EFI_UMALLOC_H */ diff --git a/gpxe/src/include/gpxe/efi/import.pl b/gpxe/src/include/gpxe/efi/import.pl new file mode 100755 index 00000000..16993944 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/import.pl @@ -0,0 +1,75 @@ +#!/usr/bin/perl -w + +use File::Spec::Functions qw ( :ALL ); +use File::Find; +use File::Path; +use FindBin; +use strict; +use warnings; + +sub try_import_file { + my $gpxedir = shift; + my $edkdirs = shift; + my $filename = shift; + + # Skip everything except headers + return unless $filename =~ /\.h$/; + print "$filename..."; + + my $outfile = catfile ( $gpxedir, $filename ); + foreach my $edkdir ( @$edkdirs ) { + my $infile = catfile ( $edkdir, $filename ); + if ( -e $infile ) { + # We have found a matching source file - import it + print "$infile\n"; + open my $infh, "<$infile" or die "Could not open $infile: $!\n"; + ( undef, my $outdir, undef ) = splitpath ( $outfile ); + mkpath ( $outdir ); + open my $outfh, ">$outfile" or die "Could not open $outfile: $!\n"; + my @dependencies = (); + while ( <$infh> ) { + # Strip CR and trailing whitespace + s/\r//g; + s/\s*$//g; + chomp; + # Update include lines, and record included files + if ( s/^\#include\s+[<\"](\S+)[>\"]/\#include / ) { + push @dependencies, $1; + } + print $outfh "$_\n"; + } + close $outfh; + close $infh; + # Recurse to handle any included files that we don't already have + foreach my $dependency ( @dependencies ) { + if ( ! -e catfile ( $gpxedir, $dependency ) ) { + print "...following dependency on $dependency\n"; + try_import_file ( $gpxedir, $edkdirs, $dependency ); + } + } + return; + } + } + print "no equivalent found\n"; +} + +# Identify edk import directories +die "Syntax $0 /path/to/edk2/edk2\n" unless @ARGV == 1; +my $edktop = shift; +die "Directory \"$edktop\" does not appear to contain the EFI EDK2\n" + unless -e catfile ( $edktop, "MdePkg" ); +my $edkdirs = [ catfile ( $edktop, "MdePkg/Include" ), + catfile ( $edktop, "IntelFrameworkPkg/Include" ) ]; + +# Identify gPXE EFI includes directory +my $gpxedir = $FindBin::Bin; +die "Directory \"$gpxedir\" does not appear to contain the gPXE EFI includes\n" + unless -e catfile ( $gpxedir, "../../../include/gpxe/efi" ); + +print "Importing EFI headers into $gpxedir\nfrom "; +print join ( "\n and ", @$edkdirs )."\n"; + +# Import headers +find ( { wanted => sub { + try_import_file ( $gpxedir, $edkdirs, abs2rel ( $_, $gpxedir ) ); +}, no_chdir => 1 }, $gpxedir ); diff --git a/gpxe/src/include/gpxe/errfile.h b/gpxe/src/include/gpxe/errfile.h index ca0abebf..c851c7d5 100644 --- a/gpxe/src/include/gpxe/errfile.h +++ b/gpxe/src/include/gpxe/errfile.h @@ -106,10 +106,12 @@ #define ERRFILE_e1000_hw ( ERRFILE_DRIVER | 0x00490000 ) #define ERRFILE_mtnic ( ERRFILE_DRIVER | 0x004a0000 ) #define ERRFILE_phantom ( ERRFILE_DRIVER | 0x004b0000 ) +#define ERRFILE_ne2k_isa ( ERRFILE_DRIVER | 0x004c0000 ) #define ERRFILE_scsi ( ERRFILE_DRIVER | 0x00700000 ) #define ERRFILE_arbel ( ERRFILE_DRIVER | 0x00710000 ) #define ERRFILE_hermon ( ERRFILE_DRIVER | 0x00720000 ) +#define ERRFILE_linda ( ERRFILE_DRIVER | 0x00730000 ) #define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 ) #define ERRFILE_arp ( ERRFILE_NET | 0x00010000 ) @@ -134,11 +136,14 @@ #define ERRFILE_netdev_settings ( ERRFILE_NET | 0x00140000 ) #define ERRFILE_dhcppkt ( ERRFILE_NET | 0x00150000 ) #define ERRFILE_slam ( ERRFILE_NET | 0x00160000 ) +#define ERRFILE_ib_sma ( ERRFILE_NET | 0x00170000 ) +#define ERRFILE_ib_packet ( ERRFILE_NET | 0x00180000 ) #define ERRFILE_image ( ERRFILE_IMAGE | 0x00000000 ) #define ERRFILE_elf ( ERRFILE_IMAGE | 0x00010000 ) #define ERRFILE_script ( ERRFILE_IMAGE | 0x00020000 ) #define ERRFILE_segment ( ERRFILE_IMAGE | 0x00030000 ) +#define ERRFILE_efi_image ( ERRFILE_IMAGE | 0x00040000 ) #define ERRFILE_asn1 ( ERRFILE_OTHER | 0x00000000 ) #define ERRFILE_chap ( ERRFILE_OTHER | 0x00010000 ) @@ -156,6 +161,8 @@ #define ERRFILE_tls ( ERRFILE_OTHER | 0x000d0000 ) #define ERRFILE_ifmgmt ( ERRFILE_OTHER | 0x000e0000 ) #define ERRFILE_iscsiboot ( ERRFILE_OTHER | 0x000f0000 ) +#define ERRFILE_efi_pci ( ERRFILE_OTHER | 0x00100000 ) +#define ERRFILE_efi_snp ( ERRFILE_OTHER | 0x00110000 ) /** @} */ diff --git a/gpxe/src/include/gpxe/ethernet.h b/gpxe/src/include/gpxe/ethernet.h index 158fe066..ff0fd6c1 100644 --- a/gpxe/src/include/gpxe/ethernet.h +++ b/gpxe/src/include/gpxe/ethernet.h @@ -9,6 +9,7 @@ #include #include +#include extern struct ll_protocol ethernet_protocol; @@ -26,6 +27,7 @@ static inline struct net_device * alloc_etherdev ( size_t priv_size ) { netdev = alloc_netdev ( priv_size ); if ( netdev ) { netdev->ll_protocol = ðernet_protocol; + netdev->max_pkt_len = ETH_FRAME_LEN; } return netdev; } diff --git a/gpxe/src/include/gpxe/features.h b/gpxe/src/include/gpxe/features.h index 107ff085..e4d29213 100644 --- a/gpxe/src/include/gpxe/features.h +++ b/gpxe/src/include/gpxe/features.h @@ -46,6 +46,7 @@ #define DHCP_EB_FEATURE_PXE 0x21 /**< PXE format */ #define DHCP_EB_FEATURE_ELF 0x22 /**< ELF format */ #define DHCP_EB_FEATURE_COMBOOT 0x23 /**< COMBOOT format */ +#define DHCP_EB_FEATURE_EFI 0x24 /**< EFI format */ /** @} */ diff --git a/gpxe/src/include/gpxe/i2c.h b/gpxe/src/include/gpxe/i2c.h index bfaee8fb..9d229546 100644 --- a/gpxe/src/include/gpxe/i2c.h +++ b/gpxe/src/include/gpxe/i2c.h @@ -8,6 +8,7 @@ */ #include +#include /** An I2C device * @@ -15,10 +16,35 @@ * is accessed via an I2C interface. */ struct i2c_device { - /** Address of this device */ - unsigned int address; - /** Flag indicating a ten-bit address format */ - int tenbit; + /** Address of this device + * + * The actual address sent on the bus will look like + * + * + * + * The "word address overflow" is any excess bits from the + * word address, i.e. any portion that does not fit within the + * defined word address length. + */ + unsigned int dev_addr; + /** Device address length, in bytes + * + * This is the number of bytes that comprise the device + * address, defined to be the portion that terminates with the + * read/write bit. + */ + unsigned int dev_addr_len; + /** Word adddress length, in bytes + * + * This is the number of bytes that comprise the word address, + * defined to be the portion that starts after the read/write + * bit and ends before the first data byte. + * + * For some devices, this length will be zero (i.e. the word + * address is contained entirely within the "word address + * overflow"). + */ + unsigned int word_addr_len; }; /** An I2C interface @@ -91,6 +117,9 @@ enum { /** Delay required for bit-bashing operation */ #define I2C_UDELAY 5 +/** Maximum number of cycles to use when attempting a bus reset */ +#define I2C_RESET_MAX_CYCLES 32 + /** * Check presence of I2C device * @@ -106,6 +135,35 @@ static inline int i2c_check_presence ( struct i2c_interface *i2c, return i2c->write ( i2c, i2cdev, 0, NULL, 0 ); } -extern void init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit ); +extern int init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit, + struct bit_basher_operations *bash_op ); + +/** + * Initialise generic I2C EEPROM device + * + * @v i2cdev I2C device + */ +static inline __always_inline void +init_i2c_eeprom ( struct i2c_device *i2cdev, unsigned int dev_addr ) { + i2cdev->dev_addr = dev_addr; + i2cdev->dev_addr_len = 1; + i2cdev->word_addr_len = 1; +} + +/** + * Initialise Atmel AT24C11 + * + * @v i2cdev I2C device + */ +static inline __always_inline void +init_at24c11 ( struct i2c_device *i2cdev ) { + /* This chip has no device address; it must be the only chip + * on the bus. The word address is contained entirely within + * the device address field. + */ + i2cdev->dev_addr = 0; + i2cdev->dev_addr_len = 1; + i2cdev->word_addr_len = 0; +} #endif /* _GPXE_I2C_H */ diff --git a/gpxe/src/include/gpxe/ib_mad.h b/gpxe/src/include/gpxe/ib_mad.h new file mode 100644 index 00000000..6c4e95b7 --- /dev/null +++ b/gpxe/src/include/gpxe/ib_mad.h @@ -0,0 +1,364 @@ +#ifndef _GPXE_IB_MAD_H +#define _GPXE_IB_MAD_H + +/** @file + * + * Infiniband management datagrams + * + */ + +#include +#include + +/***************************************************************************** + * + * Subnet management MADs + * + ***************************************************************************** + */ + +/** A subnet management header + * + * Defined in sections 14.2.1.1 and 14.2.1.2 of the IBA. + */ +struct ib_smp_hdr { + uint64_t mkey; + uint16_t slid; + uint16_t dlid; + uint8_t reserved[28]; +} __attribute__ (( packed )); + +/** Subnet management class version */ +#define IB_SMP_CLASS_VERSION 1 + +/** Subnet management direction bit + * + * This bit resides in the "status" field in the MAD header. + */ +#define IB_SMP_STATUS_D_INBOUND 0x8000 + +/* Subnet management attributes */ +#define IB_SMP_ATTR_NOTICE 0x0002 +#define IB_SMP_ATTR_NODE_DESC 0x0010 +#define IB_SMP_ATTR_NODE_INFO 0x0011 +#define IB_SMP_ATTR_SWITCH_INFO 0x0012 +#define IB_SMP_ATTR_GUID_INFO 0x0014 +#define IB_SMP_ATTR_PORT_INFO 0x0015 +#define IB_SMP_ATTR_PKEY_TABLE 0x0016 +#define IB_SMP_ATTR_SL_TO_VL_TABLE 0x0017 +#define IB_SMP_ATTR_VL_ARB_TABLE 0x0018 +#define IB_SMP_ATTR_LINEAR_FORWARD_TABLE 0x0019 +#define IB_SMP_ATTR_RANDOM_FORWARD_TABLE 0x001A +#define IB_SMP_ATTR_MCAST_FORWARD_TABLE 0x001B +#define IB_SMP_ATTR_SM_INFO 0x0020 +#define IB_SMP_ATTR_VENDOR_DIAG 0x0030 +#define IB_SMP_ATTR_LED_INFO 0x0031 +#define IB_SMP_ATTR_VENDOR_MASK 0xFF00 + +/** + * A Node Description attribute + * + * Defined in section 14.2.5.2 of the IBA + */ +struct ib_node_desc { + char node_string[64]; +} __attribute__ (( packed )); + +/** A Node Information attribute + * + * Defined in section 14.2.5.3 of the IBA. + */ +struct ib_node_info { + uint8_t base_version; + uint8_t class_version; + uint8_t node_type; + uint8_t num_ports; + uint8_t sys_guid[8]; + uint8_t node_guid[8]; + uint8_t port_guid[8]; + uint16_t partition_cap; + uint16_t device_id; + uint32_t revision; + uint8_t local_port_num; + uint8_t vendor_id[3]; +} __attribute__ ((packed)); + +#define IB_NODE_TYPE_HCA 0x01 +#define IB_NODE_TYPE_SWITCH 0x02 +#define IB_NODE_TYPE_ROUTER 0x03 + +/** A GUID Information attribute + * + * Defined in section 14.2.5.5 of the IBA. + */ +struct ib_guid_info { + uint8_t guid[8][8]; +} __attribute__ (( packed )); + +/** A Port Information attribute + * + * Defined in section 14.2.5.6 of the IBA. + */ +struct ib_port_info { + uint64_t mkey; + uint8_t gid_prefix[8]; + uint16_t lid; + uint16_t mastersm_lid; + uint32_t cap_mask; + uint16_t diag_code; + uint16_t mkey_lease_period; + uint8_t local_port_num; + uint8_t link_width_enabled; + uint8_t link_width_supported; + uint8_t link_width_active; + uint8_t link_speed_supported__port_state; + uint8_t port_phys_state__link_down_def_state; + uint8_t mkey_prot_bits__lmc; + uint8_t link_speed_active__link_speed_enabled; + uint8_t neighbour_mtu__mastersm_sl; + uint8_t vl_cap__init_type; + uint8_t vl_high_limit; + uint8_t vl_arbitration_high_cap; + uint8_t vl_arbitration_low_cap; + uint8_t init_type_reply__mtu_cap; + uint8_t vl_stall_count__hoq_life; + uint8_t operational_vls__enforcement; + uint16_t mkey_violations; + uint16_t pkey_violations; + uint16_t qkey_violations; + uint8_t guid_cap; + uint8_t client_reregister__subnet_timeout; + uint8_t resp_time_value; + uint8_t local_phy_errors__overrun_errors; + uint16_t max_credit_hint; + uint32_t link_round_trip_latency; +} __attribute__ (( packed )); + +#define IB_LINK_WIDTH_1X 0x01 +#define IB_LINK_WIDTH_4X 0x02 +#define IB_LINK_WIDTH_8X 0x04 +#define IB_LINK_WIDTH_12X 0x08 + +#define IB_LINK_SPEED_SDR 0x01 +#define IB_LINK_SPEED_DDR 0x02 +#define IB_LINK_SPEED_QDR 0x04 + +#define IB_PORT_STATE_DOWN 0x01 +#define IB_PORT_STATE_INIT 0x02 +#define IB_PORT_STATE_ARMED 0x03 +#define IB_PORT_STATE_ACTIVE 0x04 + +#define IB_PORT_PHYS_STATE_SLEEP 0x01 +#define IB_PORT_PHYS_STATE_POLLING 0x02 + +#define IB_MTU_256 0x01 +#define IB_MTU_512 0x02 +#define IB_MTU_1024 0x03 +#define IB_MTU_2048 0x04 +#define IB_MTU_4096 0x05 + +#define IB_VL_0 0x01 +#define IB_VL_0_1 0x02 +#define IB_VL_0_3 0x03 +#define IB_VL_0_7 0x04 +#define IB_VL_0_14 0x05 + +/** A Partition Key Table attribute + * + * Defined in section 14.2.5.7 of the IBA. + */ +struct ib_pkey_table { + uint16_t pkey[32]; +} __attribute__ (( packed )); + +/** A subnet management attribute */ +union ib_smp_data { + struct ib_node_desc node_desc; + struct ib_node_info node_info; + struct ib_guid_info guid_info; + struct ib_port_info port_info; + struct ib_pkey_table pkey_table; + uint8_t bytes[64]; +} __attribute__ (( packed )); + +/** A subnet management directed route path */ +struct ib_smp_dr_path { + uint8_t hops[64]; +} __attribute__ (( packed )); + +/** Subnet management MAD class-specific data */ +struct ib_smp_class_specific { + uint8_t hop_pointer; + uint8_t hop_count; +} __attribute__ (( packed )); + +/***************************************************************************** + * + * Subnet administration MADs + * + ***************************************************************************** + */ + +struct ib_rmpp_hdr { + uint32_t raw[3]; +} __attribute__ (( packed )); + +struct ib_sa_hdr { + uint32_t sm_key[2]; + uint16_t reserved; + uint16_t attrib_offset; + uint32_t comp_mask[2]; +} __attribute__ (( packed )); + +#define IB_SA_ATTR_MC_MEMBER_REC 0x38 +#define IB_SA_ATTR_PATH_REC 0x35 + +struct ib_path_record { + uint32_t reserved0[2]; + struct ib_gid dgid; + struct ib_gid sgid; + uint16_t dlid; + uint16_t slid; + uint32_t hop_limit__flow_label__raw_traffic; + uint32_t pkey__numb_path__reversible__tclass; + uint8_t reserved1; + uint8_t reserved__sl; + uint8_t mtu_selector__mtu; + uint8_t rate_selector__rate; + uint32_t preference__packet_lifetime__packet_lifetime_selector; + uint32_t reserved2[35]; +} __attribute__ (( packed )); + +#define IB_SA_PATH_REC_DGID (1<<2) +#define IB_SA_PATH_REC_SGID (1<<3) + +struct ib_mc_member_record { + struct ib_gid mgid; + struct ib_gid port_gid; + uint32_t qkey; + uint16_t mlid; + uint8_t mtu_selector__mtu; + uint8_t tclass; + uint16_t pkey; + uint8_t rate_selector__rate; + uint8_t packet_lifetime_selector__packet_lifetime; + uint32_t sl__flow_label__hop_limit; + uint8_t scope__join_state; + uint8_t proxy_join__reserved; + uint16_t reserved0; + uint32_t reserved1[37]; +} __attribute__ (( packed )); + +#define IB_SA_MCMEMBER_REC_MGID (1<<0) +#define IB_SA_MCMEMBER_REC_PORT_GID (1<<1) +#define IB_SA_MCMEMBER_REC_QKEY (1<<2) +#define IB_SA_MCMEMBER_REC_MLID (1<<3) +#define IB_SA_MCMEMBER_REC_MTU_SELECTOR (1<<4) +#define IB_SA_MCMEMBER_REC_MTU (1<<5) +#define IB_SA_MCMEMBER_REC_TRAFFIC_CLASS (1<<6) +#define IB_SA_MCMEMBER_REC_PKEY (1<<7) +#define IB_SA_MCMEMBER_REC_RATE_SELECTOR (1<<8) +#define IB_SA_MCMEMBER_REC_RATE (1<<9) +#define IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME_SELECTOR (1<<10) +#define IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME (1<<11) +#define IB_SA_MCMEMBER_REC_SL (1<<12) +#define IB_SA_MCMEMBER_REC_FLOW_LABEL (1<<13) +#define IB_SA_MCMEMBER_REC_HOP_LIMIT (1<<14) +#define IB_SA_MCMEMBER_REC_SCOPE (1<<15) +#define IB_SA_MCMEMBER_REC_JOIN_STATE (1<<16) +#define IB_SA_MCMEMBER_REC_PROXY_JOIN (1<<17) + +union ib_sa_data { + struct ib_path_record path_record; + struct ib_mc_member_record mc_member_record; +} __attribute__ (( packed )); + +/***************************************************************************** + * + * MADs + * + ***************************************************************************** + */ + +/** Management datagram class_specific data */ +union ib_mad_class_specific { + uint16_t raw; + struct ib_smp_class_specific smp; +} __attribute__ (( packed )); + +/** A management datagram common header + * + * Defined in section 13.4.2 of the IBA. + */ +struct ib_mad_hdr { + uint8_t base_version; + uint8_t mgmt_class; + uint8_t class_version; + uint8_t method; + uint16_t status; + union ib_mad_class_specific class_specific; + uint32_t tid[2]; + uint16_t attr_id; + uint8_t reserved[2]; + uint32_t attr_mod; +} __attribute__ (( packed )); + +/* Management base version */ +#define IB_MGMT_BASE_VERSION 1 + +/* Management classes */ +#define IB_MGMT_CLASS_SUBN_LID_ROUTED 0x01 +#define IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE 0x81 +#define IB_MGMT_CLASS_SUBN_ADM 0x03 +#define IB_MGMT_CLASS_PERF_MGMT 0x04 +#define IB_MGMT_CLASS_BM 0x05 +#define IB_MGMT_CLASS_DEVICE_MGMT 0x06 +#define IB_MGMT_CLASS_CM 0x07 +#define IB_MGMT_CLASS_SNMP 0x08 +#define IB_MGMT_CLASS_VENDOR_RANGE2_START 0x30 +#define IB_MGMT_CLASS_VENDOR_RANGE2_END 0x4F + +/* Management methods */ +#define IB_MGMT_METHOD_GET 0x01 +#define IB_MGMT_METHOD_SET 0x02 +#define IB_MGMT_METHOD_GET_RESP 0x81 +#define IB_MGMT_METHOD_SEND 0x03 +#define IB_MGMT_METHOD_TRAP 0x05 +#define IB_MGMT_METHOD_REPORT 0x06 +#define IB_MGMT_METHOD_REPORT_RESP 0x86 +#define IB_MGMT_METHOD_TRAP_REPRESS 0x07 +#define IB_MGMT_METHOD_DELETE 0x15 + +/* Status codes */ +#define IB_MGMT_STATUS_OK 0x0000 +#define IB_MGMT_STATUS_BAD_VERSION 0x0001 +#define IB_MGMT_STATUS_UNSUPPORTED_METHOD 0x0002 +#define IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR 0x0003 +#define IB_MGMT_STATUS_INVALID_VALUE 0x0004 + +/** A subnet management MAD */ +struct ib_mad_smp { + struct ib_mad_hdr mad_hdr; + struct ib_smp_hdr smp_hdr; + union ib_smp_data smp_data; + struct ib_smp_dr_path initial_path; + struct ib_smp_dr_path return_path; +} __attribute__ (( packed )); + +/** A subnet administration MAD */ +struct ib_mad_sa { + struct ib_mad_hdr mad_hdr; + struct ib_rmpp_hdr rmpp_hdr; + struct ib_sa_hdr sa_hdr; + union ib_sa_data sa_data; +} __attribute__ (( packed )); + +/** A management datagram */ +union ib_mad { + struct ib_mad_hdr hdr; + struct ib_mad_smp smp; + struct ib_mad_sa sa; + uint8_t bytes[256]; +} __attribute__ (( packed )); + +#endif /* _GPXE_IB_MAD_H */ diff --git a/gpxe/src/include/gpxe/ib_packet.h b/gpxe/src/include/gpxe/ib_packet.h new file mode 100644 index 00000000..5374802c --- /dev/null +++ b/gpxe/src/include/gpxe/ib_packet.h @@ -0,0 +1,147 @@ +#ifndef _GPXE_IB_PACKET_H +#define _GPXE_IB_PACKET_H + +/** @file + * + * Infiniband packet format + * + */ + +struct ib_device; +struct ib_queue_pair; +struct ib_address_vector; +struct io_buffer; + +/** Half of an Infiniband Global Identifier */ +struct ib_gid_half { + uint8_t bytes[8]; +}; + +/** An Infiniband Global Identifier */ +struct ib_gid { + union { + uint8_t bytes[16]; + uint16_t words[8]; + uint32_t dwords[4]; + struct ib_gid_half half[2]; + } u; +}; + +/** An Infiniband Local Route Header */ +struct ib_local_route_header { + /** Virtual lane and link version */ + uint8_t vl__lver; + /** Service level and next link header */ + uint8_t sl__lnh; + /** Destination LID */ + uint16_t dlid; + /** Packet length */ + uint16_t length; + /** Source LID */ + uint16_t slid; +} __attribute__ (( packed )); + +/** Infiniband virtual lanes */ +enum ib_vl { + IB_VL_DEFAULT = 0, + IB_VL_SMP = 15, +}; + +/** An Infiniband Link Next Header value */ +enum ib_lnh { + IB_LNH_RAW = 0, + IB_LNH_IPv6 = 1, + IB_LNH_BTH = 2, + IB_LNH_GRH = 3 +}; + +/** Default Infiniband LID */ +#define IB_LID_NONE 0xffff + +/** Test for multicast LID */ +#define IB_LID_MULTICAST( lid ) ( ( (lid) >= 0xc000 ) && ( (lid) <= 0xfffe ) ) + +/** An Infiniband Global Route Header */ +struct ib_global_route_header { + /** IP version, traffic class, and flow label + * + * 4 bits : Version of the GRH + * 8 bits : Traffic class + * 20 bits : Flow label + */ + uint32_t ipver__tclass__flowlabel; + /** Payload length */ + uint16_t paylen; + /** Next header */ + uint8_t nxthdr; + /** Hop limit */ + uint8_t hoplmt; + /** Source GID */ + struct ib_gid sgid; + /** Destiniation GID */ + struct ib_gid dgid; +} __attribute__ (( packed )); + +#define IB_GRH_IPVER_IPv6 0x06 +#define IB_GRH_NXTHDR_IBA 0x1b + +/** An Infiniband Base Transport Header */ +struct ib_base_transport_header { + /** Opcode */ + uint8_t opcode; + /** Transport header version, pad count, migration and solicitation */ + uint8_t se__m__padcnt__tver; + /** Partition key */ + uint16_t pkey; + /** Destination queue pair */ + uint32_t dest_qp; + /** Packet sequence number and acknowledge request */ + uint32_t ack__psn; +} __attribute__ (( packed )); + +/** An Infiniband BTH opcode */ +enum ib_bth_opcode { + BTH_OPCODE_UD_SEND = 0x64, +}; + +/** Default Infiniband partition key */ +#define IB_PKEY_NONE 0xffff + +/** Subnet management queue pair number */ +#define IB_QPN_SMP 0 + +/** An Infiniband Datagram Extended Transport Header */ +struct ib_datagram_extended_transport_header { + /** Queue key */ + uint32_t qkey; + /** Source queue pair */ + uint32_t src_qp; +} __attribute__ (( packed )); + +/** All known IB header formats */ +union ib_headers { + struct ib_local_route_header lrh; + struct { + struct ib_local_route_header lrh; + struct ib_global_route_header grh; + struct ib_base_transport_header bth; + struct ib_datagram_extended_transport_header deth; + } __attribute__ (( packed )) lrh__grh__bth__deth; + struct { + struct ib_local_route_header lrh; + struct ib_base_transport_header bth; + struct ib_datagram_extended_transport_header deth; + } __attribute__ (( packed )) lrh__bth__deth; +} __attribute__ (( packed )); + +/** Maximum size required for IB headers */ +#define IB_MAX_HEADER_SIZE sizeof ( union ib_headers ) + +extern int ib_push ( struct ib_device *ibdev, struct io_buffer *iobuf, + struct ib_queue_pair *qp, size_t payload_len, + const struct ib_address_vector *av ); +extern int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf, + struct ib_queue_pair **qp, size_t *payload_len, + struct ib_address_vector *av ); + +#endif /* _GPXE_IB_PACKET_H */ diff --git a/gpxe/src/include/gpxe/ib_sma.h b/gpxe/src/include/gpxe/ib_sma.h new file mode 100644 index 00000000..835ed4ea --- /dev/null +++ b/gpxe/src/include/gpxe/ib_sma.h @@ -0,0 +1,63 @@ +#ifndef _GPXE_IB_SMA_H +#define _GPXE_IB_SMA_H + +/** @file + * + * Infiniband Subnet Management Agent + * + */ + +#include +#include + +/** Infiniband Subnet Management Agent operations */ +struct ib_sma_operations { + /** Set port information + * + * @v ibdev Infiniband device + * @v port_info New port information + */ + int ( * set_port_info ) ( struct ib_device *ibdev, + const struct ib_port_info *port_info ); +}; + +/** An Infiniband Subnet Management Agent */ +struct ib_sma { + /** Infiniband device */ + struct ib_device *ibdev; + /** SMA operations */ + struct ib_sma_operations *op; + /** SMA completion queue */ + struct ib_completion_queue *cq; + /** SMA queue pair */ + struct ib_queue_pair *qp; + /** Poll process */ + struct process poll; +}; + +/** SMA payload size allocated for received packets */ +#define IB_SMA_PAYLOAD_LEN 2048 + +/** SMA number of send WQEs + * + * This is a policy decision. + */ +#define IB_SMA_NUM_SEND_WQES 4 + +/** SMA number of receive WQEs + * + * This is a policy decision. + */ +#define IB_SMA_NUM_RECV_WQES 2 + +/** SMA number of completion queue entries + * + * This is a policy decision + */ +#define IB_SMA_NUM_CQES 8 + +extern int ib_create_sma ( struct ib_sma *sma, struct ib_device *ibdev, + struct ib_sma_operations *op ); +extern void ib_destroy_sma ( struct ib_sma *sma ); + +#endif /* _GPXE_IB_SMA_H */ diff --git a/gpxe/src/include/gpxe/ib_smc.h b/gpxe/src/include/gpxe/ib_smc.h new file mode 100644 index 00000000..bb9020bf --- /dev/null +++ b/gpxe/src/include/gpxe/ib_smc.h @@ -0,0 +1,18 @@ +#ifndef _GPXE_IB_SMC_H +#define _GPXE_IB_SMC_H + +/** @file + * + * Infiniband Subnet Management Client + * + */ + +#include + +typedef int ( * ib_local_mad_t ) ( struct ib_device *ibdev, + union ib_mad *mad ); + +extern int ib_smc_update ( struct ib_device *ibdev, + ib_local_mad_t local_mad ); + +#endif /* _GPXE_IB_SMC_H */ diff --git a/gpxe/src/include/gpxe/infiniband.h b/gpxe/src/include/gpxe/infiniband.h index f9e65348..1bb82401 100644 --- a/gpxe/src/include/gpxe/infiniband.h +++ b/gpxe/src/include/gpxe/infiniband.h @@ -10,6 +10,8 @@ #include #include #include +#include +#include /** Subnet administrator QPN */ #define IB_SA_QPN 1 @@ -20,38 +22,9 @@ /** Subnet administrator queue key */ #define IB_GLOBAL_QKEY 0x80010000UL -/** An Infiniband Global Identifier */ -struct ib_gid { - union { - uint8_t bytes[16]; - uint16_t words[8]; - uint32_t dwords[4]; - } u; -}; - -/** An Infiniband Global Route Header */ -struct ib_global_route_header { - /** IP version, traffic class, and flow label - * - * 4 bits : Version of the GRH - * 8 bits : Traffic class - * 20 bits : Flow label - */ - uint32_t ipver_tclass_flowlabel; - /** Payload length */ - uint16_t paylen; - /** Next header */ - uint8_t nxthdr; - /** Hop limit */ - uint8_t hoplmt; - /** Source GID */ - struct ib_gid sgid; - /** Destiniation GID */ - struct ib_gid dgid; -} __attribute__ (( packed )); - struct ib_device; struct ib_queue_pair; +struct ib_address_vector; struct ib_completion_queue; /** An Infiniband Work Queue */ @@ -66,6 +39,8 @@ struct ib_work_queue { struct list_head list; /** Number of work queue entries */ unsigned int num_wqes; + /** Number of occupied work queue entries */ + unsigned int fill; /** Next work queue entry index * * This is the index of the next entry to be filled (i.e. the @@ -80,8 +55,20 @@ struct ib_work_queue { void *drv_priv; }; +/** An Infiniband multicast GID */ +struct ib_multicast_gid { + /** List of multicast GIDs on this QP */ + struct list_head list; + /** Multicast GID */ + struct ib_gid gid; +}; + /** An Infiniband Queue Pair */ struct ib_queue_pair { + /** Containing Infiniband device */ + struct ib_device *ibdev; + /** List of queue pairs on this Infiniband device */ + struct list_head list; /** Queue Pair Number */ unsigned long qpn; /** Queue key */ @@ -90,6 +77,8 @@ struct ib_queue_pair { struct ib_work_queue send; /** Receive queue */ struct ib_work_queue recv; + /** List of multicast GIDs */ + struct list_head mgids; /** Driver private data */ void *drv_priv; /** Queue owner private data */ @@ -101,6 +90,58 @@ enum ib_queue_pair_mods { IB_MODIFY_QKEY = 0x0001, }; +/** An Infiniband Address Vector */ +struct ib_address_vector { + /** Queue Pair Number */ + unsigned long qpn; + /** Queue key + * + * Not specified for received packets. + */ + unsigned long qkey; + /** Local ID */ + unsigned int lid; + /** Rate + * + * Not specified for received packets. + */ + unsigned int rate; + /** Service level */ + unsigned int sl; + /** GID is present */ + unsigned int gid_present; + /** GID, if present */ + struct ib_gid gid; +}; + +/** Infiniband completion queue operations */ +struct ib_completion_queue_operations { + /** + * Complete Send WQE + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v iobuf I/O buffer + * @v rc Completion status code + */ + void ( * complete_send ) ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + struct io_buffer *iobuf, int rc ); + /** + * Complete Receive WQE + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v av Address vector, or NULL + * @v iobuf I/O buffer + * @v rc Completion status code + */ + void ( * complete_recv ) ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + struct ib_address_vector *av, + struct io_buffer *iobuf, int rc ); +}; + /** An Infiniband Completion Queue */ struct ib_completion_queue { /** Completion queue number */ @@ -117,53 +158,12 @@ struct ib_completion_queue { unsigned long next_idx; /** List of work queues completing to this queue */ struct list_head work_queues; + /** Completion queue operations */ + struct ib_completion_queue_operations *op; /** Driver private data */ void *drv_priv; }; -/** An Infiniband completion */ -struct ib_completion { - /** Syndrome - * - * If non-zero, then the completion is in error. - */ - unsigned int syndrome; - /** Length */ - size_t len; -}; - -/** An Infiniband completion handler - * - * @v ibdev Infiniband device - * @v qp Queue pair - * @v completion Completion - * @v iobuf I/O buffer - */ -typedef void ( * ib_completer_t ) ( struct ib_device *ibdev, - struct ib_queue_pair *qp, - struct ib_completion *completion, - struct io_buffer *iobuf ); - -/** An Infiniband Address Vector */ -struct ib_address_vector { - /** Destination Queue Pair */ - unsigned int dest_qp; - /** Queue key */ - unsigned long qkey; - /** Destination Local ID */ - unsigned int dlid; - /** Rate */ - unsigned int rate; - /** Service level */ - unsigned int sl; - /** GID is present */ - unsigned int gid_present; - /** GID */ - struct ib_gid gid; -}; - -struct ib_mad_hdr; - /** * Infiniband device operations * @@ -246,15 +246,12 @@ struct ib_device_operations { * * @v ibdev Infiniband device * @v cq Completion queue - * @v complete_send Send completion handler - * @v complete_recv Receive completion handler * - * The completion handler takes ownership of the I/O buffer. + * The relevant completion handler (specified at completion + * queue creation time) takes ownership of the I/O buffer. */ void ( * poll_cq ) ( struct ib_device *ibdev, - struct ib_completion_queue *cq, - ib_completer_t complete_send, - ib_completer_t complete_recv ); + struct ib_completion_queue *cq ); /** * Poll event queue * @@ -293,16 +290,6 @@ struct ib_device_operations { void ( * mcast_detach ) ( struct ib_device *ibdev, struct ib_queue_pair *qp, struct ib_gid *gid ); - /** - * Issue management datagram - * - * @v ibdev Infiniband device - * @v mad Management datagram - * @v len Length of management datagram - * @ret rc Return status code - */ - int ( * mad ) ( struct ib_device *ibdev, struct ib_mad_hdr *mad, - size_t len ); }; /** An Infiniband device */ @@ -313,26 +300,42 @@ struct ib_device { struct list_head list; /** Underlying device */ struct device *dev; + /** List of queue pairs */ + struct list_head qps; /** Infiniband operations */ struct ib_device_operations *op; /** Port number */ unsigned int port; - /** Link state */ - int link_up; + + /** Port state */ + uint8_t port_state; + /** Link width */ + uint8_t link_width; + /** Link speed */ + uint8_t link_speed; /** Port GID */ - struct ib_gid port_gid; + struct ib_gid gid; + /** Port LID */ + uint16_t lid; /** Subnet manager LID */ - unsigned long sm_lid; + uint16_t sm_lid; + /** Subnet manager SL */ + uint8_t sm_sl; /** Partition key */ - unsigned int pkey; + uint16_t pkey; + + /** Outbound packet sequence number */ + uint32_t psn; + /** Driver private data */ void *drv_priv; /** Owner private data */ void *owner_priv; }; -extern struct ib_completion_queue * ib_create_cq ( struct ib_device *ibdev, - unsigned int num_cqes ); +extern struct ib_completion_queue * +ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes, + struct ib_completion_queue_operations *op ); extern void ib_destroy_cq ( struct ib_device *ibdev, struct ib_completion_queue *cq ); extern struct ib_queue_pair * @@ -343,54 +346,47 @@ extern int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp, unsigned long mod_list, unsigned long qkey ); extern void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ); +extern struct ib_queue_pair * ib_find_qp_qpn ( struct ib_device *ibdev, + unsigned long qpn ); +extern struct ib_queue_pair * ib_find_qp_mgid ( struct ib_device *ibdev, + struct ib_gid *gid ); extern struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq, unsigned long qpn, int is_send ); +extern int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp, + struct ib_address_vector *av, + struct io_buffer *iobuf ); +extern int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp, + struct io_buffer *iobuf ); +extern void ib_complete_send ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + struct io_buffer *iobuf, int rc ); +extern void ib_complete_recv ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + struct ib_address_vector *av, + struct io_buffer *iobuf, int rc ); +extern int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp, + struct ib_gid *gid ); +extern void ib_mcast_detach ( struct ib_device *ibdev, + struct ib_queue_pair *qp, struct ib_gid *gid ); extern struct ib_device * alloc_ibdev ( size_t priv_size ); extern int register_ibdev ( struct ib_device *ibdev ); extern void unregister_ibdev ( struct ib_device *ibdev ); extern void ib_link_state_changed ( struct ib_device *ibdev ); +extern struct list_head ib_devices; -/** - * Post send work queue entry - * - * @v ibdev Infiniband device - * @v qp Queue pair - * @v av Address vector - * @v iobuf I/O buffer - * @ret rc Return status code - */ -static inline __attribute__ (( always_inline )) int -ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp, - struct ib_address_vector *av, struct io_buffer *iobuf ) { - return ibdev->op->post_send ( ibdev, qp, av, iobuf ); -} - -/** - * Post receive work queue entry - * - * @v ibdev Infiniband device - * @v qp Queue pair - * @v iobuf I/O buffer - * @ret rc Return status code - */ -static inline __attribute__ (( always_inline )) int -ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp, - struct io_buffer *iobuf ) { - return ibdev->op->post_recv ( ibdev, qp, iobuf ); -} +/** Iterate over all network devices */ +#define for_each_ibdev( ibdev ) \ + list_for_each_entry ( (ibdev), &ib_devices, list ) /** * Poll completion queue * * @v ibdev Infiniband device * @v cq Completion queue - * @v complete_send Send completion handler - * @v complete_recv Receive completion handler */ -static inline __attribute__ (( always_inline )) void -ib_poll_cq ( struct ib_device *ibdev, struct ib_completion_queue *cq, - ib_completer_t complete_send, ib_completer_t complete_recv ) { - ibdev->op->poll_cq ( ibdev, cq, complete_send, complete_recv ); +static inline __always_inline void +ib_poll_cq ( struct ib_device *ibdev, struct ib_completion_queue *cq ) { + ibdev->op->poll_cq ( ibdev, cq ); } /** @@ -399,7 +395,7 @@ ib_poll_cq ( struct ib_device *ibdev, struct ib_completion_queue *cq, * @v ibdev Infiniband device * @ret rc Return status code */ -static inline __attribute__ (( always_inline )) int +static inline __always_inline int ib_open ( struct ib_device *ibdev ) { return ibdev->op->open ( ibdev ); } @@ -409,49 +405,20 @@ ib_open ( struct ib_device *ibdev ) { * * @v ibdev Infiniband device */ -static inline __attribute__ (( always_inline )) void +static inline __always_inline void ib_close ( struct ib_device *ibdev ) { ibdev->op->close ( ibdev ); } /** - * Attach to multicast group - * - * @v ibdev Infiniband device - * @v qp Queue pair - * @v gid Multicast GID - * @ret rc Return status code - */ -static inline __attribute__ (( always_inline )) int -ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp, - struct ib_gid *gid ) { - return ibdev->op->mcast_attach ( ibdev, qp, gid ); -} - -/** - * Detach from multicast group - * - * @v ibdev Infiniband device - * @v qp Queue pair - * @v gid Multicast GID - */ -static inline __attribute__ (( always_inline )) void -ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp, - struct ib_gid *gid ) { - ibdev->op->mcast_detach ( ibdev, qp, gid ); -} - -/** - * Issue management datagram + * Check link state * * @v ibdev Infiniband device - * @v mad Management datagram - * @v len Length of management datagram - * @ret rc Return status code + * @ret link_up Link is up */ -static inline __attribute__ (( always_inline )) int -ib_mad ( struct ib_device *ibdev, struct ib_mad_hdr *mad, size_t len ) { - return ibdev->op->mad ( ibdev, mad, len ); +static inline __always_inline int +ib_link_ok ( struct ib_device *ibdev ) { + return ( ibdev->port_state == IB_PORT_STATE_ACTIVE ); } /** @@ -460,7 +427,7 @@ ib_mad ( struct ib_device *ibdev, struct ib_mad_hdr *mad, size_t len ) { * @v ibdev Infiniband device * @ret ibdev Infiniband device */ -static inline __attribute__ (( always_inline )) struct ib_device * +static inline __always_inline struct ib_device * ibdev_get ( struct ib_device *ibdev ) { ref_get ( &ibdev->refcnt ); return ibdev; @@ -471,7 +438,7 @@ ibdev_get ( struct ib_device *ibdev ) { * * @v ibdev Infiniband device */ -static inline __attribute__ (( always_inline )) void +static inline __always_inline void ibdev_put ( struct ib_device *ibdev ) { ref_put ( &ibdev->refcnt ); } @@ -482,7 +449,7 @@ ibdev_put ( struct ib_device *ibdev ) { * @v wq Work queue * @v priv Private data */ -static inline __attribute__ (( always_inline )) void +static inline __always_inline void ib_wq_set_drvdata ( struct ib_work_queue *wq, void *priv ) { wq->drv_priv = priv; } @@ -493,7 +460,7 @@ ib_wq_set_drvdata ( struct ib_work_queue *wq, void *priv ) { * @v wq Work queue * @ret priv Private data */ -static inline __attribute__ (( always_inline )) void * +static inline __always_inline void * ib_wq_get_drvdata ( struct ib_work_queue *wq ) { return wq->drv_priv; } @@ -504,7 +471,7 @@ ib_wq_get_drvdata ( struct ib_work_queue *wq ) { * @v qp Queue pair * @v priv Private data */ -static inline __attribute__ (( always_inline )) void +static inline __always_inline void ib_qp_set_drvdata ( struct ib_queue_pair *qp, void *priv ) { qp->drv_priv = priv; } @@ -515,7 +482,7 @@ ib_qp_set_drvdata ( struct ib_queue_pair *qp, void *priv ) { * @v qp Queue pair * @ret priv Private data */ -static inline __attribute__ (( always_inline )) void * +static inline __always_inline void * ib_qp_get_drvdata ( struct ib_queue_pair *qp ) { return qp->drv_priv; } @@ -526,7 +493,7 @@ ib_qp_get_drvdata ( struct ib_queue_pair *qp ) { * @v qp Queue pair * @v priv Private data */ -static inline __attribute__ (( always_inline )) void +static inline __always_inline void ib_qp_set_ownerdata ( struct ib_queue_pair *qp, void *priv ) { qp->owner_priv = priv; } @@ -537,7 +504,7 @@ ib_qp_set_ownerdata ( struct ib_queue_pair *qp, void *priv ) { * @v qp Queue pair * @ret priv Private data */ -static inline __attribute__ (( always_inline )) void * +static inline __always_inline void * ib_qp_get_ownerdata ( struct ib_queue_pair *qp ) { return qp->owner_priv; } @@ -548,7 +515,7 @@ ib_qp_get_ownerdata ( struct ib_queue_pair *qp ) { * @v cq Completion queue * @v priv Private data */ -static inline __attribute__ (( always_inline )) void +static inline __always_inline void ib_cq_set_drvdata ( struct ib_completion_queue *cq, void *priv ) { cq->drv_priv = priv; } @@ -559,7 +526,7 @@ ib_cq_set_drvdata ( struct ib_completion_queue *cq, void *priv ) { * @v cq Completion queue * @ret priv Private data */ -static inline __attribute__ (( always_inline )) void * +static inline __always_inline void * ib_cq_get_drvdata ( struct ib_completion_queue *cq ) { return cq->drv_priv; } @@ -570,7 +537,7 @@ ib_cq_get_drvdata ( struct ib_completion_queue *cq ) { * @v ibdev Infiniband device * @v priv Private data */ -static inline __attribute__ (( always_inline )) void +static inline __always_inline void ib_set_drvdata ( struct ib_device *ibdev, void *priv ) { ibdev->drv_priv = priv; } @@ -581,7 +548,7 @@ ib_set_drvdata ( struct ib_device *ibdev, void *priv ) { * @v ibdev Infiniband device * @ret priv Private data */ -static inline __attribute__ (( always_inline )) void * +static inline __always_inline void * ib_get_drvdata ( struct ib_device *ibdev ) { return ibdev->drv_priv; } @@ -592,7 +559,7 @@ ib_get_drvdata ( struct ib_device *ibdev ) { * @v ibdev Infiniband device * @v priv Private data */ -static inline __attribute__ (( always_inline )) void +static inline __always_inline void ib_set_ownerdata ( struct ib_device *ibdev, void *priv ) { ibdev->owner_priv = priv; } @@ -603,201 +570,9 @@ ib_set_ownerdata ( struct ib_device *ibdev, void *priv ) { * @v ibdev Infiniband device * @ret priv Private data */ -static inline __attribute__ (( always_inline )) void * +static inline __always_inline void * ib_get_ownerdata ( struct ib_device *ibdev ) { return ibdev->owner_priv; } -/***************************************************************************** - * - * Management datagrams - * - * Portions Copyright (c) 2004 Mellanox Technologies Ltd. All rights - * reserved. - * - */ - -/* Management base version */ -#define IB_MGMT_BASE_VERSION 1 - -/* Management classes */ -#define IB_MGMT_CLASS_SUBN_LID_ROUTED 0x01 -#define IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE 0x81 -#define IB_MGMT_CLASS_SUBN_ADM 0x03 -#define IB_MGMT_CLASS_PERF_MGMT 0x04 -#define IB_MGMT_CLASS_BM 0x05 -#define IB_MGMT_CLASS_DEVICE_MGMT 0x06 -#define IB_MGMT_CLASS_CM 0x07 -#define IB_MGMT_CLASS_SNMP 0x08 -#define IB_MGMT_CLASS_VENDOR_RANGE2_START 0x30 -#define IB_MGMT_CLASS_VENDOR_RANGE2_END 0x4F - -/* Management methods */ -#define IB_MGMT_METHOD_GET 0x01 -#define IB_MGMT_METHOD_SET 0x02 -#define IB_MGMT_METHOD_GET_RESP 0x81 -#define IB_MGMT_METHOD_SEND 0x03 -#define IB_MGMT_METHOD_TRAP 0x05 -#define IB_MGMT_METHOD_REPORT 0x06 -#define IB_MGMT_METHOD_REPORT_RESP 0x86 -#define IB_MGMT_METHOD_TRAP_REPRESS 0x07 -#define IB_MGMT_METHOD_DELETE 0x15 -#define IB_MGMT_METHOD_RESP 0x80 - -/* Subnet management attributes */ -#define IB_SMP_ATTR_NOTICE 0x0002 -#define IB_SMP_ATTR_NODE_DESC 0x0010 -#define IB_SMP_ATTR_NODE_INFO 0x0011 -#define IB_SMP_ATTR_SWITCH_INFO 0x0012 -#define IB_SMP_ATTR_GUID_INFO 0x0014 -#define IB_SMP_ATTR_PORT_INFO 0x0015 -#define IB_SMP_ATTR_PKEY_TABLE 0x0016 -#define IB_SMP_ATTR_SL_TO_VL_TABLE 0x0017 -#define IB_SMP_ATTR_VL_ARB_TABLE 0x0018 -#define IB_SMP_ATTR_LINEAR_FORWARD_TABLE 0x0019 -#define IB_SMP_ATTR_RANDOM_FORWARD_TABLE 0x001A -#define IB_SMP_ATTR_MCAST_FORWARD_TABLE 0x001B -#define IB_SMP_ATTR_SM_INFO 0x0020 -#define IB_SMP_ATTR_VENDOR_DIAG 0x0030 -#define IB_SMP_ATTR_LED_INFO 0x0031 -#define IB_SMP_ATTR_VENDOR_MASK 0xFF00 - -#define IB_SA_ATTR_MC_MEMBER_REC 0x38 -#define IB_SA_ATTR_PATH_REC 0x35 - -#define IB_SA_MCMEMBER_REC_MGID (1<<0) -#define IB_SA_MCMEMBER_REC_PORT_GID (1<<1) -#define IB_SA_MCMEMBER_REC_QKEY (1<<2) -#define IB_SA_MCMEMBER_REC_MLID (1<<3) -#define IB_SA_MCMEMBER_REC_MTU_SELECTOR (1<<4) -#define IB_SA_MCMEMBER_REC_MTU (1<<5) -#define IB_SA_MCMEMBER_REC_TRAFFIC_CLASS (1<<6) -#define IB_SA_MCMEMBER_REC_PKEY (1<<7) -#define IB_SA_MCMEMBER_REC_RATE_SELECTOR (1<<8) -#define IB_SA_MCMEMBER_REC_RATE (1<<9) -#define IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME_SELECTOR (1<<10) -#define IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME (1<<11) -#define IB_SA_MCMEMBER_REC_SL (1<<12) -#define IB_SA_MCMEMBER_REC_FLOW_LABEL (1<<13) -#define IB_SA_MCMEMBER_REC_HOP_LIMIT (1<<14) -#define IB_SA_MCMEMBER_REC_SCOPE (1<<15) -#define IB_SA_MCMEMBER_REC_JOIN_STATE (1<<16) -#define IB_SA_MCMEMBER_REC_PROXY_JOIN (1<<17) - -#define IB_SA_PATH_REC_DGID (1<<2) -#define IB_SA_PATH_REC_SGID (1<<3) - -struct ib_mad_hdr { - uint8_t base_version; - uint8_t mgmt_class; - uint8_t class_version; - uint8_t method; - uint16_t status; - uint16_t class_specific; - uint32_t tid[2]; - uint16_t attr_id; - uint16_t resv; - uint32_t attr_mod; -} __attribute__ (( packed )); - -struct ib_sa_hdr { - uint32_t sm_key[2]; - uint16_t reserved; - uint16_t attrib_offset; - uint32_t comp_mask[2]; -} __attribute__ (( packed )); - -struct ib_rmpp_hdr { - uint32_t raw[3]; -} __attribute__ (( packed )); - -struct ib_mad_data { - struct ib_mad_hdr mad_hdr; - uint8_t data[232]; -} __attribute__ (( packed )); - -struct ib_mad_guid_info { - struct ib_mad_hdr mad_hdr; - uint32_t mkey[2]; - uint32_t reserved[8]; - uint8_t gid_local[8]; -} __attribute__ (( packed )); - -struct ib_mad_port_info { - struct ib_mad_hdr mad_hdr; - uint32_t mkey[2]; - uint32_t reserved[8]; - uint32_t mkey2[2]; - uint8_t gid_prefix[8]; - uint16_t lid; - uint16_t mastersm_lid; - uint32_t cap_mask; - uint16_t diag_code; - uint16_t mkey_lease_period; - uint8_t local_port_num; - uint8_t link_width_enabled; - uint8_t link_width_supported; - uint8_t link_width_active; - uint8_t port_state__link_speed_supported; - uint8_t link_down_def_state__port_phys_state; - uint8_t lmc__r1__mkey_prot_bits; - uint8_t link_speed_enabled__link_speed_active; -} __attribute__ (( packed )); - -struct ib_mad_pkey_table { - struct ib_mad_hdr mad_hdr; - uint32_t mkey[2]; - uint32_t reserved[8]; - uint16_t pkey[16][2]; -} __attribute__ (( packed )); - -struct ib_mad_path_record { - struct ib_mad_hdr mad_hdr; - struct ib_rmpp_hdr rmpp_hdr; - struct ib_sa_hdr sa_hdr; - uint32_t reserved0[2]; - struct ib_gid dgid; - struct ib_gid sgid; - uint16_t dlid; - uint16_t slid; - uint32_t hop_limit__flow_label__raw_traffic; - uint32_t pkey__numb_path__reversible__tclass; - uint8_t reserved1; - uint8_t reserved__sl; - uint8_t mtu_selector__mtu; - uint8_t rate_selector__rate; - uint32_t preference__packet_lifetime__packet_lifetime_selector; - uint32_t reserved2[35]; -} __attribute__ (( packed )); - -struct ib_mad_mc_member_record { - struct ib_mad_hdr mad_hdr; - struct ib_rmpp_hdr rmpp_hdr; - struct ib_sa_hdr sa_hdr; - struct ib_gid mgid; - struct ib_gid port_gid; - uint32_t qkey; - uint16_t mlid; - uint8_t mtu_selector__mtu; - uint8_t tclass; - uint16_t pkey; - uint8_t rate_selector__rate; - uint8_t packet_lifetime_selector__packet_lifetime; - uint32_t sl__flow_label__hop_limit; - uint8_t scope__join_state; - uint8_t proxy_join__reserved; - uint16_t reserved0; - uint32_t reserved1[37]; -} __attribute__ (( packed )); - -union ib_mad { - struct ib_mad_hdr mad_hdr; - struct ib_mad_data data; - struct ib_mad_guid_info guid_info; - struct ib_mad_port_info port_info; - struct ib_mad_pkey_table pkey_table; - struct ib_mad_path_record path_record; - struct ib_mad_mc_member_record mc_member_record; -} __attribute__ (( packed )); - #endif /* _GPXE_INFINIBAND_H */ diff --git a/gpxe/src/include/gpxe/init.h b/gpxe/src/include/gpxe/init.h index d2b450d7..e0e9f9c8 100644 --- a/gpxe/src/include/gpxe/init.h +++ b/gpxe/src/include/gpxe/init.h @@ -63,6 +63,7 @@ struct startup_fn { #define STARTUP_EARLY 01 /**< Early startup */ #define STARTUP_NORMAL 02 /**< Normal startup */ +#define STARTUP_LATE 03 /**< Late startup */ /** @} */ diff --git a/gpxe/src/include/gpxe/io.h b/gpxe/src/include/gpxe/io.h new file mode 100644 index 00000000..ebb8ba30 --- /dev/null +++ b/gpxe/src/include/gpxe/io.h @@ -0,0 +1,504 @@ +#ifndef _GPXE_IO_H +#define _GPXE_IO_H + +/** @file + * + * gPXE I/O API + * + * The I/O API provides methods for reading from and writing to + * memory-mapped and I/O-mapped devices. + * + * The standard methods (readl()/writel() etc.) do not strictly check + * the type of the address parameter; this is because traditional + * usage does not necessarily provide the correct pointer type. For + * example, code written for ISA devices at fixed I/O addresses (such + * as the keyboard controller) tend to use plain integer constants for + * the address parameter. + */ + +#include +#include +#include +#include + +/** + * Calculate static inline I/O API function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define IOAPI_INLINE( _subsys, _api_func ) \ + SINGLE_API_INLINE ( IOAPI_PREFIX_ ## _subsys, _api_func ) + +/** + * Provide an I/O API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_IOAPI( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( IOAPI_PREFIX_ ## _subsys, _api_func, _func ) + +/** + * Provide a static inline I/O API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_IOAPI_INLINE( _subsys, _api_func ) \ + PROVIDE_SINGLE_API_INLINE ( IOAPI_PREFIX_ ## _subsys, _api_func ) + +/* Include all architecture-independent I/O API headers */ +#include + +/* Include all architecture-dependent I/O API headers */ +#include + +/** + * Wrap an I/O read + * + * @v _func I/O API function + * @v _type Data type + * @v io_addr I/O address + * @v _prefix Prefix for address in debug message + * @v _ndigits Number of hex digits for this data type + */ +#define IOAPI_READ( _func, _type, io_addr, _prefix, _ndigits ) ( { \ + volatile _type *_io_addr = \ + ( ( volatile _type * ) ( intptr_t ) (io_addr) ); \ + _type _data = _func ( _io_addr ); \ + DBGIO ( "[" _prefix " %08lx] => %0" #_ndigits "llx\n", \ + io_to_bus ( _io_addr ), ( unsigned long long ) _data ); \ + _data; } ) + +/** + * Wrap an I/O write + * + * @v _func I/O API function + * @v _type Data type + * @v data Value to write + * @v io_addr I/O address + * @v _prefix Prefix for address in debug message + * @v _ndigits Number of hex digits for this data type + */ +#define IOAPI_WRITE( _func, _type, data, io_addr, _prefix, _ndigits ) do { \ + volatile _type *_io_addr = \ + ( ( volatile _type * ) ( intptr_t ) (io_addr) ); \ + _type _data = (data); \ + DBGIO ( "[" _prefix " %08lx] <= %0" #_ndigits "llx\n", \ + io_to_bus ( _io_addr ), ( unsigned long long ) _data ); \ + _func ( _data, _io_addr ); \ + } while ( 0 ) + +/** + * Wrap an I/O string read + * + * @v _func I/O API function + * @v _type Data type + * @v io_addr I/O address + * @v data Data buffer + * @v count Number of elements to read + * @v _prefix Prefix for address in debug message + * @v _ndigits Number of hex digits for this data type + */ +#define IOAPI_READS( _func, _type, io_addr, data, count, _prefix, _ndigits ) \ + do { \ + volatile _type *_io_addr = \ + ( ( volatile _type * ) ( intptr_t ) (io_addr) ); \ + void *_data_void = (data); /* Check data is a pointer */ \ + _type * _data = ( ( _type * ) _data_void ); \ + const _type * _dbg_data = _data; \ + unsigned int _count = (count); \ + unsigned int _dbg_count = _count; \ + _func ( _io_addr, _data, _count ); \ + DBGIO ( "[" _prefix " %08lx] =>", io_to_bus ( _io_addr ) ); \ + while ( _dbg_count-- ) { \ + DBGIO ( " %0" #_ndigits "llx", \ + ( ( unsigned long long ) *(_dbg_data++) ) ); \ + } \ + DBGIO ( "\n" ); \ + } while ( 0 ) + +/** + * Wrap an I/O string write + * + * @v _func I/O API function + * @v _type Data type + * @v io_addr I/O address + * @v data Data buffer + * @v count Number of elements to write + * @v _prefix Prefix for address in debug message + * @v _ndigits Number of hex digits for this data type + */ +#define IOAPI_WRITES( _func, _type, io_addr, data, count, _prefix, _ndigits ) \ + do { \ + volatile _type *_io_addr = \ + ( ( volatile _type * ) ( intptr_t ) (io_addr) ); \ + const void *_data_void = (data); /* Check data is a pointer */ \ + const _type * _data = ( ( const _type * ) _data_void ); \ + const _type * _dbg_data = _data; \ + unsigned int _count = (count); \ + unsigned int _dbg_count = _count; \ + DBGIO ( "[" _prefix " %08lx] <=", io_to_bus ( _io_addr ) ); \ + while ( _dbg_count-- ) { \ + DBGIO ( " %0" #_ndigits "llx", \ + ( ( unsigned long long ) *(_dbg_data++) ) ); \ + } \ + DBGIO ( "\n" ); \ + _func ( _io_addr, _data, _count ); \ + } while ( 0 ) + +/** + * Convert physical address to a bus address + * + * @v phys_addr Physical address + * @ret bus_addr Bus address + */ +unsigned long phys_to_bus ( unsigned long phys_addr ); + +/** + * Convert bus address to a physical address + * + * @v bus_addr Bus address + * @ret phys_addr Physical address + */ +unsigned long bus_to_phys ( unsigned long bus_addr ); + +/** + * Convert virtual address to a bus address + * + * @v addr Virtual address + * @ret bus_addr Bus address + */ +static inline __always_inline unsigned long +virt_to_bus ( volatile const void *addr ) { + return phys_to_bus ( virt_to_phys ( addr ) ); +} + +/** + * Convert bus address to a virtual address + * + * @v bus_addr Bus address + * @ret addr Virtual address + * + * This operation is not available under all memory models. + */ +static inline __always_inline void * bus_to_virt ( unsigned long bus_addr ) { + return phys_to_virt ( bus_to_phys ( bus_addr ) ); +} + +/** + * Map bus address as an I/O address + * + * @v bus_addr Bus address + * @v len Length of region + * @ret io_addr I/O address + */ +void * ioremap ( unsigned long bus_addr, size_t len ); + +/** + * Unmap I/O address + * + * @v io_addr I/O address + */ +void iounmap ( volatile const void *io_addr ); + +/** + * Convert I/O address to bus address (for debug only) + * + * @v io_addr I/O address + * @ret bus_addr Bus address + */ +unsigned long io_to_bus ( volatile const void *io_addr ); + +/** + * Read byte from memory-mapped device + * + * @v io_addr I/O address + * @ret data Value read + */ +uint8_t readb ( volatile uint8_t *io_addr ); +#define readb( io_addr ) IOAPI_READ ( readb, uint8_t, io_addr, "MEM", 2 ) + +/** + * Read 16-bit word from memory-mapped device + * + * @v io_addr I/O address + * @ret data Value read + */ +uint16_t readw ( volatile uint16_t *io_addr ); +#define readw( io_addr ) IOAPI_READ ( readw, uint16_t, io_addr, "MEM", 4 ) + +/** + * Read 32-bit dword from memory-mapped device + * + * @v io_addr I/O address + * @ret data Value read + */ +uint32_t readl ( volatile uint32_t *io_addr ); +#define readl( io_addr ) IOAPI_READ ( readl, uint32_t, io_addr, "MEM", 8 ) + +/** + * Read 64-bit qword from memory-mapped device + * + * @v io_addr I/O address + * @ret data Value read + */ +uint64_t readq ( volatile uint64_t *io_addr ); +#define readq( io_addr ) IOAPI_READ ( readq, uint64_t, io_addr, "MEM", 16 ) + +/** + * Write byte to memory-mapped device + * + * @v data Value to write + * @v io_addr I/O address + */ +void writeb ( uint8_t data, volatile uint8_t *io_addr ); +#define writeb( data, io_addr ) \ + IOAPI_WRITE ( writeb, uint8_t, data, io_addr, "MEM", 2 ) + +/** + * Write 16-bit word to memory-mapped device + * + * @v data Value to write + * @v io_addr I/O address + */ +void writew ( uint16_t data, volatile uint16_t *io_addr ); +#define writew( data, io_addr ) \ + IOAPI_WRITE ( writew, uint16_t, data, io_addr, "MEM", 4 ) + +/** + * Write 32-bit dword to memory-mapped device + * + * @v data Value to write + * @v io_addr I/O address + */ +void writel ( uint32_t data, volatile uint32_t *io_addr ); +#define writel( data, io_addr ) \ + IOAPI_WRITE ( writel, uint32_t, data, io_addr, "MEM", 8 ) + +/** + * Write 64-bit qword to memory-mapped device + * + * @v data Value to write + * @v io_addr I/O address + */ +void writeq ( uint64_t data, volatile uint64_t *io_addr ); +#define writeq( data, io_addr ) \ + IOAPI_WRITE ( writeq, uint64_t, data, io_addr, "MEM", 16 ) + +/** + * Read byte from I/O-mapped device + * + * @v io_addr I/O address + * @ret data Value read + */ +uint8_t inb ( volatile uint8_t *io_addr ); +#define inb( io_addr ) IOAPI_READ ( inb, uint8_t, io_addr, "IO", 2 ) + +/** + * Read 16-bit word from I/O-mapped device + * + * @v io_addr I/O address + * @ret data Value read + */ +uint16_t inw ( volatile uint16_t *io_addr ); +#define inw( io_addr ) IOAPI_READ ( inw, uint16_t, io_addr, "IO", 4 ) + +/** + * Read 32-bit dword from I/O-mapped device + * + * @v io_addr I/O address + * @ret data Value read + */ +uint32_t inl ( volatile uint32_t *io_addr ); +#define inl( io_addr ) IOAPI_READ ( inl, uint32_t, io_addr, "IO", 8 ) + +/** + * Write byte to I/O-mapped device + * + * @v data Value to write + * @v io_addr I/O address + */ +void outb ( uint8_t data, volatile uint8_t *io_addr ); +#define outb( data, io_addr ) \ + IOAPI_WRITE ( outb, uint8_t, data, io_addr, "IO", 2 ) + +/** + * Write 16-bit word to I/O-mapped device + * + * @v data Value to write + * @v io_addr I/O address + */ +void outw ( uint16_t data, volatile uint16_t *io_addr ); +#define outw( data, io_addr ) \ + IOAPI_WRITE ( outw, uint16_t, data, io_addr, "IO", 4 ) + +/** + * Write 32-bit dword to I/O-mapped device + * + * @v data Value to write + * @v io_addr I/O address + */ +void outl ( uint32_t data, volatile uint32_t *io_addr ); +#define outl( data, io_addr ) \ + IOAPI_WRITE ( outl, uint32_t, data, io_addr, "IO", 8 ) + +/** + * Read bytes from I/O-mapped device + * + * @v io_addr I/O address + * @v data Data buffer + * @v count Number of bytes to read + */ +void insb ( volatile uint8_t *io_addr, uint8_t *data, unsigned int count ); +#define insb( io_addr, data, count ) \ + IOAPI_READS ( insb, uint8_t, io_addr, data, count, "IO", 2 ) + +/** + * Read 16-bit words from I/O-mapped device + * + * @v io_addr I/O address + * @v data Data buffer + * @v count Number of words to read + */ +void insw ( volatile uint16_t *io_addr, uint16_t *data, unsigned int count ); +#define insw( io_addr, data, count ) \ + IOAPI_READS ( insw, uint16_t, io_addr, data, count, "IO", 4 ) + +/** + * Read 32-bit words from I/O-mapped device + * + * @v io_addr I/O address + * @v data Data buffer + * @v count Number of words to read + */ +void insl ( volatile uint32_t *io_addr, uint32_t *data, unsigned int count ); +#define insl( io_addr, data, count ) \ + IOAPI_READS ( insl, uint32_t, io_addr, data, count, "IO", 8 ) + +/** + * Write bytes to I/O-mapped device + * + * @v io_addr I/O address + * @v data Data buffer + * @v count Number of bytes to write + */ +void outsb ( volatile uint8_t *io_addr, const uint8_t *data, + unsigned int count ); +#define outsb( io_addr, data, count ) \ + IOAPI_WRITES ( outsb, uint8_t, io_addr, data, count, "IO", 2 ) + +/** + * Write 16-bit words to I/O-mapped device + * + * @v io_addr I/O address + * @v data Data buffer + * @v count Number of words to write + */ +void outsw ( volatile uint16_t *io_addr, const uint16_t *data, + unsigned int count ); +#define outsw( io_addr, data, count ) \ + IOAPI_WRITES ( outsw, uint16_t, io_addr, data, count, "IO", 4 ) + +/** + * Write 32-bit words to I/O-mapped device + * + * @v io_addr I/O address + * @v data Data buffer + * @v count Number of words to write + */ +void outsl ( volatile uint32_t *io_addr, const uint32_t *data, + unsigned int count ); +#define outsl( io_addr, data, count ) \ + IOAPI_WRITES ( outsl, uint32_t, io_addr, data, count, "IO", 8 ) + +/** + * Slow down I/O + * + */ +void iodelay ( void ); + +/** + * Read value from I/O-mapped device, slowly + * + * @v _func Function to use to read value + * @v data Value to write + * @v io_addr I/O address + */ +#define INX_P( _func, _type, io_addr ) ( { \ + _type _data = _func ( (io_addr) ); \ + iodelay(); \ + _data; } ) + +/** + * Read byte from I/O-mapped device + * + * @v io_addr I/O address + * @ret data Value read + */ +#define inb_p( io_addr ) INX_P ( inb, uint8_t, io_addr ) + +/** + * Read 16-bit word from I/O-mapped device + * + * @v io_addr I/O address + * @ret data Value read + */ +#define inw_p( io_addr ) INX_P ( inw, uint16_t, io_addr ) + +/** + * Read 32-bit dword from I/O-mapped device + * + * @v io_addr I/O address + * @ret data Value read + */ +#define inl_p( io_addr ) INX_P ( inl, uint32_t, io_addr ) + +/** + * Write value to I/O-mapped device, slowly + * + * @v _func Function to use to write value + * @v data Value to write + * @v io_addr I/O address + */ +#define OUTX_P( _func, data, io_addr ) do { \ + _func ( (data), (io_addr) ); \ + iodelay(); \ + } while ( 0 ) + +/** + * Write byte to I/O-mapped device, slowly + * + * @v data Value to write + * @v io_addr I/O address + */ +#define outb_p( data, io_addr ) OUTX_P ( outb, data, io_addr ) + +/** + * Write 16-bit word to I/O-mapped device, slowly + * + * @v data Value to write + * @v io_addr I/O address + */ +#define outw_p( data, io_addr ) OUTX_P ( outw, data, io_addr ) + +/** + * Write 32-bit dword to I/O-mapped device, slowly + * + * @v data Value to write + * @v io_addr I/O address + */ +#define outl_p( data, io_addr ) OUTX_P ( outl, data, io_addr ) + +/** + * Memory barrier + * + */ +void mb ( void ); +#define rmb() mb() +#define wmb() mb() + +#endif /* _GPXE_IO_H */ diff --git a/gpxe/src/include/gpxe/iobuf.h b/gpxe/src/include/gpxe/iobuf.h index ff787754..db7fa042 100644 --- a/gpxe/src/include/gpxe/iobuf.h +++ b/gpxe/src/include/gpxe/iobuf.h @@ -181,6 +181,24 @@ static inline size_t iob_tailroom ( struct io_buffer *iobuf ) { return ( iobuf->end - iobuf->tail ); } +/** + * Create a temporary I/O buffer + * + * @v iobuf I/O buffer + * @v data Data buffer + * @v len Length of data + * @v max_len Length of buffer + * + * It is sometimes useful to use the iob_xxx() methods on temporary + * data buffers. + */ +static inline void iob_populate ( struct io_buffer *iobuf, + void *data, size_t len, size_t max_len ) { + iobuf->head = iobuf->data = data; + iobuf->tail = ( data + len ); + iobuf->end = ( data + max_len ); +} + extern struct io_buffer * __malloc alloc_iob ( size_t len ); extern void free_iob ( struct io_buffer *iobuf ); extern void iob_pad ( struct io_buffer *iobuf, size_t min_len ); diff --git a/gpxe/src/include/gpxe/ipoib.h b/gpxe/src/include/gpxe/ipoib.h index bcbdc4c6..80adee5b 100644 --- a/gpxe/src/include/gpxe/ipoib.h +++ b/gpxe/src/include/gpxe/ipoib.h @@ -8,6 +8,9 @@ #include +/** IPoIB packet length */ +#define IPOIB_PKT_LEN 2048 + /** IPoIB MAC address length */ #define IPOIB_ALEN 20 @@ -23,33 +26,30 @@ struct ipoib_mac { } __attribute__ (( packed )); /** IPoIB link-layer header length */ -#define IPOIB_HLEN 24 - -/** - * IPoIB link-layer header pseudo portion - * - * This part doesn't actually exist on the wire, but it provides a - * convenient way to fit into the typical network device model. - */ -struct ipoib_pseudo_hdr { - /** Peer address */ - struct ipoib_mac peer; -} __attribute__ (( packed )); +#define IPOIB_HLEN 4 -/** IPoIB link-layer header real portion */ -struct ipoib_real_hdr { +/** IPoIB link-layer header */ +struct ipoib_hdr { /** Network-layer protocol */ uint16_t proto; /** Reserved, must be zero */ - uint16_t reserved; -} __attribute__ (( packed )); - -/** An IPoIB link-layer header */ -struct ipoib_hdr { - /** Pseudo portion */ - struct ipoib_pseudo_hdr pseudo; - /** Real portion */ - struct ipoib_real_hdr real; + union { + /** Reserved, must be zero */ + uint16_t reserved; + /** Peer addresses + * + * We use these fields internally to represent the + * peer addresses using a lookup key. There simply + * isn't enough room in the IPoIB header to store + * literal source or destination MAC addresses. + */ + struct { + /** Destination address key */ + uint8_t dest; + /** Source address key */ + uint8_t src; + } __attribute__ (( packed )) peer; + } __attribute__ (( packed )) u; } __attribute__ (( packed )); extern struct ll_protocol ipoib_protocol; @@ -68,6 +68,7 @@ static inline struct net_device * alloc_ipoibdev ( size_t priv_size ) { netdev = alloc_netdev ( priv_size ); if ( netdev ) { netdev->ll_protocol = &ipoib_protocol; + netdev->max_pkt_len = IPOIB_PKT_LEN; } return netdev; } diff --git a/gpxe/src/include/gpxe/nap.h b/gpxe/src/include/gpxe/nap.h new file mode 100644 index 00000000..f9ae3cf4 --- /dev/null +++ b/gpxe/src/include/gpxe/nap.h @@ -0,0 +1,54 @@ +#ifndef _GPXE_NAP_H +#define _GPXE_NAP_H + +/** @file + * + * CPU sleeping + * + */ + +#include +#include + +/** + * Calculate static inline CPU sleeping API function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define NAP_INLINE( _subsys, _api_func ) \ + SINGLE_API_INLINE ( NAP_PREFIX_ ## _subsys, _api_func ) + +/** + * Provide an CPU sleeping API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_NAP( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( NAP_PREFIX_ ## _subsys, _api_func, _func ) + +/** + * Provide a static inline CPU sleeping API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_NAP_INLINE( _subsys, _api_func ) \ + PROVIDE_SINGLE_API_INLINE ( NAP_PREFIX_ ## _subsys, _api_func ) + +/* Include all architecture-independent I/O API headers */ +#include + +/* Include all architecture-dependent I/O API headers */ +#include + +/** + * Sleep until next CPU interrupt + * + */ +void cpu_nap ( void ); + +#endif /* _GPXE_NAP_H */ diff --git a/gpxe/src/include/gpxe/netdevice.h b/gpxe/src/include/gpxe/netdevice.h index cdc8cbad..01b853f3 100644 --- a/gpxe/src/include/gpxe/netdevice.h +++ b/gpxe/src/include/gpxe/netdevice.h @@ -23,7 +23,7 @@ struct device; #define MAX_LL_ADDR_LEN 20 /** Maximum length of a link-layer header */ -#define MAX_LL_HEADER_LEN 32 +#define MAX_LL_HEADER_LEN 6 /** Maximum length of a network-layer address */ #define MAX_NET_ADDR_LEN 4 @@ -79,34 +79,24 @@ struct ll_protocol { * Add link-layer header * * @v iobuf I/O buffer - * @v netdev Network device - * @v net_protocol Network-layer protocol * @v ll_dest Link-layer destination address + * @v ll_source Source link-layer address + * @v net_proto Network-layer protocol, in network-byte order * @ret rc Return status code - * - * This method should prepend in the link-layer header - * (e.g. the Ethernet DIX header). */ - int ( * push ) ( struct io_buffer *iobuf, struct net_device *netdev, - struct net_protocol *net_protocol, - const void *ll_dest ); + int ( * push ) ( struct io_buffer *iobuf, const void *ll_dest, + const void *ll_source, uint16_t net_proto ); /** * Remove link-layer header * - * @v iobuf I/O buffer - * @v netdev Network device - * @v net_proto Network-layer protocol, in network-byte order - * @v ll_source Source link-layer address - * @ret rc Return status code - * - * This method should strip off the link-layer header - * (e.g. the Ethernet DIX header) and return the protocol and - * source link-layer address. The method must not alter the - * packet content, and may return the link-layer address as a - * pointer to data within the packet. + * @v iobuf I/O buffer + * @ret ll_dest Link-layer destination address + * @ret ll_source Source link-layer address + * @ret net_proto Network-layer protocol, in network-byte order + * @ret rc Return status code */ - int ( * pull ) ( struct io_buffer *iobuf, struct net_device *netdev, - uint16_t *net_proto, const void **ll_source ); + int ( * pull ) ( struct io_buffer *iobuf, const void **ll_dest, + const void **ll_source, uint16_t *net_proto ); /** * Transcribe link-layer address * @@ -120,6 +110,16 @@ struct ll_protocol { * allocated. */ const char * ( * ntoa ) ( const void * ll_addr ); + /** + * Hash multicast address + * + * @v af Address family + * @v net_addr Network-layer address + * @v ll_addr Link-layer address to fill in + * @ret rc Return status code + */ + int ( * mc_hash ) ( unsigned int af, const void *net_addr, + void *ll_addr ); /** Link-layer protocol * * This is an ARPHRD_XXX constant, in network byte order. @@ -193,16 +193,25 @@ struct net_device_operations { void ( * irq ) ( struct net_device *netdev, int enable ); }; +/** Network device error */ +struct net_device_error { + /** Error status code */ + int rc; + /** Error count */ + unsigned int count; +}; + +/** Maximum number of unique errors that we will keep track of */ +#define NETDEV_MAX_UNIQUE_ERRORS 4 + /** Network device statistics */ struct net_device_stats { - /** Count of successfully completed transmissions */ - unsigned int tx_ok; - /** Count of transmission errors */ - unsigned int tx_err; - /** Count of successfully received packets */ - unsigned int rx_ok; - /** Count of reception errors */ - unsigned int rx_err; + /** Count of successful completions */ + unsigned int good; + /** Count of error completions */ + unsigned int bad; + /** Error breakdowns */ + struct net_device_error errors[NETDEV_MAX_UNIQUE_ERRORS]; }; /** @@ -241,12 +250,19 @@ struct net_device { * This is the bitwise-OR of zero or more NETDEV_XXX constants. */ unsigned int state; + /** Maximum packet length + * + * This length includes any link-layer headers. + */ + size_t max_pkt_len; /** TX packet queue */ struct list_head tx_queue; /** RX packet queue */ struct list_head rx_queue; - /** Device statistics */ - struct net_device_stats stats; + /** TX statistics */ + struct net_device_stats tx_stats; + /** RX statistics */ + struct net_device_stats rx_stats; /** Configuration settings applicable to this device */ struct simple_settings settings; diff --git a/gpxe/src/include/gpxe/null_nap.h b/gpxe/src/include/gpxe/null_nap.h new file mode 100644 index 00000000..6dd0cda3 --- /dev/null +++ b/gpxe/src/include/gpxe/null_nap.h @@ -0,0 +1,21 @@ +#ifndef _GPXE_NULL_NAP_H +#define _GPXE_NULL_NAP_H + +/** @file + * + * Null CPU sleeping + * + */ + +#ifdef NAP_NULL +#define NAP_PREFIX_null +#else +#define NAP_PREFIX_null __null_ +#endif + +static inline __always_inline void +NAP_INLINE ( null, cpu_nap ) ( void ) { + /* Do nothing */ +} + +#endif /* _GPXE_NULL_NAP_H */ diff --git a/gpxe/src/include/gpxe/pci.h b/gpxe/src/include/gpxe/pci.h index 90721574..1ccdb100 100644 --- a/gpxe/src/include/gpxe/pci.h +++ b/gpxe/src/include/gpxe/pci.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include "pci_ids.h" /* diff --git a/gpxe/src/include/gpxe/pci_io.h b/gpxe/src/include/gpxe/pci_io.h new file mode 100644 index 00000000..365166c8 --- /dev/null +++ b/gpxe/src/include/gpxe/pci_io.h @@ -0,0 +1,122 @@ +#ifndef _GPXE_PCI_IO_H +#define _GPXE_PCI_IO_H + +/** @file + * + * PCI I/O API + * + */ + +#include +#include +#include + +/** + * Calculate static inline PCI I/O API function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define PCIAPI_INLINE( _subsys, _api_func ) \ + SINGLE_API_INLINE ( PCIAPI_PREFIX_ ## _subsys, _api_func ) + +/** + * Provide a PCI I/O API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_PCIAPI( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( PCIAPI_PREFIX_ ## _subsys, _api_func, _func ) + +/** + * Provide a static inline PCI I/O API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_PCIAPI_INLINE( _subsys, _api_func ) \ + PROVIDE_SINGLE_API_INLINE ( PCIAPI_PREFIX_ ## _subsys, _api_func ) + +/* Include all architecture-independent I/O API headers */ +#include + +/* Include all architecture-dependent I/O API headers */ +#include + +/** + * Determine maximum PCI bus number within system + * + * @ret max_bus Maximum bus number + */ +int pci_max_bus ( void ); + +/** + * Read byte from PCI configuration space + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +int pci_read_config_byte ( struct pci_device *pci, unsigned int where, + uint8_t *value ); + +/** + * Read 16-bit word from PCI configuration space + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +int pci_read_config_word ( struct pci_device *pci, unsigned int where, + uint16_t *value ); + +/** + * Read 32-bit dword from PCI configuration space + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +int pci_read_config_dword ( struct pci_device *pci, unsigned int where, + uint32_t *value ); + +/** + * Write byte to PCI configuration space + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +int pci_write_config_byte ( struct pci_device *pci, unsigned int where, + uint8_t value ); + +/** + * Write 16-bit word to PCI configuration space + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +int pci_write_config_word ( struct pci_device *pci, unsigned int where, + uint16_t value ); + +/** + * Write 32-bit dword to PCI configuration space + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +int pci_write_config_dword ( struct pci_device *pci, unsigned int where, + uint32_t value ); + +#endif /* _GPXE_PCI_IO_H */ diff --git a/gpxe/src/include/gpxe/retry.h b/gpxe/src/include/gpxe/retry.h index ec57db9e..1e7fde4c 100644 --- a/gpxe/src/include/gpxe/retry.h +++ b/gpxe/src/include/gpxe/retry.h @@ -19,6 +19,8 @@ struct retry_timer { /** List of active timers */ struct list_head list; + /** Timer is currently running */ + unsigned int running; /** Timeout value (in ticks) */ unsigned long timeout; /** Minimum timeout value (in ticks) @@ -31,10 +33,7 @@ struct retry_timer { * A value of zero means "use default timeout." */ unsigned long max_timeout; - /** Start time (in ticks) - * - * A start time of zero indicates a stopped timer. - */ + /** Start time (in ticks) */ unsigned long start; /** Retry count */ unsigned int count; @@ -74,7 +73,7 @@ static inline void start_timer_nodelay ( struct retry_timer *timer ) { */ static inline __attribute__ (( always_inline )) unsigned long timer_running ( struct retry_timer *timer ) { - return ( timer->start ); + return ( timer->running ); } #endif /* _GPXE_RETRY_H */ diff --git a/gpxe/src/include/gpxe/rotate.h b/gpxe/src/include/gpxe/rotate.h new file mode 100644 index 00000000..42ec7196 --- /dev/null +++ b/gpxe/src/include/gpxe/rotate.h @@ -0,0 +1,27 @@ +#ifndef _GPXE_ROTATE_H +#define _GPXE_ROTATE_H + +/** @file + * + * Bit operations + */ + +#include + +static inline uint32_t rol32 ( uint32_t data, unsigned int rotation ) { + return ( ( data << rotation ) | ( data >> ( 32 - rotation ) ) ); +} + +static inline uint32_t ror32 ( uint32_t data, unsigned int rotation ) { + return ( ( data >> rotation ) | ( data << ( 32 - rotation ) ) ); +} + +static inline uint64_t rol64 ( uint64_t data, unsigned int rotation ) { + return ( ( data << rotation ) | ( data >> ( 64 - rotation ) ) ); +} + +static inline uint64_t ror64 ( uint64_t data, unsigned int rotation ) { + return ( ( data >> rotation ) | ( data << ( 64 - rotation ) ) ); +} + +#endif /* _GPXE_ROTATE_H */ diff --git a/gpxe/src/include/gpxe/sanboot.h b/gpxe/src/include/gpxe/sanboot.h new file mode 100644 index 00000000..ea26a356 --- /dev/null +++ b/gpxe/src/include/gpxe/sanboot.h @@ -0,0 +1,14 @@ +#ifndef _GPXE_SANBOOT_H +#define _GPXE_SANBOOT_H + +#include + +struct sanboot_protocol { + const char *prefix; + int ( * boot ) ( const char *root_path ); +}; + +#define __sanboot_protocol \ + __table ( struct sanboot_protocol, sanboot_protocols, 01 ) + +#endif /* _GPXE_SANBOOT_H */ diff --git a/gpxe/src/include/gpxe/settings.h b/gpxe/src/include/gpxe/settings.h index ee7dacee..37c01b05 100644 --- a/gpxe/src/include/gpxe/settings.h +++ b/gpxe/src/include/gpxe/settings.h @@ -72,6 +72,14 @@ struct settings { struct refcnt *refcnt; /** Name */ const char *name; + /** Tag magic + * + * This value will be ORed in to any numerical tags + * constructed by parse_setting_name(), and can be used to + * avoid e.g. attempting to retrieve the subnet mask from + * SMBIOS, or the system UUID from DHCP. + */ + unsigned int tag_magic; /** Parent settings block */ struct settings *parent; /** Sibling settings blocks */ @@ -225,16 +233,19 @@ extern struct setting mac_setting __setting; * @v op Settings block operations * @v refcnt Containing object reference counter, or NULL * @v name Settings block name + * @v tag_magic Tag magic */ static inline void settings_init ( struct settings *settings, struct settings_operations *op, struct refcnt *refcnt, - const char *name ) { + const char *name, + unsigned int tag_magic ) { INIT_LIST_HEAD ( &settings->siblings ); INIT_LIST_HEAD ( &settings->children ); settings->op = op; settings->refcnt = refcnt; settings->name = name; + settings->tag_magic = tag_magic; } /** @@ -248,7 +259,7 @@ static inline void simple_settings_init ( struct simple_settings *simple, struct refcnt *refcnt, const char *name ) { settings_init ( &simple->settings, &simple_settings_operations, - refcnt, name ); + refcnt, name, 0 ); } /** diff --git a/gpxe/src/include/gpxe/timer.h b/gpxe/src/include/gpxe/timer.h index b7057225..862d87b3 100644 --- a/gpxe/src/include/gpxe/timer.h +++ b/gpxe/src/include/gpxe/timer.h @@ -1,41 +1,74 @@ -#ifndef GPXE_TIMER_H -#define GPXE_TIMER_H +#ifndef _GPXE_TIMER_H +#define _GPXE_TIMER_H -#include -#include +/** @file + * + * gPXE timer API + * + * The timer API provides udelay() for fixed delays, and currticks() + * for a monotonically increasing tick counter. + */ -typedef unsigned long tick_t; +#include +#include -#define MSECS_IN_SEC (1000) -#define USECS_IN_SEC (1000*1000) -#define USECS_IN_MSEC (1000) +/** + * Calculate static inline timer API function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define TIMER_INLINE( _subsys, _api_func ) \ + SINGLE_API_INLINE ( TIMER_PREFIX_ ## _subsys, _api_func ) -#define TICKS_PER_SEC USECS_IN_SEC +/** + * Provide a timer API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_TIMER( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( TIMER_PREFIX_ ## _subsys, _api_func, _func ) -extern tick_t currticks ( void ); +/** + * Provide a static inline timer API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_TIMER_INLINE( _subsys, _api_func ) \ + PROVIDE_SINGLE_API_INLINE ( TIMER_PREFIX_ ## _subsys, _api_func ) -extern void generic_currticks_udelay ( unsigned int usecs ); +/* Include all architecture-independent I/O API headers */ +#include -/** A timer */ -struct timer { - /** Initialise timer - * - * @ret rc Return status code - */ - int ( * init ) ( void ); - /** Read current time - * - * @ret ticks Current time, in ticks - */ - tick_t ( * currticks ) ( void ); - /** Delay - * - * @v usecs Time to delay, in microseconds - */ - void ( * udelay ) ( unsigned int usecs ); -}; +/* Include all architecture-dependent I/O API headers */ +#include -#define __timer( order ) __table ( struct timer, timers, order ) +/** + * Delay for a fixed number of microseconds + * + * @v usecs Number of microseconds for which to delay + */ +void udelay ( unsigned long usecs ); -#endif /* GPXE_TIMER_H */ +/** + * Get current system time in ticks + * + * @ret ticks Current time, in ticks + */ +unsigned long currticks ( void ); +/** + * Get number of ticks per second + * + * @ret ticks_per_sec Number of ticks per second + */ +unsigned long ticks_per_sec ( void ); + +/** Number of ticks per second */ +#define TICKS_PER_SEC ( ticks_per_sec() ) + +#endif /* _GPXE_TIMER_H */ diff --git a/gpxe/src/include/gpxe/tls.h b/gpxe/src/include/gpxe/tls.h index a8cf16ef..39109452 100644 --- a/gpxe/src/include/gpxe/tls.h +++ b/gpxe/src/include/gpxe/tls.h @@ -109,6 +109,22 @@ struct tls_cipherspec { void *mac_secret; }; +/** TLS pre-master secret */ +struct tls_pre_master_secret { + /** TLS version */ + uint16_t version; + /** Random data */ + uint8_t random[46]; +} __attribute__ (( packed )); + +/** TLS client random data */ +struct tls_client_random { + /** GMT Unix time */ + uint32_t gmt_unix_time; + /** Random data */ + uint8_t random[28]; +} __attribute__ (( packed )); + /** A TLS session */ struct tls_session { /** Reference counter */ @@ -128,13 +144,13 @@ struct tls_session { /** Next RX cipher specification */ struct tls_cipherspec rx_cipherspec_pending; /** Premaster secret */ - uint8_t pre_master_secret[48]; + struct tls_pre_master_secret pre_master_secret; /** Master secret */ uint8_t master_secret[48]; /** Server random bytes */ uint8_t server_random[32]; /** Client random bytes */ - uint8_t client_random[32]; + struct tls_client_random client_random; /** MD5 context for handshake verification */ uint8_t handshake_md5_ctx[MD5_CTX_SIZE]; /** SHA1 context for handshake verification */ diff --git a/gpxe/src/include/gpxe/uaccess.h b/gpxe/src/include/gpxe/uaccess.h index 05f89e03..33aaed18 100644 --- a/gpxe/src/include/gpxe/uaccess.h +++ b/gpxe/src/include/gpxe/uaccess.h @@ -19,9 +19,324 @@ * */ -#include +#include +#include +#include +#include + +/** + * A pointer to a user buffer + * + */ +typedef unsigned long userptr_t; /** Equivalent of NULL for user pointers */ #define UNULL ( ( userptr_t ) 0 ) +/** + * @defgroup uaccess_trivial Trivial user access API implementations + * + * User access API implementations that can be used by environments in + * which virtual addresses allow access to all of memory. + * + * @{ + * + */ + +/** + * Convert virtual address to user pointer + * + * @v addr Virtual address + * @ret userptr User pointer + */ +static inline __always_inline userptr_t +trivial_virt_to_user ( volatile const void *addr ) { + return ( ( userptr_t ) addr ); +} + +/** + * Convert user pointer to virtual address + * + * @v userptr User pointer + * @v offset Offset from user pointer + * @ret addr Virtual address + * + * This operation is not available under all memory models. + */ +static inline __always_inline void * +trivial_user_to_virt ( userptr_t userptr, off_t offset ) { + return ( ( void * ) userptr + offset ); +} + +/** + * Add offset to user pointer + * + * @v userptr User pointer + * @v offset Offset + * @ret userptr New pointer value + */ +static inline __always_inline userptr_t +trivial_userptr_add ( userptr_t userptr, off_t offset ) { + return ( userptr + offset ); +} + +/** + * Copy data between user buffers + * + * @v dest Destination + * @v dest_off Destination offset + * @v src Source + * @v src_off Source offset + * @v len Length + */ +static inline __always_inline void +trivial_memcpy_user ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, size_t len ) { + memcpy ( ( ( void * ) dest + dest_off ), + ( ( void * ) src + src_off ), len ); +} + +/** + * Copy data between user buffers, allowing for overlap + * + * @v dest Destination + * @v dest_off Destination offset + * @v src Source + * @v src_off Source offset + * @v len Length + */ +static inline __always_inline void +trivial_memmove_user ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, size_t len ) { + memmove ( ( ( void * ) dest + dest_off ), + ( ( void * ) src + src_off ), len ); +} + +/** + * Fill user buffer with a constant byte + * + * @v buffer User buffer + * @v offset Offset within buffer + * @v c Constant byte with which to fill + * @v len Length + */ +static inline __always_inline void +trivial_memset_user ( userptr_t buffer, off_t offset, int c, size_t len ) { + memset ( ( ( void * ) buffer + offset ), c, len ); +} + +/** + * Find length of NUL-terminated string in user buffer + * + * @v buffer User buffer + * @v offset Offset within buffer + * @ret len Length of string (excluding NUL) + */ +static inline __always_inline size_t +trivial_strlen_user ( userptr_t buffer, off_t offset ) { + return strlen ( ( void * ) buffer + offset ); +} + +/** + * Find character in user buffer + * + * @v buffer User buffer + * @v offset Starting offset within buffer + * @v c Character to search for + * @v len Length of user buffer + * @ret offset Offset of character, or <0 if not found + */ +static inline __always_inline off_t +trivial_memchr_user ( userptr_t buffer, off_t offset, int c, size_t len ) { + void *found; + + found = memchr ( ( ( void * ) buffer + offset ), c, len ); + return ( found ? ( found - ( void * ) buffer ) : -1 ); +} + +/** @} */ + +/** + * Calculate static inline user access API function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define UACCESS_INLINE( _subsys, _api_func ) \ + SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func ) + +/** + * Provide an user access API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_UACCESS( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( UACCESS_PREFIX_ ## _subsys, _api_func, _func ) + +/** + * Provide a static inline user access API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_UACCESS_INLINE( _subsys, _api_func ) \ + PROVIDE_SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func ) + +/* Include all architecture-independent user access API headers */ +#include + +/* Include all architecture-dependent user access API headers */ +#include + +/** + * Convert physical address to user pointer + * + * @v phys_addr Physical address + * @ret userptr User pointer + */ +userptr_t phys_to_user ( unsigned long phys_addr ); + +/** + * Convert user pointer to physical address + * + * @v userptr User pointer + * @v offset Offset from user pointer + * @ret phys_addr Physical address + */ +unsigned long user_to_phys ( userptr_t userptr, off_t offset ); + +/** + * Convert virtual address to user pointer + * + * @v addr Virtual address + * @ret userptr User pointer + */ +userptr_t virt_to_user ( volatile const void *addr ); + +/** + * Convert user pointer to virtual address + * + * @v userptr User pointer + * @v offset Offset from user pointer + * @ret addr Virtual address + * + * This operation is not available under all memory models. + */ +void * user_to_virt ( userptr_t userptr, off_t offset ); + +/** + * Add offset to user pointer + * + * @v userptr User pointer + * @v offset Offset + * @ret userptr New pointer value + */ +userptr_t userptr_add ( userptr_t userptr, off_t offset ); + +/** + * Convert virtual address to a physical address + * + * @v addr Virtual address + * @ret phys_addr Physical address + */ +static inline __always_inline unsigned long +virt_to_phys ( volatile const void *addr ) { + return user_to_phys ( virt_to_user ( addr ), 0 ); +} + +/** + * Convert physical address to a virtual address + * + * @v addr Virtual address + * @ret phys_addr Physical address + * + * This operation is not available under all memory models. + */ +static inline __always_inline void * phys_to_virt ( unsigned long phys_addr ) { + return user_to_virt ( phys_to_user ( phys_addr ), 0 ); +} + +/** + * Copy data between user buffers + * + * @v dest Destination + * @v dest_off Destination offset + * @v src Source + * @v src_off Source offset + * @v len Length + */ +void memcpy_user ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, size_t len ); + +/** + * Copy data to user buffer + * + * @v dest Destination + * @v dest_off Destination offset + * @v src Source + * @v len Length + */ +static inline __always_inline void +copy_to_user ( userptr_t dest, off_t dest_off, const void *src, size_t len ) { + memcpy_user ( dest, dest_off, virt_to_user ( src ), 0, len ); +} + +/** + * Copy data from user buffer + * + * @v dest Destination + * @v src Source + * @v src_off Source offset + * @v len Length + */ +static inline __always_inline void +copy_from_user ( void *dest, userptr_t src, off_t src_off, size_t len ) { + memcpy_user ( virt_to_user ( dest ), 0, src, src_off, len ); +} + +/** + * Copy data between user buffers, allowing for overlap + * + * @v dest Destination + * @v dest_off Destination offset + * @v src Source + * @v src_off Source offset + * @v len Length + */ +void memmove_user ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, size_t len ); + +/** + * Fill user buffer with a constant byte + * + * @v userptr User buffer + * @v offset Offset within buffer + * @v c Constant byte with which to fill + * @v len Length + */ +void memset_user ( userptr_t userptr, off_t offset, int c, size_t len ); + +/** + * Find length of NUL-terminated string in user buffer + * + * @v userptr User buffer + * @v offset Offset within buffer + * @ret len Length of string (excluding NUL) + */ +size_t strlen_user ( userptr_t userptr, off_t offset ); + +/** + * Find character in user buffer + * + * @v userptr User buffer + * @v offset Starting offset within buffer + * @v c Character to search for + * @v len Length of user buffer + * @ret offset Offset of character, or <0 if not found + */ +off_t memchr_user ( userptr_t userptr, off_t offset, int c, size_t len ); + #endif /* _GPXE_UACCESS_H */ diff --git a/gpxe/src/include/gpxe/umalloc.h b/gpxe/src/include/gpxe/umalloc.h index 49ec22b4..e6fc7bf0 100644 --- a/gpxe/src/include/gpxe/umalloc.h +++ b/gpxe/src/include/gpxe/umalloc.h @@ -8,10 +8,59 @@ * */ +#include +#include #include -extern userptr_t umalloc ( size_t size ); -extern userptr_t urealloc ( userptr_t ptr, size_t new_size ); -extern void ufree ( userptr_t ptr ); +/** + * Provide a user memory allocation API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_UMALLOC( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( UMALLOC_PREFIX_ ## _subsys, _api_func, _func ) + +/* Include all architecture-independent I/O API headers */ +#include + +/* Include all architecture-dependent I/O API headers */ +#include + +/** + * Reallocate external memory + * + * @v userptr Memory previously allocated by umalloc(), or UNULL + * @v new_size Requested size + * @ret userptr Allocated memory, or UNULL + * + * Calling realloc() with a new size of zero is a valid way to free a + * memory block. + */ +userptr_t urealloc ( userptr_t userptr, size_t new_size ); + +/** + * Allocate external memory + * + * @v size Requested size + * @ret userptr Memory, or UNULL + * + * Memory is guaranteed to be aligned to a page boundary. + */ +static inline __always_inline userptr_t umalloc ( size_t size ) { + return urealloc ( UNULL, size ); +} + +/** + * Free external memory + * + * @v userptr Memory allocated by umalloc(), or UNULL + * + * If @c ptr is UNULL, no action is taken. + */ +static inline __always_inline void ufree ( userptr_t userptr ) { + urealloc ( userptr, 0 ); +} #endif /* _GPXE_UMALLOC_H */ diff --git a/gpxe/src/include/gpxe/xfer.h b/gpxe/src/include/gpxe/xfer.h index 9575bf69..e592fa38 100644 --- a/gpxe/src/include/gpxe/xfer.h +++ b/gpxe/src/include/gpxe/xfer.h @@ -149,8 +149,8 @@ extern int xfer_deliver_raw ( struct xfer_interface *xfer, const void *data, size_t len ); extern int xfer_vprintf ( struct xfer_interface *xfer, const char *format, va_list args ); -extern int xfer_printf ( struct xfer_interface *xfer, - const char *format, ... ); +extern int __attribute__ (( format ( printf, 2, 3 ) )) +xfer_printf ( struct xfer_interface *xfer, const char *format, ... ); extern int xfer_seek ( struct xfer_interface *xfer, off_t offset, int whence ); extern void ignore_xfer_close ( struct xfer_interface *xfer, int rc ); diff --git a/gpxe/src/include/nic.h b/gpxe/src/include/nic.h index 65e4be71..186b2ea4 100644 --- a/gpxe/src/include/nic.h +++ b/gpxe/src/include/nic.h @@ -17,6 +17,7 @@ #include #include #include +#include #include "dhcp.h" typedef enum { diff --git a/gpxe/src/include/pxe_types.h b/gpxe/src/include/pxe_types.h index e31af062..dd9092ef 100644 --- a/gpxe/src/include/pxe_types.h +++ b/gpxe/src/include/pxe_types.h @@ -7,9 +7,8 @@ * */ -#include "stdint.h" -#include "pxe_addr.h" /* Architecture-specific PXE definitions */ -#include "errno.h" /* PXE status codes */ +#include +#include /* PXE status codes */ /** @addtogroup pxe Preboot eXecution Environment (PXE) API * @{ diff --git a/gpxe/src/include/stddef.h b/gpxe/src/include/stddef.h index 6f91d219..11ea9345 100644 --- a/gpxe/src/include/stddef.h +++ b/gpxe/src/include/stddef.h @@ -15,4 +15,10 @@ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) +/* __WCHAR_TYPE__ is defined by gcc and will change if -fshort-wchar is used */ +#ifndef __WCHAR_TYPE__ +#define __WCHAR_TYPE__ long int +#endif +typedef __WCHAR_TYPE__ wchar_t; + #endif /* STDDEF_H */ diff --git a/gpxe/src/include/stdlib.h b/gpxe/src/include/stdlib.h index ae996962..f3dc7e41 100644 --- a/gpxe/src/include/stdlib.h +++ b/gpxe/src/include/stdlib.h @@ -68,5 +68,6 @@ static inline void srand ( unsigned int seed ) { */ extern int system ( const char *command ); +extern __cdecl int main ( void ); #endif /* STDLIB_H */ diff --git a/gpxe/src/include/unistd.h b/gpxe/src/include/unistd.h index 7c44a0ce..dc1f67f6 100644 --- a/gpxe/src/include/unistd.h +++ b/gpxe/src/include/unistd.h @@ -4,7 +4,6 @@ #include #include -unsigned int sleep ( unsigned int seconds ); extern int execv ( const char *command, char * const argv[] ); /** @@ -22,10 +21,21 @@ extern int execv ( const char *command, char * const argv[] ); rc; \ } ) -void udelay(unsigned int usecs); -void mdelay(unsigned int msecs); +/* Pick up udelay() */ +#include -#define usleep(x) udelay(x) +/* + * sleep() prototype is defined by POSIX.1. usleep() prototype is + * defined by 4.3BSD. udelay() and mdelay() prototypes are chosen to + * be reasonably sensible. + * + */ + +extern unsigned int sleep ( unsigned int seconds ); +extern void mdelay ( unsigned long msecs ); +static inline __always_inline void usleep ( unsigned long usecs ) { + udelay ( usecs ); +} #endif /* _UNISTD_H */ diff --git a/gpxe/src/include/usr/aoeboot.h b/gpxe/src/include/usr/aoeboot.h deleted file mode 100644 index 0421ebcc..00000000 --- a/gpxe/src/include/usr/aoeboot.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _USR_AOEBOOT_H -#define _USR_AOEBOOT_H - -extern int aoeboot ( const char *root_path ); - -#endif /* _USR_AOEBOOT_H */ diff --git a/gpxe/src/include/usr/iscsiboot.h b/gpxe/src/include/usr/iscsiboot.h deleted file mode 100644 index b17951d5..00000000 --- a/gpxe/src/include/usr/iscsiboot.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _USR_ISCSIBOOT_H -#define _USR_ISCSIBOOT_H - -extern int iscsiboot ( const char *root_path ); - -#endif /* _USR_ISCSIBOOT_H */ diff --git a/gpxe/src/interface/efi/efi_console.c b/gpxe/src/interface/efi/efi_console.c new file mode 100644 index 00000000..b6e0dafd --- /dev/null +++ b/gpxe/src/interface/efi/efi_console.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2008 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#define ATTR_BOLD 0x08 + +#define ATTR_FCOL_MASK 0x07 +#define ATTR_FCOL_BLACK 0x00 +#define ATTR_FCOL_BLUE 0x01 +#define ATTR_FCOL_GREEN 0x02 +#define ATTR_FCOL_CYAN 0x03 +#define ATTR_FCOL_RED 0x04 +#define ATTR_FCOL_MAGENTA 0x05 +#define ATTR_FCOL_YELLOW 0x06 +#define ATTR_FCOL_WHITE 0x07 + +#define ATTR_BCOL_MASK 0x70 +#define ATTR_BCOL_BLACK 0x00 +#define ATTR_BCOL_BLUE 0x10 +#define ATTR_BCOL_GREEN 0x20 +#define ATTR_BCOL_CYAN 0x30 +#define ATTR_BCOL_RED 0x40 +#define ATTR_BCOL_MAGENTA 0x50 +#define ATTR_BCOL_YELLOW 0x60 +#define ATTR_BCOL_WHITE 0x70 + +#define ATTR_DEFAULT ATTR_FCOL_WHITE + +/** Current character attribute */ +static unsigned int efi_attr = ATTR_DEFAULT; + +/** + * Handle ANSI CUP (cursor position) + * + * @v count Parameter count + * @v params[0] Row (1 is top) + * @v params[1] Column (1 is left) + */ +static void efi_handle_cup ( unsigned int count __unused, int params[] ) { + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut; + int cx = ( params[1] - 1 ); + int cy = ( params[0] - 1 ); + + if ( cx < 0 ) + cx = 0; + if ( cy < 0 ) + cy = 0; + + conout->SetCursorPosition ( conout, cx, cy ); +} + +/** + * Handle ANSI ED (erase in page) + * + * @v count Parameter count + * @v params[0] Region to erase + */ +static void efi_handle_ed ( unsigned int count __unused, + int params[] __unused ) { + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut; + + /* We assume that we always clear the whole screen */ + assert ( params[0] == ANSIESC_ED_ALL ); + + conout->ClearScreen ( conout ); +} + +/** + * Handle ANSI SGR (set graphics rendition) + * + * @v count Parameter count + * @v params List of graphic rendition aspects + */ +static void efi_handle_sgr ( unsigned int count, int params[] ) { + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut; + static const uint8_t efi_attr_fcols[10] = { + ATTR_FCOL_BLACK, ATTR_FCOL_RED, ATTR_FCOL_GREEN, + ATTR_FCOL_YELLOW, ATTR_FCOL_BLUE, ATTR_FCOL_MAGENTA, + ATTR_FCOL_CYAN, ATTR_FCOL_WHITE, + ATTR_FCOL_WHITE, ATTR_FCOL_WHITE /* defaults */ + }; + static const uint8_t efi_attr_bcols[10] = { + ATTR_BCOL_BLACK, ATTR_BCOL_RED, ATTR_BCOL_GREEN, + ATTR_BCOL_YELLOW, ATTR_BCOL_BLUE, ATTR_BCOL_MAGENTA, + ATTR_BCOL_CYAN, ATTR_BCOL_WHITE, + ATTR_BCOL_BLACK, ATTR_BCOL_BLACK /* defaults */ + }; + unsigned int i; + int aspect; + + for ( i = 0 ; i < count ; i++ ) { + aspect = params[i]; + if ( aspect == 0 ) { + efi_attr = ATTR_DEFAULT; + } else if ( aspect == 1 ) { + efi_attr |= ATTR_BOLD; + } else if ( aspect == 22 ) { + efi_attr &= ~ATTR_BOLD; + } else if ( ( aspect >= 30 ) && ( aspect <= 39 ) ) { + efi_attr &= ~ATTR_FCOL_MASK; + efi_attr |= efi_attr_fcols[ aspect - 30 ]; + } else if ( ( aspect >= 40 ) && ( aspect <= 49 ) ) { + efi_attr &= ~ATTR_BCOL_MASK; + efi_attr |= efi_attr_bcols[ aspect - 40 ]; + } + } + + conout->SetAttribute ( conout, efi_attr ); +} + +/** EFI console ANSI escape sequence handlers */ +static struct ansiesc_handler efi_ansiesc_handlers[] = { + { ANSIESC_CUP, efi_handle_cup }, + { ANSIESC_ED, efi_handle_ed }, + { ANSIESC_SGR, efi_handle_sgr }, + { 0, NULL } +}; + +/** EFI console ANSI escape sequence context */ +static struct ansiesc_context efi_ansiesc_ctx = { + .handlers = efi_ansiesc_handlers, +}; + +/** + * Print a character to EFI console + * + * @v character Character to be printed + */ +static void efi_putchar ( int character ) { + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut; + wchar_t wstr[] = { character, 0 }; + + /* Intercept ANSI escape sequences */ + character = ansiesc_process ( &efi_ansiesc_ctx, character ); + if ( character < 0 ) + return; + + conout->OutputString ( conout, wstr ); +} + +/** + * Pointer to current ANSI output sequence + * + * While we are in the middle of returning an ANSI sequence for a + * special key, this will point to the next character to return. When + * not in the middle of such a sequence, this will point to a NUL + * (note: not "will be NULL"). + */ +static const char *ansi_input = ""; + +/** Mapping from EFI scan codes to ANSI escape sequences */ +static const char *ansi_sequences[] = { + [SCAN_UP] = "[A", + [SCAN_DOWN] = "[B", + [SCAN_RIGHT] = "[C", + [SCAN_LEFT] = "[D", + [SCAN_HOME] = "[H", + [SCAN_END] = "[F", + [SCAN_INSERT] = "[2~", + /* EFI translates an incoming backspace via the serial console + * into a SCAN_DELETE. There's not much we can do about this. + */ + [SCAN_DELETE] = "[3~", + [SCAN_PAGE_UP] = "[5~", + [SCAN_PAGE_DOWN] = "[6~", + /* EFI translates some (but not all) incoming escape sequences + * via the serial console into equivalent scancodes. When it + * doesn't recognise a sequence, it helpfully(!) translates + * the initial ESC and passes the remainder through verbatim. + * Treating SCAN_ESC as equivalent to an empty escape sequence + * works around this bug. + */ + [SCAN_ESC] = "", +}; + +/** + * Get ANSI escape sequence corresponding to EFI scancode + * + * @v scancode EFI scancode + * @ret ansi_seq ANSI escape sequence, if any, otherwise NULL + */ +static const char * scancode_to_ansi_seq ( unsigned int scancode ) { + if ( scancode < ( sizeof ( ansi_sequences ) / + sizeof ( ansi_sequences[0] ) ) ) { + return ansi_sequences[scancode]; + } + return NULL; +} + +/** + * Get character from EFI console + * + * @ret character Character read from console + */ +static int efi_getchar ( void ) { + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn; + const char *ansi_seq; + EFI_INPUT_KEY key; + EFI_STATUS efirc; + + /* If we are mid-sequence, pass out the next byte */ + if ( *ansi_input ) + return *(ansi_input++); + + /* Read key from real EFI console */ + if ( ( efirc = conin->ReadKeyStroke ( conin, &key ) ) != 0 ) { + DBG ( "EFI could not read keystroke: %lx\n", efirc ); + return 0; + } + DBG2 ( "EFI read key stroke with unicode %04x scancode %04x\n", + key.UnicodeChar, key.ScanCode ); + + /* If key has a Unicode representation, return it */ + if ( key.UnicodeChar ) + return key.UnicodeChar; + + /* Otherwise, check for a special key that we know about */ + if ( ( ansi_seq = scancode_to_ansi_seq ( key.ScanCode ) ) ) { + /* Start of escape sequence: return ESC (0x1b) */ + ansi_input = ansi_seq; + return 0x1b; + } + + return 0; +} + +/** + * Check for character ready to read from EFI console + * + * @ret True Character available to read + * @ret False No character available to read + */ +static int efi_iskey ( void ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn; + EFI_STATUS efirc; + + /* If we are mid-sequence, we are always ready */ + if ( *ansi_input ) + return 1; + + /* Check to see if the WaitForKey event has fired */ + if ( ( efirc = bs->CheckEvent ( conin->WaitForKey ) ) == 0 ) + return 1; + + return 0; +} + +struct console_driver efi_console __console_driver = { + .putchar = efi_putchar, + .getchar = efi_getchar, + .iskey = efi_iskey, +}; diff --git a/gpxe/src/interface/efi/efi_entry.c b/gpxe/src/interface/efi/efi_entry.c new file mode 100644 index 00000000..b00828ad --- /dev/null +++ b/gpxe/src/interface/efi/efi_entry.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2008 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include + +/** Image handle passed to entry point */ +EFI_HANDLE efi_image_handle; + +/** System table passed to entry point */ +EFI_SYSTEM_TABLE *efi_systab; + +/** Declared used EFI protocols */ +static struct efi_protocol efi_protocols[0] \ + __table_start ( struct efi_protocol, efi_protocols ); +static struct efi_protocol efi_protocols_end[0] \ + __table_end ( struct efi_protocol, efi_protocols ); + +/** + * EFI entry point + * + * @v image_handle Image handle + * @v systab System table + * @ret efirc EFI return status code + */ +EFI_STATUS EFIAPI efi_entry ( EFI_HANDLE image_handle, + EFI_SYSTEM_TABLE *systab ) { + EFI_BOOT_SERVICES *bs; + struct efi_protocol *prot; + EFI_STATUS efirc; + + /* Store image handle and system table pointer for future use */ + efi_image_handle = image_handle; + efi_systab = systab; + + /* Sanity checks */ + if ( ! systab ) + return EFI_NOT_AVAILABLE_YET; + if ( ! systab->ConOut ) + return EFI_NOT_AVAILABLE_YET; + if ( ! systab->BootServices ) { + DBGC ( systab, "EFI provided no BootServices entry point\n" ); + return EFI_NOT_AVAILABLE_YET; + } + if ( ! systab->RuntimeServices ) { + DBGC ( systab, "EFI provided no RuntimeServices entry " + "point\n" ); + return EFI_NOT_AVAILABLE_YET; + } + DBGC ( systab, "EFI handle %p systab %p\n", image_handle, systab ); + + /* Look up required protocols */ + bs = systab->BootServices; + for ( prot = efi_protocols ; prot < efi_protocols_end ; prot++ ) { + if ( ( efirc = bs->LocateProtocol ( &prot->u.guid, NULL, + prot->protocol ) ) != 0 ) { + DBGC ( systab, "EFI does not provide protocol %s\n", + uuid_ntoa ( &prot->u.uuid ) ); + return efirc; + } + DBGC ( systab, "EFI protocol %s is at %p\n", + uuid_ntoa ( &prot->u.uuid ), *(prot->protocol) ); + } + + /* Call to main() */ + return RC_TO_EFIRC ( main () ); +} diff --git a/gpxe/src/interface/efi/efi_io.c b/gpxe/src/interface/efi/efi_io.c new file mode 100644 index 00000000..1d4537ab --- /dev/null +++ b/gpxe/src/interface/efi/efi_io.c @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2008 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +/** @file + * + * gPXE I/O API for EFI + * + */ + +/** CPU I/O protocol */ +static EFI_CPU_IO_PROTOCOL *cpu_io; +EFI_REQUIRE_PROTOCOL ( EFI_CPU_IO_PROTOCOL, &cpu_io ); + +/** Maximum address that can be used for port I/O */ +#define MAX_PORT_ADDRESS 0xffff + +/** + * Determine whether or not address is a port I/O address + * + * @v io_addr I/O address + * @v is_port I/O address is a port I/O address + */ +#define IS_PORT_ADDRESS(io_addr) \ + ( ( ( intptr_t ) (io_addr) ) <= MAX_PORT_ADDRESS ) + +/** + * Determine EFI CPU I/O width code + * + * @v size Size of value + * @ret width EFI width code + * + * Someone at Intel clearly gets paid by the number of lines of code + * they write. No-one should ever be able to make I/O this + * convoluted. The EFI_CPU_IO_PROTOCOL_WIDTH enum is my favourite + * idiocy. + */ +static EFI_CPU_IO_PROTOCOL_WIDTH efi_width ( size_t size ) { + switch ( size ) { + case 1 : return EfiCpuIoWidthFifoUint8; + case 2 : return EfiCpuIoWidthFifoUint16; + case 4 : return EfiCpuIoWidthFifoUint32; + case 8 : return EfiCpuIoWidthFifoUint64; + default : + assert ( 0 ); + /* I wonder what this will actually do... */ + return EfiCpuIoWidthMaximum; + } +} + +/** + * Read from device + * + * @v io_addr I/O address + * @v size Size of value + * @ret data Value read + */ +unsigned long long efi_ioread ( volatile void *io_addr, size_t size ) { + EFI_CPU_IO_PROTOCOL_IO_MEM read; + unsigned long long data = 0; + EFI_STATUS efirc; + + read = ( IS_PORT_ADDRESS ( io_addr ) ? + cpu_io->Io.Read : cpu_io->Mem.Read ); + + if ( ( efirc = read ( cpu_io, efi_width ( size ), + ( intptr_t ) io_addr, 1, + ( void * ) &data ) ) != 0 ) { + DBG ( "EFI I/O read at %p failed: %lx\n", io_addr, efirc ); + return -1ULL; + } + + return data; +} + +/** + * Write to device + * + * @v data Value to write + * @v io_addr I/O address + * @v size Size of value + */ +void efi_iowrite ( unsigned long long data, volatile void *io_addr, + size_t size ) { + EFI_CPU_IO_PROTOCOL_IO_MEM write; + EFI_STATUS efirc; + + write = ( IS_PORT_ADDRESS ( io_addr ) ? + cpu_io->Io.Write : cpu_io->Mem.Write ); + + if ( ( efirc = write ( cpu_io, efi_width ( size ), + ( intptr_t ) io_addr, 1, + ( void * ) &data ) ) != 0 ) { + DBG ( "EFI I/O write at %p failed: %lx\n", io_addr, efirc ); + } +} + +/** + * String read from device + * + * @v io_addr I/O address + * @v data Data buffer + * @v size Size of values + * @v count Number of values to read + */ +void efi_ioreads ( volatile void *io_addr, void *data, + size_t size, unsigned int count ) { + EFI_CPU_IO_PROTOCOL_IO_MEM read; + EFI_STATUS efirc; + + read = ( IS_PORT_ADDRESS ( io_addr ) ? + cpu_io->Io.Read : cpu_io->Mem.Read ); + + if ( ( efirc = read ( cpu_io, efi_width ( size ), + ( intptr_t ) io_addr, count, + ( void * ) data ) ) != 0 ) { + DBG ( "EFI I/O string read at %p failed: %lx\n", + io_addr, efirc ); + } +} + +/** + * String write to device + * + * @v io_addr I/O address + * @v data Data buffer + * @v size Size of values + * @v count Number of values to write + */ +void efi_iowrites ( volatile void *io_addr, const void *data, + size_t size, unsigned int count ) { + EFI_CPU_IO_PROTOCOL_IO_MEM write; + EFI_STATUS efirc; + + write = ( IS_PORT_ADDRESS ( io_addr ) ? + cpu_io->Io.Write : cpu_io->Mem.Write ); + + if ( ( efirc = write ( cpu_io, efi_width ( size ), + ( intptr_t ) io_addr, count, + ( void * ) data ) ) != 0 ) { + DBG ( "EFI I/O write at %p failed: %lx\n", + io_addr, efirc ); + } +} + +/** + * Wait for I/O-mapped operation to complete + * + */ +static void efi_iodelay ( void ) { + /* Write to non-existent port. Probably x86-only. */ + outb ( 0, 0x80 ); +} + +PROVIDE_IOAPI_INLINE ( efi, phys_to_bus ); +PROVIDE_IOAPI_INLINE ( efi, bus_to_phys ); +PROVIDE_IOAPI_INLINE ( efi, ioremap ); +PROVIDE_IOAPI_INLINE ( efi, iounmap ); +PROVIDE_IOAPI_INLINE ( efi, io_to_bus ); +PROVIDE_IOAPI_INLINE ( efi, readb ); +PROVIDE_IOAPI_INLINE ( efi, readw ); +PROVIDE_IOAPI_INLINE ( efi, readl ); +PROVIDE_IOAPI_INLINE ( efi, readq ); +PROVIDE_IOAPI_INLINE ( efi, writeb ); +PROVIDE_IOAPI_INLINE ( efi, writew ); +PROVIDE_IOAPI_INLINE ( efi, writel ); +PROVIDE_IOAPI_INLINE ( efi, writeq ); +PROVIDE_IOAPI_INLINE ( efi, inb ); +PROVIDE_IOAPI_INLINE ( efi, inw ); +PROVIDE_IOAPI_INLINE ( efi, inl ); +PROVIDE_IOAPI_INLINE ( efi, outb ); +PROVIDE_IOAPI_INLINE ( efi, outw ); +PROVIDE_IOAPI_INLINE ( efi, outl ); +PROVIDE_IOAPI_INLINE ( efi, insb ); +PROVIDE_IOAPI_INLINE ( efi, insw ); +PROVIDE_IOAPI_INLINE ( efi, insl ); +PROVIDE_IOAPI_INLINE ( efi, outsb ); +PROVIDE_IOAPI_INLINE ( efi, outsw ); +PROVIDE_IOAPI_INLINE ( efi, outsl ); +PROVIDE_IOAPI ( efi, iodelay, efi_iodelay ); +PROVIDE_IOAPI_INLINE ( efi, mb ); diff --git a/gpxe/src/interface/efi/efi_pci.c b/gpxe/src/interface/efi/efi_pci.c new file mode 100644 index 00000000..93408165 --- /dev/null +++ b/gpxe/src/interface/efi/efi_pci.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2008 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +/** @file + * + * gPXE PCI I/O API for EFI + * + */ + +/** PCI root bridge I/O protocol */ +static EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *efipci; +EFI_REQUIRE_PROTOCOL ( EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL, &efipci ); + +static unsigned long efipci_address ( struct pci_device *pci, + unsigned long location ) { + return EFI_PCI_ADDRESS ( pci->bus, PCI_SLOT ( pci->devfn ), + PCI_FUNC ( pci->devfn ), + EFIPCI_OFFSET ( location ) ); +} + +int efipci_read ( struct pci_device *pci, unsigned long location, + void *value ) { + EFI_STATUS efirc; + + if ( ( efirc = efipci->Pci.Read ( efipci, EFIPCI_WIDTH ( location ), + efipci_address ( pci, location ), 1, + value ) ) != 0 ) { + DBG ( "EFIPCI config read from %02x:%02x.%x offset %02lx " + "failed: %lx\n", pci->bus, PCI_SLOT ( pci->devfn ), + PCI_FUNC ( pci->devfn ), EFIPCI_OFFSET ( location ), + efirc ); + return -EIO; + } + + return 0; +} + +int efipci_write ( struct pci_device *pci, unsigned long location, + unsigned long value ) { + EFI_STATUS efirc; + + if ( ( efirc = efipci->Pci.Write ( efipci, EFIPCI_WIDTH ( location ), + efipci_address ( pci, location ), 1, + &value ) ) != 0 ) { + DBG ( "EFIPCI config write to %02x:%02x.%x offset %02lx " + "failed: %lx\n", pci->bus, PCI_SLOT ( pci->devfn ), + PCI_FUNC ( pci->devfn ), EFIPCI_OFFSET ( location ), + efirc ); + return -EIO; + } + + return 0; +} + +PROVIDE_PCIAPI_INLINE ( efi, pci_max_bus ); +PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_byte ); +PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_word ); +PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_dword ); +PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_byte ); +PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_word ); +PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_dword ); diff --git a/gpxe/src/interface/efi/efi_snp.c b/gpxe/src/interface/efi/efi_snp.c new file mode 100644 index 00000000..40136623 --- /dev/null +++ b/gpxe/src/interface/efi/efi_snp.c @@ -0,0 +1,980 @@ +/* + * Copyright (C) 2008 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * gPXE EFI SNP interface + * + */ + +/** An SNP device */ +struct efi_snp_device { + /** The underlying gPXE network device */ + struct net_device *netdev; + /** The SNP structure itself */ + EFI_SIMPLE_NETWORK_PROTOCOL snp; + /** The SNP "mode" (parameters) */ + EFI_SIMPLE_NETWORK_MODE mode; + /** Outstanding TX packet count (via "interrupt status") + * + * Used in order to generate TX completions. + */ + unsigned int tx_count_interrupts; + /** Outstanding TX packet count (via "recycled tx buffers") + * + * Used in order to generate TX completions. + */ + unsigned int tx_count_txbufs; + /** Outstanding RX packet count (via "interrupt status") */ + unsigned int rx_count_interrupts; + /** Outstanding RX packet count (via WaitForPacket event) */ + unsigned int rx_count_events; +}; + +/** EFI simple network protocol GUID */ +static EFI_GUID efi_simple_network_protocol_guid + = EFI_SIMPLE_NETWORK_PROTOCOL_GUID; + +/** EFI driver binding protocol GUID */ +static EFI_GUID efi_driver_binding_protocol_guid + = EFI_DRIVER_BINDING_PROTOCOL_GUID; + +/** EFI PCI I/O protocol GUID */ +static EFI_GUID efi_pci_io_protocol_guid + = EFI_PCI_IO_PROTOCOL_GUID; + +/** + * Set EFI SNP mode based on gPXE net device parameters + * + * @v snp SNP interface + */ +static void efi_snp_set_mode ( struct efi_snp_device *snpdev ) { + struct net_device *netdev = snpdev->netdev; + EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode; + unsigned int ll_addr_len = netdev->ll_protocol->ll_addr_len; + + mode->HwAddressSize = ll_addr_len; + mode->MediaHeaderSize = netdev->ll_protocol->ll_header_len; + mode->MaxPacketSize = netdev->max_pkt_len; + mode->ReceiveFilterMask = ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST ); + assert ( ll_addr_len <= sizeof ( mode->CurrentAddress ) ); + memcpy ( &mode->CurrentAddress, netdev->ll_addr, ll_addr_len ); + memcpy ( &mode->BroadcastAddress, netdev->ll_protocol->ll_broadcast, + ll_addr_len ); + memcpy ( &mode->PermanentAddress, netdev->ll_addr, ll_addr_len ); + mode->IfType = ntohs ( netdev->ll_protocol->ll_proto ); + mode->MacAddressChangeable = TRUE; + mode->MediaPresentSupported = TRUE; + mode->MediaPresent = ( netdev_link_ok ( netdev ) ? TRUE : FALSE ); +} + +/** + * Poll net device and count received packets + * + * @v snpdev SNP device + */ +static void efi_snp_poll ( struct efi_snp_device *snpdev ) { + struct io_buffer *iobuf; + unsigned int before = 0; + unsigned int after = 0; + unsigned int arrived; + + /* We have to report packet arrivals, and this is the easiest + * way to fake it. + */ + list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list ) + before++; + netdev_poll ( snpdev->netdev ); + list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list ) + after++; + arrived = ( after - before ); + + snpdev->rx_count_interrupts += arrived; + snpdev->rx_count_events += arrived; +} + +/** + * Change SNP state from "stopped" to "started" + * + * @v snp SNP interface + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_start ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + + DBGC2 ( snpdev, "SNPDEV %p START\n", snpdev ); + + snpdev->mode.State = EfiSimpleNetworkStarted; + return 0; +} + +/** + * Change SNP state from "started" to "stopped" + * + * @v snp SNP interface + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_stop ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + + DBGC2 ( snpdev, "SNPDEV %p STOP\n", snpdev ); + + snpdev->mode.State = EfiSimpleNetworkStopped; + return 0; +} + +/** + * Open the network device + * + * @v snp SNP interface + * @v extra_rx_bufsize Extra RX buffer size, in bytes + * @v extra_tx_bufsize Extra TX buffer size, in bytes + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, + UINTN extra_rx_bufsize, UINTN extra_tx_bufsize ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + int rc; + + DBGC2 ( snpdev, "SNPDEV %p INITIALIZE (%ld extra RX, %ld extra TX)\n", + snpdev, extra_rx_bufsize, extra_tx_bufsize ); + + if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) { + DBGC ( snpdev, "SNPDEV %p could not open %s: %s\n", + snpdev, snpdev->netdev->name, strerror ( rc ) ); + return RC_TO_EFIRC ( rc ); + } + + snpdev->mode.State = EfiSimpleNetworkInitialized; + return 0; +} + +/** + * Reset the network device + * + * @v snp SNP interface + * @v ext_verify Extended verification required + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + int rc; + + DBGC2 ( snpdev, "SNPDEV %p RESET (%s extended verification)\n", + snpdev, ( ext_verify ? "with" : "without" ) ); + + netdev_close ( snpdev->netdev ); + snpdev->mode.State = EfiSimpleNetworkStarted; + + if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) { + DBGC ( snpdev, "SNPDEV %p could not reopen %s: %s\n", + snpdev, snpdev->netdev->name, strerror ( rc ) ); + return RC_TO_EFIRC ( rc ); + } + + snpdev->mode.State = EfiSimpleNetworkInitialized; + return 0; +} + +/** + * Shut down the network device + * + * @v snp SNP interface + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + + DBGC2 ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev ); + + netdev_close ( snpdev->netdev ); + snpdev->mode.State = EfiSimpleNetworkStarted; + return 0; +} + +/** + * Manage receive filters + * + * @v snp SNP interface + * @v enable Receive filters to enable + * @v disable Receive filters to disable + * @v mcast_reset Reset multicast filters + * @v mcast_count Number of multicast filters + * @v mcast Multicast filters + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_receive_filters ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINT32 enable, + UINT32 disable, BOOLEAN mcast_reset, + UINTN mcast_count, EFI_MAC_ADDRESS *mcast ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + unsigned int i; + + DBGC2 ( snpdev, "SNPDEV %p RECEIVE_FILTERS %08lx&~%08lx%s %ld mcast\n", + snpdev, enable, disable, ( mcast_reset ? " reset" : "" ), + mcast_count ); + for ( i = 0 ; i < mcast_count ; i++ ) { + DBGC2_HDA ( snpdev, i, &mcast[i], + snpdev->netdev->ll_protocol->ll_addr_len ); + } + + /* Lie through our teeth, otherwise MNP refuses to accept us */ + return 0; +} + +/** + * Set station address + * + * @v snp SNP interface + * @v reset Reset to permanent address + * @v new New station address + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_station_address ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset, + EFI_MAC_ADDRESS *new ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol; + + DBGC2 ( snpdev, "SNPDEV %p STATION_ADDRESS %s\n", snpdev, + ( reset ? "reset" : ll_protocol->ntoa ( new ) ) ); + + /* Set the MAC address */ + if ( reset ) + new = &snpdev->mode.PermanentAddress; + memcpy ( snpdev->netdev->ll_addr, new, ll_protocol->ll_addr_len ); + + /* MAC address changes take effect only on netdev_open() */ + if ( snpdev->netdev->state & NETDEV_OPEN ) { + DBGC ( snpdev, "SNPDEV %p MAC address changed while net " + "devive open\n", snpdev ); + } + + return 0; +} + +/** + * Get (or reset) statistics + * + * @v snp SNP interface + * @v reset Reset statistics + * @v stats_len Size of statistics table + * @v stats Statistics table + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_statistics ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset, + UINTN *stats_len, EFI_NETWORK_STATISTICS *stats ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + EFI_NETWORK_STATISTICS stats_buf; + + DBGC2 ( snpdev, "SNPDEV %p STATISTICS%s", snpdev, + ( reset ? " reset" : "" ) ); + + /* Gather statistics */ + memset ( &stats_buf, 0, sizeof ( stats_buf ) ); + stats_buf.TxGoodFrames = snpdev->netdev->tx_stats.good; + stats_buf.TxDroppedFrames = snpdev->netdev->tx_stats.bad; + stats_buf.TxTotalFrames = ( snpdev->netdev->tx_stats.good + + snpdev->netdev->tx_stats.bad ); + stats_buf.RxGoodFrames = snpdev->netdev->rx_stats.good; + stats_buf.RxDroppedFrames = snpdev->netdev->rx_stats.bad; + stats_buf.RxTotalFrames = ( snpdev->netdev->rx_stats.good + + snpdev->netdev->rx_stats.bad ); + if ( *stats_len > sizeof ( stats_buf ) ) + *stats_len = sizeof ( stats_buf ); + if ( stats ) + memcpy ( stats, &stats_buf, *stats_len ); + + /* Reset statistics if requested to do so */ + if ( reset ) { + memset ( &snpdev->netdev->tx_stats, 0, + sizeof ( snpdev->netdev->tx_stats ) ); + memset ( &snpdev->netdev->rx_stats, 0, + sizeof ( snpdev->netdev->rx_stats ) ); + } + + return 0; +} + +/** + * Convert multicast IP address to MAC address + * + * @v snp SNP interface + * @v ipv6 Address is IPv6 + * @v ip IP address + * @v mac MAC address + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_mcast_ip_to_mac ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ipv6, + EFI_IP_ADDRESS *ip, EFI_MAC_ADDRESS *mac ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol; + const char *ip_str; + int rc; + + ip_str = ( ipv6 ? "(IPv6)" /* FIXME when we have inet6_ntoa() */ : + inet_ntoa ( *( ( struct in_addr * ) ip ) ) ); + DBGC2 ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str ); + + /* Try to hash the address */ + if ( ( rc = ll_protocol->mc_hash ( ( ipv6 ? AF_INET6 : AF_INET ), + ip, mac ) ) != 0 ) { + DBGC ( snpdev, "SNPDEV %p could not hash %s: %s\n", + snpdev, ip_str, strerror ( rc ) ); + return RC_TO_EFIRC ( rc ); + } + + return 0; +} + +/** + * Read or write non-volatile storage + * + * @v snp SNP interface + * @v read Operation is a read + * @v offset Starting offset within NVRAM + * @v len Length of data buffer + * @v data Data buffer + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN read, + UINTN offset, UINTN len, VOID *data ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + + DBGC2 ( snpdev, "SNPDEV %p NVDATA %s %lx+%lx\n", snpdev, + ( read ? "read" : "write" ), offset, len ); + if ( ! read ) + DBGC2_HDA ( snpdev, offset, data, len ); + + return EFI_UNSUPPORTED; +} + +/** + * Read interrupt status and TX recycled buffer status + * + * @v snp SNP interface + * @v interrupts Interrupt status, or NULL + * @v txbufs Recycled transmit buffer address, or NULL + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, + UINT32 *interrupts, VOID **txbufs ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + + DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev ); + + /* Poll the network device */ + efi_snp_poll ( snpdev ); + + /* Interrupt status. In practice, this seems to be used only + * to detect TX completions. + */ + if ( interrupts ) { + *interrupts = 0; + /* Report TX completions once queue is empty; this + * avoids having to add hooks in the net device layer. + */ + if ( snpdev->tx_count_interrupts && + list_empty ( &snpdev->netdev->tx_queue ) ) { + *interrupts |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; + snpdev->tx_count_interrupts--; + } + /* Report RX */ + if ( snpdev->rx_count_interrupts ) { + *interrupts |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT; + snpdev->rx_count_interrupts--; + } + DBGC2 ( snpdev, " INTS:%02lx", *interrupts ); + } + + /* TX completions. It would be possible to design a more + * idiotic scheme for this, but it would be a challenge. + * According to the UEFI header file, txbufs will be filled in + * with a list of "recycled transmit buffers" (i.e. completed + * TX buffers). Observant readers may care to note that + * *txbufs is a void pointer. Precisely how a list of + * completed transmit buffers is meant to be represented as an + * array of voids is left as an exercise for the reader. + * + * The only users of this interface (MnpDxe/MnpIo.c and + * PxeBcDxe/Bc.c within the EFI dev kit) both just poll until + * seeing a non-NULL result return in txbufs. This is valid + * provided that they do not ever attempt to transmit more + * than one packet concurrently (and that TX never times out). + */ + if ( txbufs ) { + if ( snpdev->tx_count_txbufs && + list_empty ( &snpdev->netdev->tx_queue ) ) { + *txbufs = "Which idiot designed this API?"; + snpdev->tx_count_txbufs--; + } else { + *txbufs = NULL; + } + DBGC2 ( snpdev, " TX:%s", ( *txbufs ? "some" : "none" ) ); + } + + DBGC2 ( snpdev, "\n" ); + return 0; +} + +/** + * Start packet transmission + * + * @v snp SNP interface + * @v ll_header_len Link-layer header length, if to be filled in + * @v len Length of data buffer + * @v data Data buffer + * @v ll_src Link-layer source address, if specified + * @v ll_dest Link-layer destination address, if specified + * @v net_proto Network-layer protocol (in host order) + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, + UINTN ll_header_len, UINTN len, VOID *data, + EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest, + UINT16 *net_proto ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol; + struct io_buffer *iobuf; + int rc; + EFI_STATUS efirc; + + DBGC2 ( snpdev, "SNPDEV %p TRANSMIT %p+%lx", snpdev, data, len ); + if ( ll_header_len ) { + if ( ll_src ) { + DBGC2 ( snpdev, " src %s", + ll_protocol->ntoa ( ll_src ) ); + } + if ( ll_dest ) { + DBGC2 ( snpdev, " dest %s", + ll_protocol->ntoa ( ll_dest ) ); + } + if ( net_proto ) { + DBGC2 ( snpdev, " proto %04x", *net_proto ); + } + } + DBGC2 ( snpdev, "\n" ); + + /* Sanity checks */ + if ( ll_header_len ) { + if ( ll_header_len != ll_protocol->ll_header_len ) { + DBGC ( snpdev, "SNPDEV %p TX invalid header length " + "%ld\n", snpdev, ll_header_len ); + efirc = EFI_INVALID_PARAMETER; + goto err_sanity; + } + if ( len < ll_header_len ) { + DBGC ( snpdev, "SNPDEV %p invalid packet length %ld\n", + snpdev, len ); + efirc = EFI_BUFFER_TOO_SMALL; + goto err_sanity; + } + if ( ! ll_dest ) { + DBGC ( snpdev, "SNPDEV %p TX missing destination " + "address\n", snpdev ); + efirc = EFI_INVALID_PARAMETER; + goto err_sanity; + } + if ( ! net_proto ) { + DBGC ( snpdev, "SNPDEV %p TX missing network " + "protocol\n", snpdev ); + efirc = EFI_INVALID_PARAMETER; + goto err_sanity; + } + if ( ! ll_src ) + ll_src = &snpdev->mode.CurrentAddress; + } + + /* Allocate buffer */ + iobuf = alloc_iob ( len ); + if ( ! iobuf ) { + DBGC ( snpdev, "SNPDEV %p TX could not allocate %ld-byte " + "buffer\n", snpdev, len ); + efirc = EFI_DEVICE_ERROR; + goto err_alloc_iob; + } + memcpy ( iob_put ( iobuf, len ), data, len ); + + /* Create link-layer header, if specified */ + if ( ll_header_len ) { + iob_pull ( iobuf, ll_header_len ); + if ( ( rc = ll_protocol->push ( iobuf, ll_dest, ll_src, + htons ( *net_proto ) )) != 0 ){ + DBGC ( snpdev, "SNPDEV %p TX could not construct " + "header: %s\n", snpdev, strerror ( rc ) ); + efirc = RC_TO_EFIRC ( rc ); + goto err_ll_push; + } + } + + /* Transmit packet */ + if ( ( rc = netdev_tx ( snpdev->netdev, iobuf ) ) != 0 ) { + DBGC ( snpdev, "SNPDEV %p TX could not transmit: %s\n", + snpdev, strerror ( rc ) ); + iobuf = NULL; + efirc = RC_TO_EFIRC ( rc ); + goto err_tx; + } + + /* Record transmission as outstanding */ + snpdev->tx_count_interrupts++; + snpdev->tx_count_txbufs++; + + return 0; + + err_tx: + err_ll_push: + free_iob ( iobuf ); + err_alloc_iob: + err_sanity: + return efirc; +} + +/** + * Receive packet + * + * @v snp SNP interface + * @v ll_header_len Link-layer header length, if to be filled in + * @v len Length of data buffer + * @v data Data buffer + * @v ll_src Link-layer source address, if specified + * @v ll_dest Link-layer destination address, if specified + * @v net_proto Network-layer protocol (in host order) + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, + UINTN *ll_header_len, UINTN *len, VOID *data, + EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest, + UINT16 *net_proto ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol; + struct io_buffer *iobuf; + const void *iob_ll_dest; + const void *iob_ll_src; + uint16_t iob_net_proto; + int rc; + EFI_STATUS efirc; + + DBGC2 ( snpdev, "SNPDEV %p RECEIVE %p(+%lx)", snpdev, data, *len ); + + /* Poll the network device */ + efi_snp_poll ( snpdev ); + + /* Dequeue a packet, if one is available */ + iobuf = netdev_rx_dequeue ( snpdev->netdev ); + if ( ! iobuf ) { + DBGC2 ( snpdev, "\n" ); + efirc = EFI_NOT_READY; + goto out_no_packet; + } + DBGC2 ( snpdev, "+%zx\n", iob_len ( iobuf ) ); + + /* Return packet to caller */ + memcpy ( data, iobuf->data, iob_len ( iobuf ) ); + *len = iob_len ( iobuf ); + + /* Attempt to decode link-layer header */ + if ( ( rc = ll_protocol->pull ( iobuf, &iob_ll_dest, &iob_ll_src, + &iob_net_proto ) ) != 0 ) { + DBGC ( snpdev, "SNPDEV %p could not parse header: %s\n", + snpdev, strerror ( rc ) ); + efirc = RC_TO_EFIRC ( rc ); + goto out_bad_ll_header; + } + + /* Return link-layer header parameters to caller, if required */ + if ( ll_header_len ) + *ll_header_len = ll_protocol->ll_header_len; + if ( ll_src ) + memcpy ( ll_src, iob_ll_src, ll_protocol->ll_addr_len ); + if ( ll_dest ) + memcpy ( ll_dest, iob_ll_dest, ll_protocol->ll_addr_len ); + if ( net_proto ) + *net_proto = ntohs ( iob_net_proto ); + + efirc = 0; + + out_bad_ll_header: + free_iob ( iobuf ); +out_no_packet: + return efirc; +} + +/** + * Poll event + * + * @v event Event + * @v context Event context + */ +static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event, + VOID *context ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + struct efi_snp_device *snpdev = context; + + DBGCP ( snpdev, "SNPDEV %p WAIT_FOR_PACKET\n", snpdev ); + + /* Do nothing unless the net device is open */ + if ( ! ( snpdev->netdev->state & NETDEV_OPEN ) ) + return; + + /* Poll the network device */ + efi_snp_poll ( snpdev ); + + /* Fire event if packets have been received */ + if ( snpdev->rx_count_events != 0 ) { + DBGC2 ( snpdev, "SNPDEV %p firing WaitForPacket event\n", + snpdev ); + bs->SignalEvent ( event ); + snpdev->rx_count_events--; + } +} + +/** SNP interface */ +static EFI_SIMPLE_NETWORK_PROTOCOL efi_snp_device_snp = { + .Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION, + .Start = efi_snp_start, + .Stop = efi_snp_stop, + .Initialize = efi_snp_initialize, + .Reset = efi_snp_reset, + .Shutdown = efi_snp_shutdown, + .ReceiveFilters = efi_snp_receive_filters, + .StationAddress = efi_snp_station_address, + .Statistics = efi_snp_statistics, + .MCastIpToMac = efi_snp_mcast_ip_to_mac, + .NvData = efi_snp_nvdata, + .GetStatus = efi_snp_get_status, + .Transmit = efi_snp_transmit, + .Receive = efi_snp_receive, +}; + +/** + * Locate net device corresponding to EFI device + * + * @v driver EFI driver + * @v device EFI device + * @ret netdev Net device, or NULL if not found + */ +static struct net_device * +efi_snp_netdev ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + union { + EFI_PCI_IO_PROTOCOL *pci; + void *interface; + } u; + UINTN pci_segment, pci_bus, pci_dev, pci_fn; + unsigned int pci_busdevfn; + struct net_device *netdev = NULL; + EFI_STATUS efirc; + + /* See if device is a PCI device */ + if ( ( efirc = bs->OpenProtocol ( device, + &efi_pci_io_protocol_guid, + &u.interface, + driver->DriverBindingHandle, + device, + EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){ + DBGCP ( driver, "SNPDRV %p device %p is not a PCI device\n", + driver, device ); + goto out_no_pci_io; + } + + /* Get PCI bus:dev.fn address */ + if ( ( efirc = u.pci->GetLocation ( u.pci, &pci_segment, &pci_bus, + &pci_dev, &pci_fn ) ) != 0 ) { + DBGC ( driver, "SNPDRV %p device %p could not get PCI " + "location: %lx\n", driver, device, efirc ); + goto out_no_pci_location; + } + DBGCP ( driver, "SNPDRV %p device %p is PCI %04lx:%02lx:%02lx.%lx\n", + driver, device, pci_segment, pci_bus, pci_dev, pci_fn ); + + /* Look up corresponding network device */ + pci_busdevfn = PCI_BUSDEVFN ( pci_bus, PCI_DEVFN ( pci_dev, pci_fn ) ); + if ( ( netdev = find_netdev_by_location ( BUS_TYPE_PCI, + pci_busdevfn ) ) == NULL ) { + DBGCP ( driver, "SNPDRV %p device %p is not a gPXE network " + "device\n", driver, device ); + goto out_no_netdev; + } + DBGC ( driver, "SNPDRV %p device %p is %s\n", + driver, device, netdev->name ); + + out_no_netdev: + out_no_pci_location: + bs->CloseProtocol ( device, &efi_pci_io_protocol_guid, + driver->DriverBindingHandle, device ); + out_no_pci_io: + return netdev; +} + +/** + * Locate SNP corresponding to EFI device + * + * @v driver EFI driver + * @v device EFI device + * @ret snp EFI SNP, or NULL if not found + */ +static struct efi_snp_device * +efi_snp_snpdev ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + union { + EFI_SIMPLE_NETWORK_PROTOCOL *snp; + void *interface; + } u; + struct efi_snp_device *snpdev; + EFI_STATUS efirc; + + if ( ( efirc = bs->OpenProtocol ( device, + &efi_simple_network_protocol_guid, + &u.interface, + driver->DriverBindingHandle, + device, + EFI_OPEN_PROTOCOL_GET_PROTOCOL))!=0){ + DBGC ( driver, "SNPDRV %p device %p could not locate SNP: " + "%lx\n", driver, device, efirc ); + return NULL; + } + + snpdev = container_of ( u.snp, struct efi_snp_device, snp ); + DBGCP ( driver, "SNPDRV %p device %p is SNPDEV %p\n", + driver, device, snpdev ); + return snpdev; +} + +/** + * Check to see if driver supports a device + * + * @v driver EFI driver + * @v device EFI device + * @v child Path to child device, if any + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_driver_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver, + EFI_HANDLE device, + EFI_DEVICE_PATH_PROTOCOL *child ) { + struct net_device *netdev; + + DBGCP ( driver, "SNPDRV %p DRIVER_SUPPORTED %p (%p)\n", + driver, device, child ); + + netdev = efi_snp_netdev ( driver, device ); + return ( netdev ? 0 : EFI_UNSUPPORTED ); +} + +/** + * Attach driver to device + * + * @v driver EFI driver + * @v device EFI device + * @v child Path to child device, if any + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver, + EFI_HANDLE device, + EFI_DEVICE_PATH_PROTOCOL *child ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + struct efi_snp_device *snpdev; + struct net_device *netdev; + EFI_STATUS efirc; + + DBGCP ( driver, "SNPDRV %p DRIVER_START %p (%p)\n", + driver, device, child ); + + /* Allocate the SNP device */ + snpdev = zalloc ( sizeof ( *snpdev ) ); + if ( ! snpdev ) { + efirc = EFI_OUT_OF_RESOURCES; + goto err_alloc_snp; + } + + /* Identify the net device */ + netdev = efi_snp_netdev ( driver, device ); + if ( ! netdev ) { + DBGC ( snpdev, "SNPDEV %p cannot find netdev for device %p\n", + snpdev, device ); + efirc = EFI_UNSUPPORTED; + goto err_no_netdev; + } + snpdev->netdev = netdev_get ( netdev ); + + /* Sanity check */ + if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) { + DBGC ( snpdev, "SNPDEV %p cannot support link-layer address " + "length %zd for %s\n", snpdev, + netdev->ll_protocol->ll_addr_len, netdev->name ); + efirc = EFI_INVALID_PARAMETER; + goto err_ll_addr_len; + } + + /* Populate the SNP structure */ + memcpy ( &snpdev->snp, &efi_snp_device_snp, sizeof ( snpdev->snp ) ); + snpdev->snp.Mode = &snpdev->mode; + if ( ( efirc = bs->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY, + efi_snp_wait_for_packet, snpdev, + &snpdev->snp.WaitForPacket ) ) != 0 ){ + DBGC ( snpdev, "SNPDEV %p could not create event: %lx\n", + snpdev, efirc ); + goto err_create_event; + } + + /* Populate the SNP mode structure */ + snpdev->mode.State = EfiSimpleNetworkStopped; + efi_snp_set_mode ( snpdev ); + + /* Install the SNP */ + if ( ( efirc = bs->InstallProtocolInterface ( &device, + &efi_simple_network_protocol_guid, + EFI_NATIVE_INTERFACE, &snpdev->snp ) ) != 0 ) { + DBGC ( snpdev, "SNPDEV %p could not install protocol: %lx\n", + snpdev, efirc ); + goto err_install_protocol_interface; + } + + DBGC ( snpdev, "SNPDEV %p installed for %s on device %p\n", + snpdev, netdev->name, device ); + return 0; + + bs->UninstallProtocolInterface ( device, + &efi_simple_network_protocol_guid, + &snpdev->snp ); + err_install_protocol_interface: + bs->CloseEvent ( snpdev->snp.WaitForPacket ); + err_create_event: + err_ll_addr_len: + netdev_put ( netdev ); + err_no_netdev: + free ( snpdev ); + err_alloc_snp: + return efirc; +} + +/** + * Detach driver from device + * + * @v driver EFI driver + * @v device EFI device + * @v num_children Number of child devices + * @v children List of child devices + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver, + EFI_HANDLE device, + UINTN num_children, + EFI_HANDLE *children ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + struct efi_snp_device *snpdev; + + DBGCP ( driver, "SNPDRV %p DRIVER_STOP %p (%ld %p)\n", + driver, device, num_children, children ); + + /* Locate SNP device */ + snpdev = efi_snp_snpdev ( driver, device ); + if ( ! snpdev ) { + DBGC ( driver, "SNPDRV %p device %p could not find SNPDEV\n", + driver, device ); + return EFI_DEVICE_ERROR; + } + + /* Uninstall the SNP */ + bs->UninstallProtocolInterface ( device, + &efi_simple_network_protocol_guid, + &snpdev->snp ); + bs->CloseEvent ( snpdev->snp.WaitForPacket ); + netdev_put ( snpdev->netdev ); + free ( snpdev ); + return 0; +} + +/** EFI SNP driver binding */ +static EFI_DRIVER_BINDING_PROTOCOL efi_snp_binding = { + efi_snp_driver_supported, + efi_snp_driver_start, + efi_snp_driver_stop, + 0x10, + NULL, + NULL +}; + +/** + * Install EFI SNP driver + * + * @ret rc Return status code + */ +int efi_snp_install ( void ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_DRIVER_BINDING_PROTOCOL *driver = &efi_snp_binding; + EFI_STATUS efirc; + + driver->ImageHandle = efi_image_handle; + if ( ( efirc = bs->InstallProtocolInterface ( + &driver->DriverBindingHandle, + &efi_driver_binding_protocol_guid, + EFI_NATIVE_INTERFACE, + driver ) ) != 0 ) { + DBGC ( driver, "SNPDRV %p could not install driver binding: " + "%lx\n", driver, efirc ); + return EFIRC_TO_RC ( efirc ); + } + + DBGC ( driver, "SNPDRV %p driver binding installed as %p\n", + driver, driver->DriverBindingHandle ); + return 0; +} diff --git a/gpxe/src/interface/efi/efi_timer.c b/gpxe/src/interface/efi/efi_timer.c new file mode 100644 index 00000000..b4e54a65 --- /dev/null +++ b/gpxe/src/interface/efi/efi_timer.c @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2008 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +/** @file + * + * gPXE timer API for EFI + * + */ + +/** Scale factor to apply to CPU timer 0 + * + * The timer is scaled down in order to ensure that reasonable values + * for "number of ticks" don't exceed the size of an unsigned long. + */ +#define EFI_TIMER0_SHIFT 12 + +/** Calibration time */ +#define EFI_CALIBRATE_DELAY_MS 1 + +/** CPU protocol */ +static EFI_CPU_ARCH_PROTOCOL *cpu_arch; +EFI_REQUIRE_PROTOCOL ( EFI_CPU_ARCH_PROTOCOL, &cpu_arch ); + +/** + * Delay for a fixed number of microseconds + * + * @v usecs Number of microseconds for which to delay + */ +static void efi_udelay ( unsigned long usecs ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_STATUS efirc; + + if ( ( efirc = bs->Stall ( usecs ) ) != 0 ) { + DBG ( "EFI could not delay for %ldus: %lx\n", + usecs, efirc ); + /* Probably screwed */ + } +} + +/** + * Get current system time in ticks + * + * @ret ticks Current time, in ticks + */ +static unsigned long efi_currticks ( void ) { + UINT64 time; + EFI_STATUS efirc; + + /* Read CPU timer 0 (TSC) */ + if ( ( efirc = cpu_arch->GetTimerValue ( cpu_arch, 0, &time, + NULL ) ) != 0 ) { + DBG ( "EFI could not read CPU timer: %lx\n", efirc ); + /* Probably screwed */ + return -1UL; + } + + return ( time >> EFI_TIMER0_SHIFT ); +} + +/** + * Get number of ticks per second + * + * @ret ticks_per_sec Number of ticks per second + */ +static unsigned long efi_ticks_per_sec ( void ) { + static unsigned long ticks_per_sec = 0; + + /* Calibrate timer, if necessary. EFI does nominally provide + * the timer speed via the (optional) TimerPeriod parameter to + * the GetTimerValue() call, but it gets the speed slightly + * wrong. By up to three orders of magnitude. Not helpful. + */ + if ( ! ticks_per_sec ) { + unsigned long start; + unsigned long elapsed; + + DBG ( "Calibrating EFI timer with a %d ms delay\n", + EFI_CALIBRATE_DELAY_MS ); + start = currticks(); + mdelay ( EFI_CALIBRATE_DELAY_MS ); + elapsed = ( currticks() - start ); + ticks_per_sec = ( elapsed * ( 1000 / EFI_CALIBRATE_DELAY_MS )); + DBG ( "EFI CPU timer calibrated at %ld ticks in %d ms (%ld " + "ticks/sec)\n", elapsed, EFI_CALIBRATE_DELAY_MS, + ticks_per_sec ); + } + + return ticks_per_sec; +} + +PROVIDE_TIMER ( efi, udelay, efi_udelay ); +PROVIDE_TIMER ( efi, currticks, efi_currticks ); +PROVIDE_TIMER ( efi, ticks_per_sec, efi_ticks_per_sec ); diff --git a/gpxe/src/interface/efi/efi_uaccess.c b/gpxe/src/interface/efi/efi_uaccess.c new file mode 100644 index 00000000..1c54c031 --- /dev/null +++ b/gpxe/src/interface/efi/efi_uaccess.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2008 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +/** @file + * + * gPXE user access API for EFI + * + */ + +PROVIDE_UACCESS_INLINE ( efi, phys_to_user ); +PROVIDE_UACCESS_INLINE ( efi, user_to_phys ); +PROVIDE_UACCESS_INLINE ( efi, virt_to_user ); +PROVIDE_UACCESS_INLINE ( efi, user_to_virt ); +PROVIDE_UACCESS_INLINE ( efi, userptr_add ); +PROVIDE_UACCESS_INLINE ( efi, memcpy_user ); +PROVIDE_UACCESS_INLINE ( efi, memmove_user ); +PROVIDE_UACCESS_INLINE ( efi, memset_user ); +PROVIDE_UACCESS_INLINE ( efi, strlen_user ); +PROVIDE_UACCESS_INLINE ( efi, memchr_user ); diff --git a/gpxe/src/interface/efi/efi_umalloc.c b/gpxe/src/interface/efi/efi_umalloc.c new file mode 100644 index 00000000..d7357a1d --- /dev/null +++ b/gpxe/src/interface/efi/efi_umalloc.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2008 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include + +/** @file + * + * gPXE user memory allocation API for EFI + * + */ + +/** Equivalent of NOWHERE for user pointers */ +#define UNOWHERE ( ~UNULL ) + +/** + * Reallocate external memory + * + * @v old_ptr Memory previously allocated by umalloc(), or UNULL + * @v new_size Requested size + * @ret new_ptr Allocated memory, or UNULL + * + * Calling realloc() with a new size of zero is a valid way to free a + * memory block. + */ +static userptr_t efi_urealloc ( userptr_t old_ptr, size_t new_size ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_PHYSICAL_ADDRESS phys_addr; + unsigned int new_pages, old_pages; + userptr_t new_ptr = UNOWHERE; + size_t old_size; + EFI_STATUS efirc; + + /* Allocate new memory if necessary. If allocation fails, + * return without touching the old block. + */ + if ( new_size ) { + new_pages = ( EFI_SIZE_TO_PAGES ( new_size ) + 1 ); + if ( ( efirc = bs->AllocatePages ( AllocateAnyPages, + EfiBootServicesData, + new_pages, + &phys_addr ) ) != 0 ) { + DBG ( "EFI could not allocate %d pages: %lx\n", + new_pages, efirc ); + return UNULL; + } + assert ( phys_addr != 0 ); + new_ptr = phys_to_user ( phys_addr + EFI_PAGE_SIZE ); + copy_to_user ( new_ptr, -EFI_PAGE_SIZE, + &new_size, sizeof ( new_size ) ); + DBG ( "EFI allocated %d pages at %llx\n", + new_pages, phys_addr ); + } + + /* Copy across relevant part of the old data region (if any), + * then free it. Note that at this point either (a) new_ptr + * is valid, or (b) new_size is 0; either way, the memcpy() is + * valid. + */ + if ( old_ptr && ( old_ptr != UNOWHERE ) ) { + copy_from_user ( &old_size, old_ptr, -EFI_PAGE_SIZE, + sizeof ( old_size ) ); + memcpy_user ( new_ptr, 0, old_ptr, 0, + ( (old_size < new_size) ? old_size : new_size )); + old_pages = ( EFI_SIZE_TO_PAGES ( old_size ) + 1 ); + phys_addr = user_to_phys ( old_ptr, -EFI_PAGE_SIZE ); + if ( ( efirc = bs->FreePages ( phys_addr, old_pages ) ) != 0 ){ + DBG ( "EFI could not free %d pages at %llx: %lx\n", + old_pages, phys_addr, efirc ); + /* Not fatal; we have leaked memory but successfully + * allocated (if asked to do so). + */ + } + DBG ( "EFI freed %d pages at %llx\n", old_pages, phys_addr ); + } + + return new_ptr; +} + +PROVIDE_UMALLOC ( efi, urealloc, efi_urealloc ); diff --git a/gpxe/src/interface/pxe/pxe_undi.c b/gpxe/src/interface/pxe/pxe_undi.c index 5d06f2d8..4e4a3da0 100644 --- a/gpxe/src/interface/pxe/pxe_undi.c +++ b/gpxe/src/interface/pxe/pxe_undi.c @@ -199,9 +199,10 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT struct DataBlk *datablk; struct io_buffer *iobuf; struct net_protocol *net_protocol; + struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol; char destaddr[MAX_LL_ADDR_LEN]; const void *ll_dest; - size_t ll_hlen = pxe_netdev->ll_protocol->ll_header_len; + size_t ll_hlen = ll_protocol->ll_header_len; size_t len; unsigned int i; int rc; @@ -259,17 +260,17 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT copy_from_real ( destaddr, undi_transmit->DestAddr.segment, undi_transmit->DestAddr.offset, - pxe_netdev->ll_protocol->ll_addr_len ); + ll_protocol->ll_addr_len ); ll_dest = destaddr; } else { DBG ( " BCAST" ); - ll_dest = pxe_netdev->ll_protocol->ll_broadcast; + ll_dest = ll_protocol->ll_broadcast; } /* Add link-layer header */ - if ( ( rc = pxe_netdev->ll_protocol->push ( iobuf, pxe_netdev, - net_protocol, - ll_dest )) != 0 ){ + if ( ( rc = ll_protocol->push ( iobuf, ll_dest, + pxe_netdev->ll_addr, + net_protocol->net_proto ))!=0){ free_iob ( iobuf ); undi_transmit->Status = PXENV_STATUS ( rc ); return PXENV_EXIT_FAILURE; @@ -391,10 +392,10 @@ PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS *undi_get_statistics ) { DBG ( "PXENV_UNDI_GET_STATISTICS" ); - undi_get_statistics->XmtGoodFrames = pxe_netdev->stats.tx_ok; - undi_get_statistics->RcvGoodFrames = pxe_netdev->stats.rx_ok; - undi_get_statistics->RcvCRCErrors = pxe_netdev->stats.rx_err; - undi_get_statistics->RcvResourceErrors = pxe_netdev->stats.rx_err; + undi_get_statistics->XmtGoodFrames = pxe_netdev->tx_stats.good; + undi_get_statistics->RcvGoodFrames = pxe_netdev->rx_stats.good; + undi_get_statistics->RcvCRCErrors = pxe_netdev->rx_stats.bad; + undi_get_statistics->RcvResourceErrors = pxe_netdev->rx_stats.bad; undi_get_statistics->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; @@ -408,7 +409,8 @@ PXENV_EXIT_t pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS *undi_clear_statistics ) { DBG ( "PXENV_UNDI_CLEAR_STATISTICS" ); - memset ( &pxe_netdev->stats, 0, sizeof ( pxe_netdev->stats ) ); + memset ( &pxe_netdev->tx_stats, 0, sizeof ( pxe_netdev->tx_stats ) ); + memset ( &pxe_netdev->rx_stats, 0, sizeof ( pxe_netdev->rx_stats ) ); undi_clear_statistics->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; @@ -545,6 +547,7 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { struct io_buffer *iobuf; size_t len; struct ll_protocol *ll_protocol; + const void *ll_dest; const void *ll_source; uint16_t net_proto; size_t ll_hlen; @@ -625,9 +628,8 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { /* Strip link-layer header */ ll_protocol = pxe_netdev->ll_protocol; - if ( ( rc = ll_protocol->pull ( iobuf, pxe_netdev, - &net_proto, - &ll_source ) ) != 0 ) { + if ( ( rc = ll_protocol->pull ( iobuf, &ll_dest, &ll_source, + &net_proto ) ) != 0 ) { /* Assume unknown net_proto and no ll_source */ net_proto = 0; ll_source = NULL; diff --git a/gpxe/src/net/aoe.c b/gpxe/src/net/aoe.c index e3f84e5a..ec3814bf 100644 --- a/gpxe/src/net/aoe.c +++ b/gpxe/src/net/aoe.c @@ -94,6 +94,13 @@ static int aoe_send_command ( struct aoe_session *aoe ) { return -ENETUNREACH; } + /* If we are transmitting anything that requires a response, + * start the retransmission timer. Do this before attempting + * to allocate the I/O buffer, in case allocation itself + * fails. + */ + start_timer ( &aoe->timer ); + /* Calculate count and data_out_len for this subcommand */ count = command->cb.count.native; if ( count > AOE_MAX_COUNT ) @@ -101,8 +108,8 @@ static int aoe_send_command ( struct aoe_session *aoe ) { data_out_len = ( command->data_out ? ( count * ATA_SECTOR_SIZE ) : 0 ); /* Create outgoing I/O buffer */ - iobuf = alloc_iob ( ETH_HLEN + sizeof ( *aoehdr ) + sizeof ( *aoecmd ) + - data_out_len ); + iobuf = alloc_iob ( ETH_HLEN + sizeof ( *aoehdr ) + + sizeof ( *aoecmd ) + data_out_len ); if ( ! iobuf ) return -ENOMEM; iob_reserve ( iobuf, ETH_HLEN ); @@ -133,7 +140,6 @@ static int aoe_send_command ( struct aoe_session *aoe ) { aoe->command_offset, data_out_len ); /* Send packet */ - start_timer ( &aoe->timer ); return net_tx ( iobuf, aoe->netdev, &aoe_protocol, aoe->target ); } @@ -231,7 +237,8 @@ static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr, * @ret rc Return status code * */ -static int aoe_rx ( struct io_buffer *iobuf, struct net_device *netdev __unused, +static int aoe_rx ( struct io_buffer *iobuf, + struct net_device *netdev __unused, const void *ll_source ) { struct aoehdr *aoehdr = iobuf->data; unsigned int len = iob_len ( iobuf ); diff --git a/gpxe/src/net/ethernet.c b/gpxe/src/net/ethernet.c index 7b1c496f..3b289705 100644 --- a/gpxe/src/net/ethernet.c +++ b/gpxe/src/net/ethernet.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -41,19 +42,19 @@ static uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; * Add Ethernet link-layer header * * @v iobuf I/O buffer - * @v netdev Network device - * @v net_protocol Network-layer protocol * @v ll_dest Link-layer destination address + * @v ll_source Source link-layer address + * @v net_proto Network-layer protocol, in network-byte order + * @ret rc Return status code */ -static int eth_push ( struct io_buffer *iobuf, struct net_device *netdev, - struct net_protocol *net_protocol, - const void *ll_dest ) { +static int eth_push ( struct io_buffer *iobuf, const void *ll_dest, + const void *ll_source, uint16_t net_proto ) { struct ethhdr *ethhdr = iob_push ( iobuf, sizeof ( *ethhdr ) ); /* Build Ethernet header */ memcpy ( ethhdr->h_dest, ll_dest, ETH_ALEN ); - memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN ); - ethhdr->h_protocol = net_protocol->net_proto; + memcpy ( ethhdr->h_source, ll_source, ETH_ALEN ); + ethhdr->h_protocol = net_proto; return 0; } @@ -62,14 +63,13 @@ static int eth_push ( struct io_buffer *iobuf, struct net_device *netdev, * Remove Ethernet link-layer header * * @v iobuf I/O buffer - * @v netdev Network device - * @v net_proto Network-layer protocol, in network-byte order - * @v ll_source Source link-layer address + * @ret ll_dest Link-layer destination address + * @ret ll_source Source link-layer address + * @ret net_proto Network-layer protocol, in network-byte order * @ret rc Return status code */ -static int eth_pull ( struct io_buffer *iobuf, - struct net_device *netdev __unused, - uint16_t *net_proto, const void **ll_source ) { +static int eth_pull ( struct io_buffer *iobuf, const void **ll_dest, + const void **ll_source, uint16_t *net_proto ) { struct ethhdr *ethhdr = iobuf->data; /* Sanity check */ @@ -83,8 +83,9 @@ static int eth_pull ( struct io_buffer *iobuf, iob_pull ( iobuf, sizeof ( *ethhdr ) ); /* Fill in required fields */ - *net_proto = ethhdr->h_protocol; + *ll_dest = ethhdr->h_dest; *ll_source = ethhdr->h_source; + *net_proto = ethhdr->h_protocol; return 0; } @@ -92,8 +93,8 @@ static int eth_pull ( struct io_buffer *iobuf, /** * Transcribe Ethernet address * - * @v ll_addr Link-layer address - * @ret string Link-layer address in human-readable format + * @v ll_addr Link-layer address + * @ret string Link-layer address in human-readable format */ const char * eth_ntoa ( const void *ll_addr ) { static char buf[18]; /* "00:00:00:00:00:00" */ @@ -105,6 +106,32 @@ const char * eth_ntoa ( const void *ll_addr ) { return buf; } +/** + * Hash multicast address + * + * @v af Address family + * @v net_addr Network-layer address + * @v ll_addr Link-layer address to fill in + * @ret rc Return status code + */ +static int eth_mc_hash ( unsigned int af, const void *net_addr, + void *ll_addr ) { + const uint8_t *net_addr_bytes = net_addr; + uint8_t *ll_addr_bytes = ll_addr; + + switch ( af ) { + case AF_INET: + ll_addr_bytes[0] = 0x01; + ll_addr_bytes[1] = 0x00; + ll_addr_bytes[2] = 0x5e; + ll_addr_bytes[3] = net_addr_bytes[1] & 0x7f; + ll_addr_bytes[4] = net_addr_bytes[2]; + ll_addr_bytes[5] = net_addr_bytes[3]; + default: + return -ENOTSUP; + } +} + /** Ethernet protocol */ struct ll_protocol ethernet_protocol __ll_protocol = { .name = "Ethernet", @@ -115,4 +142,5 @@ struct ll_protocol ethernet_protocol __ll_protocol = { .push = eth_push, .pull = eth_pull, .ntoa = eth_ntoa, + .mc_hash = eth_mc_hash, }; diff --git a/gpxe/src/net/infiniband.c b/gpxe/src/net/infiniband.c index ab76742e..fb6fca7d 100644 --- a/gpxe/src/net/infiniband.c +++ b/gpxe/src/net/infiniband.c @@ -46,10 +46,12 @@ struct list_head ib_devices = LIST_HEAD_INIT ( ib_devices ); * * @v ibdev Infiniband device * @v num_cqes Number of completion queue entries + * @v op Completion queue operations * @ret cq New completion queue */ -struct ib_completion_queue * ib_create_cq ( struct ib_device *ibdev, - unsigned int num_cqes ) { +struct ib_completion_queue * +ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes, + struct ib_completion_queue_operations *op ) { struct ib_completion_queue *cq; int rc; @@ -58,22 +60,28 @@ struct ib_completion_queue * ib_create_cq ( struct ib_device *ibdev, /* Allocate and initialise data structure */ cq = zalloc ( sizeof ( *cq ) ); if ( ! cq ) - return NULL; + goto err_alloc_cq; cq->num_cqes = num_cqes; INIT_LIST_HEAD ( &cq->work_queues ); + cq->op = op; /* Perform device-specific initialisation and get CQN */ if ( ( rc = ibdev->op->create_cq ( ibdev, cq ) ) != 0 ) { DBGC ( ibdev, "IBDEV %p could not initialise completion " "queue: %s\n", ibdev, strerror ( rc ) ); - free ( cq ); - return NULL; + goto err_dev_create_cq; } DBGC ( ibdev, "IBDEV %p created %d-entry completion queue %p (%p) " "with CQN %#lx\n", ibdev, num_cqes, cq, ib_cq_get_drvdata ( cq ), cq->cqn ); return cq; + + ibdev->op->destroy_cq ( ibdev, cq ); + err_dev_create_cq: + free ( cq ); + err_alloc_cq: + return NULL; } /** @@ -120,7 +128,9 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev, ( num_recv_wqes * sizeof ( qp->recv.iobufs[0] ) ) ); qp = zalloc ( total_size ); if ( ! qp ) - return NULL; + goto err_alloc_qp; + qp->ibdev = ibdev; + list_add ( &qp->list, &ibdev->qps ); qp->qkey = qkey; qp->send.qp = qp; qp->send.is_send = 1; @@ -134,15 +144,13 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev, qp->recv.num_wqes = num_recv_wqes; qp->recv.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) + ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) )); + INIT_LIST_HEAD ( &qp->mgids ); /* Perform device-specific initialisation and get QPN */ if ( ( rc = ibdev->op->create_qp ( ibdev, qp ) ) != 0 ) { DBGC ( ibdev, "IBDEV %p could not initialise queue pair: " "%s\n", ibdev, strerror ( rc ) ); - list_del ( &qp->send.list ); - list_del ( &qp->recv.list ); - free ( qp ); - return NULL; + goto err_dev_create_qp; } DBGC ( ibdev, "IBDEV %p created queue pair %p (%p) with QPN %#lx\n", @@ -154,6 +162,15 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev, ibdev, qp->qpn, num_recv_wqes, qp->recv.iobufs, ( ( ( void * ) qp ) + total_size ) ); return qp; + + ibdev->op->destroy_qp ( ibdev, qp ); + err_dev_create_qp: + list_del ( &qp->send.list ); + list_del ( &qp->recv.list ); + list_del ( &qp->list ); + free ( qp ); + err_alloc_qp: + return NULL; } /** @@ -190,14 +207,79 @@ int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp, * @v qp Queue pair */ void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) { + struct io_buffer *iobuf; + unsigned int i; + DBGC ( ibdev, "IBDEV %p destroying QPN %#lx\n", ibdev, qp->qpn ); + + assert ( list_empty ( &qp->mgids ) ); + + /* Perform device-specific destruction */ ibdev->op->destroy_qp ( ibdev, qp ); + + /* Complete any remaining I/O buffers with errors */ + for ( i = 0 ; i < qp->send.num_wqes ; i++ ) { + if ( ( iobuf = qp->send.iobufs[i] ) != NULL ) + ib_complete_send ( ibdev, qp, iobuf, -ECANCELED ); + } + for ( i = 0 ; i < qp->recv.num_wqes ; i++ ) { + if ( ( iobuf = qp->recv.iobufs[i] ) != NULL ) { + ib_complete_recv ( ibdev, qp, NULL, iobuf, + -ECANCELED ); + } + } + + /* Remove work queues from completion queue */ list_del ( &qp->send.list ); list_del ( &qp->recv.list ); + + /* Free QP */ + list_del ( &qp->list ); free ( qp ); } +/** + * Find queue pair by QPN + * + * @v ibdev Infiniband device + * @v qpn Queue pair number + * @ret qp Queue pair, or NULL + */ +struct ib_queue_pair * ib_find_qp_qpn ( struct ib_device *ibdev, + unsigned long qpn ) { + struct ib_queue_pair *qp; + + list_for_each_entry ( qp, &ibdev->qps, list ) { + if ( qp->qpn == qpn ) + return qp; + } + return NULL; +} + +/** + * Find queue pair by multicast GID + * + * @v ibdev Infiniband device + * @v gid Multicast GID + * @ret qp Queue pair, or NULL + */ +struct ib_queue_pair * ib_find_qp_mgid ( struct ib_device *ibdev, + struct ib_gid *gid ) { + struct ib_queue_pair *qp; + struct ib_multicast_gid *mgid; + + list_for_each_entry ( qp, &ibdev->qps, list ) { + list_for_each_entry ( mgid, &qp->mgids, list ) { + if ( memcmp ( &mgid->gid, gid, + sizeof ( mgid->gid ) ) == 0 ) { + return qp; + } + } + } + return NULL; +} + /** * Find work queue belonging to completion queue * @@ -217,142 +299,158 @@ struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq, return NULL; } -/*************************************************************************** - * - * Management datagram operations - * - *************************************************************************** - */ - /** - * Get port information + * Post send work queue entry * * @v ibdev Infiniband device - * @v port_info Port information datagram to fill in + * @v qp Queue pair + * @v av Address vector + * @v iobuf I/O buffer * @ret rc Return status code */ -static int ib_get_port_info ( struct ib_device *ibdev, - struct ib_mad_port_info *port_info ) { - struct ib_mad_hdr *hdr = &port_info->mad_hdr; +int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp, + struct ib_address_vector *av, + struct io_buffer *iobuf ) { int rc; - /* Construct MAD */ - memset ( port_info, 0, sizeof ( *port_info ) ); - hdr->base_version = IB_MGMT_BASE_VERSION; - hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; - hdr->class_version = 1; - hdr->method = IB_MGMT_METHOD_GET; - hdr->attr_id = htons ( IB_SMP_ATTR_PORT_INFO ); - hdr->attr_mod = htonl ( ibdev->port ); - - if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *port_info ) ) ) != 0 ) { - DBGC ( ibdev, "IBDEV %p could not get port info: %s\n", - ibdev, strerror ( rc ) ); + /* Check queue fill level */ + if ( qp->send.fill >= qp->send.num_wqes ) { + DBGC ( ibdev, "IBDEV %p QPN %#lx send queue full\n", + ibdev, qp->qpn ); + return -ENOBUFS; + } + + /* Post to hardware */ + if ( ( rc = ibdev->op->post_send ( ibdev, qp, av, iobuf ) ) != 0 ) { + DBGC ( ibdev, "IBDEV %p QPN %#lx could not post send WQE: " + "%s\n", ibdev, qp->qpn, strerror ( rc ) ); return rc; } + + qp->send.fill++; return 0; } /** - * Get GUID information + * Post receive work queue entry * * @v ibdev Infiniband device - * @v guid_info GUID information datagram to fill in + * @v qp Queue pair + * @v iobuf I/O buffer * @ret rc Return status code */ -static int ib_get_guid_info ( struct ib_device *ibdev, - struct ib_mad_guid_info *guid_info ) { - struct ib_mad_hdr *hdr = &guid_info->mad_hdr; +int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp, + struct io_buffer *iobuf ) { int rc; - /* Construct MAD */ - memset ( guid_info, 0, sizeof ( *guid_info ) ); - hdr->base_version = IB_MGMT_BASE_VERSION; - hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; - hdr->class_version = 1; - hdr->method = IB_MGMT_METHOD_GET; - hdr->attr_id = htons ( IB_SMP_ATTR_GUID_INFO ); + /* Check queue fill level */ + if ( qp->recv.fill >= qp->recv.num_wqes ) { + DBGC ( ibdev, "IBDEV %p QPN %#lx receive queue full\n", + ibdev, qp->qpn ); + return -ENOBUFS; + } - if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *guid_info ) ) ) != 0 ) { - DBGC ( ibdev, "IBDEV %p could not get GUID info: %s\n", - ibdev, strerror ( rc ) ); + /* Post to hardware */ + if ( ( rc = ibdev->op->post_recv ( ibdev, qp, iobuf ) ) != 0 ) { + DBGC ( ibdev, "IBDEV %p QPN %#lx could not post receive WQE: " + "%s\n", ibdev, qp->qpn, strerror ( rc ) ); return rc; } + + qp->recv.fill++; return 0; } /** - * Get partition key table + * Complete send work queue entry * * @v ibdev Infiniband device - * @v guid_info Partition key table datagram to fill in - * @ret rc Return status code + * @v qp Queue pair + * @v iobuf I/O buffer + * @v rc Completion status code */ -static int ib_get_pkey_table ( struct ib_device *ibdev, - struct ib_mad_pkey_table *pkey_table ) { - struct ib_mad_hdr *hdr = &pkey_table->mad_hdr; - int rc; - - /* Construct MAD */ - memset ( pkey_table, 0, sizeof ( *pkey_table ) ); - hdr->base_version = IB_MGMT_BASE_VERSION; - hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; - hdr->class_version = 1; - hdr->method = IB_MGMT_METHOD_GET; - hdr->attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE ); +void ib_complete_send ( struct ib_device *ibdev, struct ib_queue_pair *qp, + struct io_buffer *iobuf, int rc ) { + qp->send.cq->op->complete_send ( ibdev, qp, iobuf, rc ); + qp->send.fill--; +} - if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *pkey_table ) ) ) != 0 ) { - DBGC ( ibdev, "IBDEV %p could not get pkey table: %s\n", - ibdev, strerror ( rc ) ); - return rc; - } - return 0; +/** + * Complete receive work queue entry + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v av Address vector + * @v iobuf I/O buffer + * @v rc Completion status code + */ +void ib_complete_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp, + struct ib_address_vector *av, + struct io_buffer *iobuf, int rc ) { + qp->recv.cq->op->complete_recv ( ibdev, qp, av, iobuf, rc ); + qp->recv.fill--; } /** - * Get MAD parameters + * Attach to multicast group * * @v ibdev Infiniband device + * @v qp Queue pair + * @v gid Multicast GID * @ret rc Return status code */ -static int ib_get_mad_params ( struct ib_device *ibdev ) { - union { - /* This union exists just to save stack space */ - struct ib_mad_port_info port_info; - struct ib_mad_guid_info guid_info; - struct ib_mad_pkey_table pkey_table; - } u; +int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp, + struct ib_gid *gid ) { + struct ib_multicast_gid *mgid; int rc; - /* Port info gives us the link state, the first half of the - * port GID and the SM LID. - */ - if ( ( rc = ib_get_port_info ( ibdev, &u.port_info ) ) != 0 ) - return rc; - ibdev->link_up = ( ( u.port_info.port_state__link_speed_supported - & 0xf ) == 4 ); - memcpy ( &ibdev->port_gid.u.bytes[0], u.port_info.gid_prefix, 8 ); - ibdev->sm_lid = ntohs ( u.port_info.mastersm_lid ); + /* Add to software multicast GID list */ + mgid = zalloc ( sizeof ( *mgid ) ); + if ( ! mgid ) { + rc = -ENOMEM; + goto err_alloc_mgid; + } + memcpy ( &mgid->gid, gid, sizeof ( mgid->gid ) ); + list_add ( &mgid->list, &qp->mgids ); - /* GUID info gives us the second half of the port GID */ - if ( ( rc = ib_get_guid_info ( ibdev, &u.guid_info ) ) != 0 ) - return rc; - memcpy ( &ibdev->port_gid.u.bytes[8], u.guid_info.gid_local, 8 ); + /* Add to hardware multicast GID list */ + if ( ( rc = ibdev->op->mcast_attach ( ibdev, qp, gid ) ) != 0 ) + goto err_dev_mcast_attach; - /* Get partition key */ - if ( ( rc = ib_get_pkey_table ( ibdev, &u.pkey_table ) ) != 0 ) - return rc; - ibdev->pkey = ntohs ( u.pkey_table.pkey[0][0] ); + return 0; - DBGC ( ibdev, "IBDEV %p port GID is %08lx:%08lx:%08lx:%08lx\n", - ibdev, htonl ( ibdev->port_gid.u.dwords[0] ), - htonl ( ibdev->port_gid.u.dwords[1] ), - htonl ( ibdev->port_gid.u.dwords[2] ), - htonl ( ibdev->port_gid.u.dwords[3] ) ); + err_dev_mcast_attach: + list_del ( &mgid->list ); + free ( mgid ); + err_alloc_mgid: + return rc; +} - return 0; +/** + * Detach from multicast group + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v gid Multicast GID + */ +void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp, + struct ib_gid *gid ) { + struct ib_multicast_gid *mgid; + + /* Remove from hardware multicast GID list */ + ibdev->op->mcast_detach ( ibdev, qp, gid ); + + /* Remove from software multicast GID list */ + list_for_each_entry ( mgid, &qp->mgids, list ) { + if ( memcmp ( &mgid->gid, gid, sizeof ( mgid->gid ) ) == 0 ) { + list_del ( &mgid->list ); + free ( mgid ); + break; + } + } } + /*************************************************************************** * * Event queues @@ -366,14 +464,6 @@ static int ib_get_mad_params ( struct ib_device *ibdev ) { * @v ibdev Infiniband device */ void ib_link_state_changed ( struct ib_device *ibdev ) { - int rc; - - /* Update MAD parameters */ - if ( ( rc = ib_get_mad_params ( ibdev ) ) != 0 ) { - DBGC ( ibdev, "IBDEV %p could not update MAD parameters: %s\n", - ibdev, strerror ( rc ) ); - return; - } /* Notify IPoIB of link state change */ ipoib_link_state_changed ( ibdev ); @@ -420,6 +510,9 @@ struct ib_device * alloc_ibdev ( size_t priv_size ) { if ( ibdev ) { drv_priv = ( ( ( void * ) ibdev ) + sizeof ( *ibdev ) ); ib_set_drvdata ( ibdev, drv_priv ); + INIT_LIST_HEAD ( &ibdev->qps ); + ibdev->lid = IB_LID_NONE; + ibdev->pkey = IB_PKEY_NONE; } return ibdev; } @@ -441,10 +534,6 @@ int register_ibdev ( struct ib_device *ibdev ) { if ( ( rc = ib_open ( ibdev ) ) != 0 ) goto err_open; - /* Get MAD parameters */ - if ( ( rc = ib_get_mad_params ( ibdev ) ) != 0 ) - goto err_get_mad_params; - /* Add IPoIB device */ if ( ( rc = ipoib_probe ( ibdev ) ) != 0 ) { DBGC ( ibdev, "IBDEV %p could not add IPoIB device: %s\n", @@ -457,7 +546,6 @@ int register_ibdev ( struct ib_device *ibdev ) { return 0; err_ipoib_probe: - err_get_mad_params: ib_close ( ibdev ); err_open: list_del ( &ibdev->list ); diff --git a/gpxe/src/net/ipv4.c b/gpxe/src/net/ipv4.c index 82a13c33..63dcca28 100644 --- a/gpxe/src/net/ipv4.c +++ b/gpxe/src/net/ipv4.c @@ -188,7 +188,7 @@ static struct io_buffer * ipv4_reassemble ( struct io_buffer * iobuf ) { free_iob ( iobuf ); /** Check if the fragment series is over */ - if ( !iphdr->frags & IP_MASK_MOREFRAGS ) { + if ( ! ( iphdr->frags & IP_MASK_MOREFRAGS ) ) { iobuf = fragbuf->frag_iob; free_fragbuf ( fragbuf ); return iobuf; @@ -266,7 +266,6 @@ static uint16_t ipv4_pshdr_chksum ( struct io_buffer *iobuf, uint16_t csum ) { static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src, struct net_device *netdev, uint8_t *ll_dest ) { struct ll_protocol *ll_protocol = netdev->ll_protocol; - uint8_t *dest_bytes = ( ( uint8_t * ) &dest ); if ( dest.s_addr == INADDR_BROADCAST ) { /* Broadcast address */ @@ -274,17 +273,7 @@ static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src, ll_protocol->ll_addr_len ); return 0; } else if ( IN_MULTICAST ( ntohl ( dest.s_addr ) ) ) { - /* Special case: IPv4 multicast over Ethernet. This - * code may need to be generalised once we find out - * what happens for other link layers. - */ - ll_dest[0] = 0x01; - ll_dest[1] = 0x00; - ll_dest[2] = 0x5e; - ll_dest[3] = dest_bytes[1] & 0x7f; - ll_dest[4] = dest_bytes[2]; - ll_dest[5] = dest_bytes[3]; - return 0; + return ll_protocol->mc_hash ( AF_INET, &dest, ll_dest ); } else { /* Unicast address: resolve via ARP */ return arp_resolve ( netdev, &ipv4_protocol, &dest, diff --git a/gpxe/src/net/netdevice.c b/gpxe/src/net/netdevice.c index 3721b334..e8587a9d 100644 --- a/gpxe/src/net/netdevice.c +++ b/gpxe/src/net/netdevice.c @@ -45,6 +45,45 @@ static struct net_protocol net_protocols_end[0] /** List of network devices */ struct list_head net_devices = LIST_HEAD_INIT ( net_devices ); +/** + * Record network device statistic + * + * @v stats Network device statistics + * @v rc Status code + */ +static void netdev_record_stat ( struct net_device_stats *stats, int rc ) { + struct net_device_error *error; + struct net_device_error *least_common_error; + unsigned int i; + + /* If this is not an error, just update the good counter */ + if ( rc == 0 ) { + stats->good++; + return; + } + + /* Update the bad counter */ + stats->bad++; + + /* Locate the appropriate error record */ + least_common_error = &stats->errors[0]; + for ( i = 0 ; i < ( sizeof ( stats->errors ) / + sizeof ( stats->errors[0] ) ) ; i++ ) { + error = &stats->errors[i]; + /* Update matching record, if found */ + if ( error->rc == rc ) { + error->count++; + return; + } + if ( error->count < least_common_error->count ) + least_common_error = error; + } + + /* Overwrite the least common error record */ + least_common_error->rc = rc; + least_common_error->count = 1; +} + /** * Transmit raw packet via network device * @@ -91,12 +130,11 @@ void netdev_tx_complete_err ( struct net_device *netdev, struct io_buffer *iobuf, int rc ) { /* Update statistics counter */ + netdev_record_stat ( &netdev->tx_stats, rc ); if ( rc == 0 ) { - netdev->stats.tx_ok++; DBGC ( netdev, "NETDEV %p transmission %p complete\n", netdev, iobuf ); } else { - netdev->stats.tx_err++; DBGC ( netdev, "NETDEV %p transmission %p failed: %s\n", netdev, iobuf, strerror ( rc ) ); } @@ -158,7 +196,7 @@ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) { list_add_tail ( &iobuf->list, &netdev->rx_queue ); /* Update statistics counter */ - netdev->stats.rx_ok++; + netdev_record_stat ( &netdev->rx_stats, 0 ); } /** @@ -183,7 +221,7 @@ void netdev_rx_err ( struct net_device *netdev, free_iob ( iobuf ); /* Update statistics counter */ - netdev->stats.rx_err++; + netdev_record_stat ( &netdev->rx_stats, rc ); } /** @@ -268,7 +306,7 @@ struct net_device * alloc_netdev ( size_t priv_size ) { INIT_LIST_HEAD ( &netdev->rx_queue ); settings_init ( netdev_settings ( netdev ), &netdev_settings_operations, &netdev->refcnt, - netdev->name ); + netdev->name, 0 ); netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) ); } return netdev; @@ -439,6 +477,7 @@ struct net_device * find_netdev_by_location ( unsigned int bus_type, */ int net_tx ( struct io_buffer *iobuf, struct net_device *netdev, struct net_protocol *net_protocol, const void *ll_dest ) { + struct ll_protocol *ll_protocol = netdev->ll_protocol; int rc; /* Force a poll on the netdevice to (potentially) clear any @@ -449,8 +488,8 @@ int net_tx ( struct io_buffer *iobuf, struct net_device *netdev, netdev_poll ( netdev ); /* Add link-layer header */ - if ( ( rc = netdev->ll_protocol->push ( iobuf, netdev, net_protocol, - ll_dest ) ) != 0 ) { + if ( ( rc = ll_protocol->push ( iobuf, ll_dest, netdev->ll_addr, + net_protocol->net_proto ) ) != 0 ) { free_iob ( iobuf ); return rc; } @@ -495,8 +534,9 @@ static void net_step ( struct process *process __unused ) { struct net_device *netdev; struct io_buffer *iobuf; struct ll_protocol *ll_protocol; - uint16_t net_proto; + const void *ll_dest; const void *ll_source; + uint16_t net_proto; int rc; /* Poll and process each network device */ @@ -519,9 +559,9 @@ static void net_step ( struct process *process __unused ) { /* Remove link-layer header */ ll_protocol = netdev->ll_protocol; - if ( ( rc = ll_protocol->pull ( iobuf, netdev, - &net_proto, - &ll_source ) ) != 0 ) { + if ( ( rc = ll_protocol->pull ( iobuf, &ll_dest, + &ll_source, + &net_proto ) ) != 0 ) { free_iob ( iobuf ); continue; } diff --git a/gpxe/src/net/retry.c b/gpxe/src/net/retry.c index 2a645c97..cd793a7f 100644 --- a/gpxe/src/net/retry.c +++ b/gpxe/src/net/retry.c @@ -55,9 +55,10 @@ static LIST_HEAD ( timers ); * be stopped and the timer's callback function will be called. */ void start_timer ( struct retry_timer *timer ) { - if ( ! timer_running ( timer ) ) + if ( ! timer->running ) list_add ( &timer->list, &timers ); timer->start = currticks(); + timer->running = 1; /* 0 means "use default timeout" */ if ( timer->min_timeout == 0 ) @@ -82,6 +83,8 @@ void start_timer ( struct retry_timer *timer ) { void start_timer_fixed ( struct retry_timer *timer, unsigned long timeout ) { start_timer ( timer ); timer->timeout = timeout; + DBG2 ( "Timer %p expiry time changed to %ld\n", + timer, ( timer->start + timer->timeout ) ); } /** @@ -97,12 +100,12 @@ void stop_timer ( struct retry_timer *timer ) { unsigned long runtime; /* If timer was already stopped, do nothing */ - if ( ! timer_running ( timer ) ) + if ( ! timer->running ) return; list_del ( &timer->list ); runtime = ( now - timer->start ); - timer->start = 0; + timer->running = 0; DBG2 ( "Timer %p stopped at time %ld (ran for %ld)\n", timer, now, runtime ); @@ -144,8 +147,9 @@ static void timer_expired ( struct retry_timer *timer ) { /* Stop timer without performing RTT calculations */ DBG2 ( "Timer %p stopped at time %ld on expiry\n", timer, currticks() ); + assert ( timer->running ); list_del ( &timer->list ); - timer->start = 0; + timer->running = 0; timer->count++; /* Back off the timeout value */ diff --git a/gpxe/src/net/tcp/ftp.c b/gpxe/src/net/tcp/ftp.c index 3b88f7b6..82dc19ca 100644 --- a/gpxe/src/net/tcp/ftp.c +++ b/gpxe/src/net/tcp/ftp.c @@ -109,23 +109,39 @@ static void ftp_done ( struct ftp_request *ftp, int rc ) { * */ +/** An FTP control channel string */ +struct ftp_control_string { + /** Literal portion */ + const char *literal; + /** Variable portion + * + * @v ftp FTP request + * @ret string Variable portion of string + */ + const char * ( *variable ) ( struct ftp_request *ftp ); +}; + /** - * FTP control channel strings + * Retrieve FTP pathname * - * These are used as printf() format strings. Since only one of them - * (RETR) takes an argument, we always supply that argument to the - * snprintf() call. + * @v ftp FTP request + * @ret path FTP pathname */ -static const char * ftp_strings[] = { - [FTP_CONNECT] = NULL, - [FTP_USER] = "USER anonymous\r\n", - [FTP_PASS] = "PASS etherboot@etherboot.org\r\n", - [FTP_TYPE] = "TYPE I\r\n", - [FTP_PASV] = "PASV\r\n", - [FTP_RETR] = "RETR %s\r\n", - [FTP_WAIT] = NULL, - [FTP_QUIT] = "QUIT\r\n", - [FTP_DONE] = NULL, +static const char * ftp_uri_path ( struct ftp_request *ftp ) { + return ftp->uri->path; +} + +/** FTP control channel strings */ +static struct ftp_control_string ftp_strings[] = { + [FTP_CONNECT] = { NULL, NULL }, + [FTP_USER] = { "USER anonymous", NULL }, + [FTP_PASS] = { "PASS etherboot@etherboot.org", NULL }, + [FTP_TYPE] = { "TYPE I", NULL }, + [FTP_PASV] = { "PASV", NULL }, + [FTP_RETR] = { "RETR ", ftp_uri_path }, + [FTP_WAIT] = { NULL, NULL }, + [FTP_QUIT] = { "QUIT", NULL }, + [FTP_DONE] = { NULL, NULL }, }; /** @@ -178,18 +194,23 @@ static void ftp_parse_value ( char **text, uint8_t *value, size_t len ) { * */ static void ftp_next_state ( struct ftp_request *ftp ) { + struct ftp_control_string *ftp_string; + const char *literal; + const char *variable; /* Move to next state */ if ( ftp->state < FTP_DONE ) ftp->state++; /* Send control string if needed */ - if ( ftp_strings[ftp->state] != NULL ) { - DBGC ( ftp, "FTP %p sending ", ftp ); - DBGC ( ftp, ftp_strings[ftp->state], ftp->uri->path ); - xfer_printf ( &ftp->control, ftp_strings[ftp->state], - ftp->uri->path ); - } + ftp_string = &ftp_strings[ftp->state]; + literal = ftp_string->literal; + variable = ( ftp_string->variable ? + ftp_string->variable ( ftp ) : "" ); + if ( literal ) { + DBGC ( ftp, "FTP %p sending %s%s\n", ftp, literal, variable ); + xfer_printf ( &ftp->control, "%s%s\r\n", literal, variable ); + } } /** diff --git a/gpxe/src/net/tls.c b/gpxe/src/net/tls.c index 834686fb..fa4b58d4 100644 --- a/gpxe/src/net/tls.c +++ b/gpxe/src/net/tls.c @@ -270,16 +270,16 @@ static void tls_generate_master_secret ( struct tls_session *tls ) { DBGC_HD ( tls, &tls->pre_master_secret, sizeof ( tls->pre_master_secret ) ); DBGC ( tls, "TLS %p client random bytes:\n", tls ); - DBGC_HD ( tls, &tls->client_random, sizeof ( tls->server_random ) ); + DBGC_HD ( tls, &tls->client_random, sizeof ( tls->client_random ) ); DBGC ( tls, "TLS %p server random bytes:\n", tls ); DBGC_HD ( tls, &tls->server_random, sizeof ( tls->server_random ) ); - tls_prf_label ( tls, tls->pre_master_secret, + tls_prf_label ( tls, &tls->pre_master_secret, sizeof ( tls->pre_master_secret ), - tls->master_secret, sizeof ( tls->master_secret ), + &tls->master_secret, sizeof ( tls->master_secret ), "master secret", - tls->client_random, sizeof ( tls->client_random ), - tls->server_random, sizeof ( tls->server_random ) ); + &tls->client_random, sizeof ( tls->client_random ), + &tls->server_random, sizeof ( tls->server_random ) ); DBGC ( tls, "TLS %p generated master secret:\n", tls ); DBGC_HD ( tls, &tls->master_secret, sizeof ( tls->master_secret ) ); @@ -304,10 +304,10 @@ static int tls_generate_keys ( struct tls_session *tls ) { int rc; /* Generate key block */ - tls_prf_label ( tls, tls->master_secret, sizeof ( tls->master_secret ), + tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ), key_block, sizeof ( key_block ), "key expansion", - tls->server_random, sizeof ( tls->server_random ), - tls->client_random, sizeof ( tls->client_random ) ); + &tls->server_random, sizeof ( tls->server_random ), + &tls->client_random, sizeof ( tls->client_random ) ); /* Split key block into portions */ key = key_block; @@ -604,7 +604,7 @@ static int tls_send_client_hello ( struct tls_session *tls ) { htonl ( sizeof ( hello ) - sizeof ( hello.type_length ) ) ); hello.version = htons ( TLS_VERSION_TLS_1_0 ); - memcpy ( &hello.random, tls->client_random, sizeof ( hello.random ) ); + memcpy ( &hello.random, &tls->client_random, sizeof ( hello.random ) ); hello.cipher_suite_len = htons ( sizeof ( hello.cipher_suites ) ); hello.cipher_suites[0] = htons ( TLS_RSA_WITH_AES_128_CBC_SHA ); hello.cipher_suites[1] = htons ( TLS_RSA_WITH_AES_256_CBC_SHA ); @@ -643,7 +643,7 @@ static int tls_send_client_key_exchange ( struct tls_session *tls ) { sizeof ( tls->pre_master_secret ) ); DBGC_HD ( tls, tls->rsa_mod, tls->rsa_mod_len ); DBGC_HD ( tls, tls->rsa_pub_exp, tls->rsa_pub_exp_len ); - RSA_encrypt ( rsa_ctx, tls->pre_master_secret, + RSA_encrypt ( rsa_ctx, ( const uint8_t * ) &tls->pre_master_secret, sizeof ( tls->pre_master_secret ), key_xchg.encrypted_pre_master_secret, 0 ); DBGC ( tls, "RSA encrypt done. Ciphertext:\n" ); @@ -685,7 +685,7 @@ static int tls_send_finished ( struct tls_session *tls ) { htonl ( sizeof ( finished ) - sizeof ( finished.type_length ) ) ); tls_verify_handshake ( tls, digest ); - tls_prf_label ( tls, tls->master_secret, sizeof ( tls->master_secret ), + tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ), finished.verify_data, sizeof ( finished.verify_data ), "client finished", digest, sizeof ( digest ) ); @@ -802,7 +802,7 @@ static int tls_new_server_hello ( struct tls_session *tls, } /* Copy out server random bytes */ - memcpy ( tls->server_random, hello_a->random, + memcpy ( &tls->server_random, &hello_a->random, sizeof ( tls->server_random ) ); /* Select cipher suite */ @@ -1710,13 +1710,12 @@ int add_tls ( struct xfer_interface *xfer, struct xfer_interface **next ) { tls_clear_cipher ( tls, &tls->tx_cipherspec_pending ); tls_clear_cipher ( tls, &tls->rx_cipherspec ); tls_clear_cipher ( tls, &tls->rx_cipherspec_pending ); - *( ( uint32_t * ) tls->client_random ) = 0; /* GMT Unix time */ - tls_generate_random ( ( tls->client_random + 4 ), - ( sizeof ( tls->client_random ) - 4 ) ); - *( ( uint16_t * ) tls->pre_master_secret ) - = htons ( TLS_VERSION_TLS_1_0 ); - tls_generate_random ( ( tls->pre_master_secret + 2 ), - ( sizeof ( tls->pre_master_secret ) - 2 ) ); + tls->client_random.gmt_unix_time = 0; + tls_generate_random ( &tls->client_random.random, + ( sizeof ( tls->client_random.random ) ) ); + tls->pre_master_secret.version = htons ( TLS_VERSION_TLS_1_0 ); + tls_generate_random ( &tls->pre_master_secret.random, + ( sizeof ( tls->pre_master_secret.random ) ) ); digest_init ( &md5_algorithm, tls->handshake_md5_ctx ); digest_init ( &sha1_algorithm, tls->handshake_sha1_ctx ); tls->tx_state = TLS_TX_CLIENT_HELLO; diff --git a/gpxe/src/net/udp/dhcp.c b/gpxe/src/net/udp/dhcp.c index ab751cd5..21347832 100644 --- a/gpxe/src/net/udp/dhcp.c +++ b/gpxe/src/net/udp/dhcp.c @@ -256,7 +256,7 @@ static struct dhcp_settings * dhcpset_create ( const struct dhcphdr *dhcphdr, dhcppkt_init ( &dhcpset->dhcppkt, data, len ); settings_init ( &dhcpset->settings, &dhcpset_settings_operations, &dhcpset->refcnt, - DHCP_SETTINGS_NAME ); + DHCP_SETTINGS_NAME, 0 ); } return dhcpset; } diff --git a/gpxe/src/net/udp/tftp.c b/gpxe/src/net/udp/tftp.c index 8fdb3714..b262b108 100644 --- a/gpxe/src/net/udp/tftp.c +++ b/gpxe/src/net/udp/tftp.c @@ -45,6 +45,15 @@ FEATURE ( FEATURE_PROTOCOL, "TFTP", DHCP_EB_FEATURE_TFTP, 1 ); +/* TFTP-specific error codes */ +#define ETFTP_INVALID_BLKSIZE EUNIQ_01 +#define ETFTP_INVALID_TSIZE EUNIQ_02 +#define ETFTP_MC_NO_PORT EUNIQ_03 +#define ETFTP_MC_NO_MC EUNIQ_04 +#define ETFTP_MC_INVALID_MC EUNIQ_05 +#define ETFTP_MC_INVALID_IP EUNIQ_06 +#define ETFTP_MC_INVALID_PORT EUNIQ_07 + /** * A TFTP request * @@ -504,7 +513,7 @@ static int tftp_process_blksize ( struct tftp_request *tftp, if ( *end ) { DBGC ( tftp, "TFTP %p got invalid blksize \"%s\"\n", tftp, value ); - return -EINVAL; + return -( EINVAL | ETFTP_INVALID_BLKSIZE ); } DBGC ( tftp, "TFTP %p blksize=%d\n", tftp, tftp->blksize ); @@ -526,7 +535,7 @@ static int tftp_process_tsize ( struct tftp_request *tftp, if ( *end ) { DBGC ( tftp, "TFTP %p got invalid tsize \"%s\"\n", tftp, value ); - return -EINVAL; + return -( EINVAL | ETFTP_INVALID_TSIZE ); } DBGC ( tftp, "TFTP %p tsize=%ld\n", tftp, tftp->tsize ); @@ -560,13 +569,13 @@ static int tftp_process_multicast ( struct tftp_request *tftp, port = strchr ( addr, ',' ); if ( ! port ) { DBGC ( tftp, "TFTP %p multicast missing port,mc\n", tftp ); - return -EINVAL; + return -( EINVAL | ETFTP_MC_NO_PORT ); } *(port++) = '\0'; mc = strchr ( port, ',' ); if ( ! mc ) { DBGC ( tftp, "TFTP %p multicast missing mc\n", tftp ); - return -EINVAL; + return -( EINVAL | ETFTP_MC_NO_MC ); } *(mc++) = '\0'; @@ -575,7 +584,7 @@ static int tftp_process_multicast ( struct tftp_request *tftp, tftp->flags &= ~TFTP_FL_SEND_ACK; if ( *mc_end ) { DBGC ( tftp, "TFTP %p multicast invalid mc %s\n", tftp, mc ); - return -EINVAL; + return -( EINVAL | ETFTP_MC_INVALID_MC ); } DBGC ( tftp, "TFTP %p is%s the master client\n", tftp, ( ( tftp->flags & TFTP_FL_SEND_ACK ) ? "" : " not" ) ); @@ -584,7 +593,7 @@ static int tftp_process_multicast ( struct tftp_request *tftp, if ( inet_aton ( addr, &socket.sin.sin_addr ) == 0 ) { DBGC ( tftp, "TFTP %p multicast invalid IP address " "%s\n", tftp, addr ); - return -EINVAL; + return -( EINVAL | ETFTP_MC_INVALID_IP ); } DBGC ( tftp, "TFTP %p multicast IP address %s\n", tftp, inet_ntoa ( socket.sin.sin_addr ) ); @@ -592,7 +601,7 @@ static int tftp_process_multicast ( struct tftp_request *tftp, if ( *port_end ) { DBGC ( tftp, "TFTP %p multicast invalid port %s\n", tftp, port ); - return -EINVAL; + return -( EINVAL | ETFTP_MC_INVALID_PORT ); } DBGC ( tftp, "TFTP %p multicast port %d\n", tftp, ntohs ( socket.sin.sin_port ) ); diff --git a/gpxe/src/tests/gdbstub_test.gdb b/gpxe/src/tests/gdbstub_test.gdb old mode 100644 new mode 100755 diff --git a/gpxe/src/usr/aoeboot.c b/gpxe/src/usr/aoeboot.c index f0e481bd..e977b10f 100644 --- a/gpxe/src/usr/aoeboot.c +++ b/gpxe/src/usr/aoeboot.c @@ -6,9 +6,9 @@ #include #include #include +#include #include #include -#include /** * Guess boot network device @@ -16,17 +16,18 @@ * @ret netdev Boot network device */ static struct net_device * guess_boot_netdev ( void ) { - struct net_device *boot_netdev; + struct net_device *netdev; /* Just use the first network device */ - for_each_netdev ( boot_netdev ) { - return boot_netdev; + for_each_netdev ( netdev ) { + if ( netdev->state & NETDEV_OPEN ) + return netdev; } return NULL; } -int aoeboot ( const char *root_path ) { +static int aoeboot ( const char *root_path ) { struct ata_device ata; struct int13_drive drive; int rc; @@ -71,3 +72,8 @@ int aoeboot ( const char *root_path ) { error_attach: return rc; } + +struct sanboot_protocol aoe_sanboot_protocol __sanboot_protocol = { + .prefix = "aoe:", + .boot = aoeboot, +}; diff --git a/gpxe/src/usr/autoboot.c b/gpxe/src/usr/autoboot.c index 326292b4..f5f7f7d1 100644 --- a/gpxe/src/usr/autoboot.c +++ b/gpxe/src/usr/autoboot.c @@ -24,13 +24,12 @@ #include #include #include +#include #include #include #include #include #include -#include -#include #include /** @file @@ -45,6 +44,12 @@ /** Shutdown flags for exit */ int shutdown_exit_flags = 0; +/* SAN boot protocols */ +static struct sanboot_protocol sanboot_protocols[0] \ + __table_start ( struct sanboot_protocol, sanboot_protocols ); +static struct sanboot_protocol sanboot_protocols_end[0] \ + __table_end ( struct sanboot_protocol, sanboot_protocols ); + /** * Identify the boot network device * @@ -141,12 +146,15 @@ static int boot_next_server_and_filename ( struct in_addr next_server, * @ret rc Return status code */ int boot_root_path ( const char *root_path ) { + struct sanboot_protocol *sanboot; /* Quick hack */ - if ( strncmp ( root_path, "iscsi:", 6 ) == 0 ) { - return iscsiboot ( root_path ); - } else if ( strncmp ( root_path, "aoe:", 4 ) == 0 ) { - return aoeboot ( root_path ); + for ( sanboot = sanboot_protocols ; + sanboot < sanboot_protocols_end ; sanboot++ ) { + if ( strncmp ( root_path, sanboot->prefix, + strlen ( sanboot->prefix ) ) == 0 ) { + return sanboot->boot ( root_path ); + } } return -ENOTSUP; diff --git a/gpxe/src/usr/ifmgmt.c b/gpxe/src/usr/ifmgmt.c index 9c88ab53..72d86137 100644 --- a/gpxe/src/usr/ifmgmt.c +++ b/gpxe/src/usr/ifmgmt.c @@ -58,6 +58,25 @@ void ifclose ( struct net_device *netdev ) { netdev_close ( netdev ); } +/** + * Print network device error breakdown + * + * @v stats Network device statistics + * @v prefix Message prefix + */ +static void ifstat_errors ( struct net_device_stats *stats, + const char *prefix ) { + unsigned int i; + + for ( i = 0 ; i < ( sizeof ( stats->errors ) / + sizeof ( stats->errors[0] ) ) ; i++ ) { + if ( stats->errors[i].count ) + printf ( " [%s: %d x \"%s\"]\n", prefix, + stats->errors[i].count, + strerror ( stats->errors[i].rc ) ); + } +} + /** * Print status of network device * @@ -69,8 +88,10 @@ void ifstat ( struct net_device *netdev ) { netdev->name, netdev_hwaddr ( netdev ), netdev->dev->name, ( ( netdev->state & NETDEV_OPEN ) ? "open" : "closed" ), ( netdev_link_ok ( netdev ) ? "up" : "down" ), - netdev->stats.tx_ok, netdev->stats.tx_err, - netdev->stats.rx_ok, netdev->stats.rx_err ); + netdev->tx_stats.good, netdev->tx_stats.bad, + netdev->rx_stats.good, netdev->rx_stats.bad ); + ifstat_errors ( &netdev->tx_stats, "TXE" ); + ifstat_errors ( &netdev->rx_stats, "RXE" ); } /** diff --git a/gpxe/src/usr/iscsiboot.c b/gpxe/src/usr/iscsiboot.c index 84d77c45..cdf7790b 100644 --- a/gpxe/src/usr/iscsiboot.c +++ b/gpxe/src/usr/iscsiboot.c @@ -9,9 +9,9 @@ #include #include #include +#include #include #include -#include struct setting keep_san_setting __setting = { .name = "keep-san", @@ -26,17 +26,18 @@ struct setting keep_san_setting __setting = { * @ret netdev Boot network device */ static struct net_device * guess_boot_netdev ( void ) { - struct net_device *boot_netdev; + struct net_device *netdev; /* Just use the first network device */ - for_each_netdev ( boot_netdev ) { - return boot_netdev; + for_each_netdev ( netdev ) { + if ( netdev->state & NETDEV_OPEN ) + return netdev; } return NULL; } -int iscsiboot ( const char *root_path ) { +static int iscsiboot ( const char *root_path ) { struct scsi_device *scsi; struct int13_drive *drive; int keep_san; @@ -100,3 +101,8 @@ int iscsiboot ( const char *root_path ) { err_alloc_scsi: return rc; } + +struct sanboot_protocol iscsi_sanboot_protocol __sanboot_protocol = { + .prefix = "iscsi:", + .boot = iscsiboot, +}; diff --git a/gpxe/src/util/.gitignore b/gpxe/src/util/.gitignore index 98adc2df..7f9d7557 100644 --- a/gpxe/src/util/.gitignore +++ b/gpxe/src/util/.gitignore @@ -2,3 +2,4 @@ nrv2b zbin hijack prototester +efilink diff --git a/gpxe/src/util/efilink.c b/gpxe/src/util/efilink.c new file mode 100644 index 00000000..e21f4a90 --- /dev/null +++ b/gpxe/src/util/efilink.c @@ -0,0 +1,507 @@ +#include +#include +#include +#include +#include +#include +#include + +struct bfd_file { + bfd *bfd; + asymbol **symtab; + long symcount; +}; + +struct pe_relocs { + struct pe_relocs *next; + unsigned long start_rva; + unsigned int used_relocs; + unsigned int total_relocs; + uint16_t *relocs; +}; + +/** + * Allocate memory + * + * @v len Length of memory to allocate + * @ret ptr Pointer to allocated memory + */ +static void * xmalloc ( size_t len ) { + void *ptr; + + ptr = malloc ( len ); + if ( ! ptr ) { + fprintf ( stderr, "Could not allocate %zd bytes\n", len ); + exit ( 1 ); + } + + return ptr; +} + +/** + * Generate entry in PE relocation table + * + * @v pe_reltab PE relocation table + * @v rva RVA + * @v size Size of relocation entry + */ +static void generate_pe_reloc ( struct pe_relocs **pe_reltab, + unsigned long rva, size_t size ) { + unsigned long start_rva; + uint16_t reloc; + struct pe_relocs *pe_rel; + uint16_t *relocs; + + /* Construct */ + start_rva = ( rva & ~0xfff ); + reloc = ( rva & 0xfff ); + switch ( size ) { + case 4: + reloc |= 0x3000; + break; + case 2: + reloc |= 0x2000; + break; + default: + fprintf ( stderr, "Unsupported relocation size %zd\n", size ); + exit ( 1 ); + } + + /* Locate or create PE relocation table */ + for ( pe_rel = *pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) { + if ( pe_rel->start_rva == start_rva ) + break; + } + if ( ! pe_rel ) { + pe_rel = xmalloc ( sizeof ( *pe_rel ) ); + memset ( pe_rel, 0, sizeof ( *pe_rel ) ); + pe_rel->next = *pe_reltab; + *pe_reltab = pe_rel; + pe_rel->start_rva = start_rva; + } + + /* Expand relocation list if necessary */ + if ( pe_rel->used_relocs < pe_rel->total_relocs ) { + relocs = pe_rel->relocs; + } else { + pe_rel->total_relocs = ( pe_rel->total_relocs ? + ( pe_rel->total_relocs * 2 ) : 256 ); + relocs = xmalloc ( pe_rel->total_relocs * + sizeof ( pe_rel->relocs[0] ) ); + memset ( relocs, 0, + pe_rel->total_relocs * sizeof ( pe_rel->relocs[0] ) ); + memcpy ( relocs, pe_rel->relocs, + pe_rel->used_relocs * sizeof ( pe_rel->relocs[0] ) ); + free ( pe_rel->relocs ); + pe_rel->relocs = relocs; + } + + /* Store relocation */ + pe_rel->relocs[ pe_rel->used_relocs++ ] = reloc; +} + +/** + * Calculate size of binary PE relocation table + * + * @v pe_reltab PE relocation table + * @v buffer Buffer to contain binary table, or NULL + * @ret size Size of binary table + */ +static size_t output_pe_reltab ( struct pe_relocs *pe_reltab, + void *buffer ) { + struct pe_relocs *pe_rel; + unsigned int num_relocs; + size_t size; + size_t total_size = 0; + + for ( pe_rel = pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) { + num_relocs = ( ( pe_rel->used_relocs + 1 ) & ~1 ); + size = ( sizeof ( uint32_t ) /* VirtualAddress */ + + sizeof ( uint32_t ) /* SizeOfBlock */ + + ( num_relocs * sizeof ( uint16_t ) ) ); + if ( buffer ) { + *( (uint32_t *) ( buffer + total_size + 0 ) ) + = pe_rel->start_rva; + *( (uint32_t *) ( buffer + total_size + 4 ) ) = size; + memcpy ( ( buffer + total_size + 8 ), pe_rel->relocs, + ( num_relocs * sizeof ( uint16_t ) ) ); + } + total_size += size; + } + + return total_size; +} + +/** + * Read symbol table + * + * @v bfd BFD file + */ +static void read_symtab ( struct bfd_file *bfd ) { + long symtab_size; + + /* Get symbol table size */ + symtab_size = bfd_get_symtab_upper_bound ( bfd->bfd ); + if ( symtab_size < 0 ) { + bfd_perror ( "Could not get symbol table upper bound" ); + exit ( 1 ); + } + + /* Allocate and read symbol table */ + bfd->symtab = xmalloc ( symtab_size ); + bfd->symcount = bfd_canonicalize_symtab ( bfd->bfd, bfd->symtab ); + if ( bfd->symcount < 0 ) { + bfd_perror ( "Cannot read symbol table" ); + exit ( 1 ); + } +} + +/** + * Read relocation table + * + * @v bfd BFD file + * @v section Section + * @v symtab Symbol table + * @ret reltab Relocation table + */ +static arelent ** read_reltab ( struct bfd_file *bfd, asection *section ) { + long reltab_size; + arelent **reltab; + long numrels; + + /* Get relocation table size */ + reltab_size = bfd_get_reloc_upper_bound ( bfd->bfd, section ); + if ( reltab_size < 0 ) { + bfd_perror ( "Could not get relocation table upper bound" ); + exit ( 1 ); + } + + /* Allocate and read relocation table */ + reltab = xmalloc ( reltab_size ); + numrels = bfd_canonicalize_reloc ( bfd->bfd, section, reltab, + bfd->symtab ); + if ( numrels < 0 ) { + bfd_perror ( "Cannot read relocation table" ); + exit ( 1 ); + } + + return reltab; +} + + +/** + * Open input BFD file + * + * @v filename File name + * @ret ibfd BFD file + */ +static struct bfd_file * open_input_bfd ( const char *filename ) { + struct bfd_file *ibfd; + + /* Create BFD file */ + ibfd = xmalloc ( sizeof ( *ibfd ) ); + memset ( ibfd, 0, sizeof ( *ibfd ) ); + + /* Open the file */ + ibfd->bfd = bfd_openr ( filename, NULL ); + if ( ! ibfd->bfd ) { + fprintf ( stderr, "Cannot open %s: ", filename ); + bfd_perror ( NULL ); + exit ( 1 ); + } + + /* The call to bfd_check_format() must be present, otherwise + * we get a segfault from later BFD calls. + */ + if ( bfd_check_format ( ibfd->bfd, bfd_object ) < 0 ) { + fprintf ( stderr, "%s is not an object file\n", filename ); + exit ( 1 ); + } + + /* Read symbols and relocation entries */ + read_symtab ( ibfd ); + + return ibfd; +} + +/** + * Open output BFD file + * + * @v filename File name + * @v ibfd Input BFD file + * @ret obfd BFD file + */ +static struct bfd_file * open_output_bfd ( const char *filename, + struct bfd_file *ibfd ) { + struct bfd_file *obfd; + asection *isection; + asection *osection; + + /* + * Most of this code is based on what objcopy.c does. + * + */ + + /* Create BFD file */ + obfd = xmalloc ( sizeof ( *obfd ) ); + memset ( obfd, 0, sizeof ( *obfd ) ); + + /* Open the file */ + obfd->bfd = bfd_openw ( filename, ibfd->bfd->xvec->name ); + if ( ! obfd->bfd ) { + fprintf ( stderr, "Cannot open %s: ", filename ); + bfd_perror ( NULL ); + exit ( 1 ); + } + + /* Copy per-file data */ + if ( ! bfd_set_arch_mach ( obfd->bfd, bfd_get_arch ( ibfd->bfd ), + bfd_get_mach ( ibfd->bfd ) ) ) { + bfd_perror ( "Cannot copy architecture" ); + exit ( 1 ); + } + if ( ! bfd_set_format ( obfd->bfd, bfd_get_format ( ibfd->bfd ) ) ) { + bfd_perror ( "Cannot copy format" ); + exit ( 1 ); + } + if ( ! bfd_copy_private_header_data ( ibfd->bfd, obfd->bfd ) ) { + bfd_perror ( "Cannot copy private header data" ); + exit ( 1 ); + } + + /* Create sections */ + for ( isection = ibfd->bfd->sections ; isection ; + isection = isection->next ) { + osection = bfd_make_section_anyway ( obfd->bfd, + isection->name ); + if ( ! osection ) { + bfd_perror ( "Cannot create section" ); + exit ( 1 ); + } + if ( ! bfd_set_section_flags ( obfd->bfd, osection, + isection->flags ) ) { + bfd_perror ( "Cannot copy section flags" ); + exit ( 1 ); + } + if ( ! bfd_set_section_size ( obfd->bfd, osection, + bfd_section_size ( ibfd->bfd, isection ) ) ) { + bfd_perror ( "Cannot copy section size" ); + exit ( 1 ); + } + if ( ! bfd_set_section_vma ( obfd->bfd, osection, + bfd_section_vma ( ibfd->bfd, isection ) ) ) { + bfd_perror ( "Cannot copy section VMA" ); + exit ( 1 ); + } + osection->lma = bfd_section_lma ( ibfd->bfd, isection ); + if ( ! bfd_set_section_alignment ( obfd->bfd, osection, + bfd_section_alignment ( ibfd->bfd, isection ) ) ) { + bfd_perror ( "Cannot copy section alignment" ); + exit ( 1 ); + } + osection->entsize = isection->entsize; + isection->output_section = osection; + isection->output_offset = 0; + if ( ! bfd_copy_private_section_data ( ibfd->bfd, isection, + obfd->bfd, osection ) ){ + bfd_perror ( "Cannot copy section private data" ); + exit ( 1 ); + } + } + + /* Copy symbol table */ + bfd_set_symtab ( obfd->bfd, ibfd->symtab, ibfd->symcount ); + obfd->symtab = ibfd->symtab; + + return obfd; +} + +/** + * Copy section from input BFD file to output BFD file + * + * @v obfd Output BFD file + * @v ibfd Input BFD file + * @v section Section + */ +static void copy_bfd_section ( struct bfd_file *obfd, struct bfd_file *ibfd, + asection *isection ) { + size_t size; + void *buf; + arelent **reltab; + arelent **rel; + char *errmsg; + + /* Read in original section */ + size = bfd_section_size ( ibfd->bfd, isection ); + if ( ! size ) + return; + buf = xmalloc ( size ); + if ( ( ! bfd_get_section_contents ( ibfd->bfd, isection, + buf, 0, size ) ) ) { + fprintf ( stderr, "Cannot read section %s: ", isection->name ); + bfd_perror ( NULL ); + exit ( 1 ); + } + + /* Perform relocations. We do this here, rather than letting + * ld do it for us when creating the input ELF file, so that + * we can change symbol values as a result of having created + * the .reloc section. + */ + reltab = read_reltab ( ibfd, isection ); + for ( rel = reltab ; *rel ; rel++ ) { + bfd_perform_relocation ( ibfd->bfd, *rel, buf, isection, + NULL, &errmsg ); + } + free ( reltab ); + + /* Write out modified section */ + if ( ( ! bfd_set_section_contents ( obfd->bfd, + isection->output_section, + buf, 0, size ) ) ) { + fprintf ( stderr, "Cannot write section %s: ", + isection->output_section->name ); + bfd_perror ( NULL ); + exit ( 1 ); + } + + free ( buf ); +} + +/** + * Process relocation record + * + * @v section Section + * @v rel Relocation entry + * @v pe_reltab PE relocation table to fill in + */ +static void process_reloc ( asection *section, arelent *rel, + struct pe_relocs **pe_reltab ) { + reloc_howto_type *howto = rel->howto; + asymbol *sym = *(rel->sym_ptr_ptr); + unsigned long offset = ( section->lma + rel->address ); + + if ( bfd_is_abs_section ( sym->section ) ) { + /* Skip absolute symbols; the symbol value won't + * change when the object is loaded. + */ + } else if ( strcmp ( howto->name, "R_386_32" ) == 0 ) { + /* Generate a 4-byte PE relocation */ + generate_pe_reloc ( pe_reltab, offset, 4 ); + } else if ( strcmp ( howto->name, "R_386_16" ) == 0 ) { + /* Generate a 2-byte PE relocation */ + generate_pe_reloc ( pe_reltab, offset, 2 ); + } else if ( strcmp ( howto->name, "R_386_PC32" ) == 0 ) { + /* Skip PC-relative relocations; all relative offsets + * remain unaltered when the object is loaded. + */ + } else { + fprintf ( stderr, "Unrecognised relocation type %s\n", + howto->name ); + exit ( 1 ); + } +} + +/** + * Create .reloc section + * + * obfd Output BFD file + * section .reloc section in output file + * pe_reltab PE relocation table + */ +static void create_reloc_section ( struct bfd_file *obfd, asection *section, + struct pe_relocs *pe_reltab ) { + size_t raw_size; + size_t size; + size_t old_size; + void *buf; + asymbol **sym; + + /* Build binary PE relocation table */ + raw_size = output_pe_reltab ( pe_reltab, NULL ); + size = ( ( raw_size + 31 ) & ~31 ); + buf = xmalloc ( size ); + memset ( buf, 0, size ); + output_pe_reltab ( pe_reltab, buf ); + + /* Write .reloc section */ + old_size = bfd_section_size ( obfd->bfd, section ); + if ( ! bfd_set_section_size ( obfd->bfd, section, size ) ) { + bfd_perror ( "Cannot resize .reloc section" ); + exit ( 1 ); + } + if ( ! bfd_set_section_contents ( obfd->bfd, section, + buf, 0, size ) ) { + bfd_perror ( "Cannot set .reloc section contents" ); + exit ( 1 ); + } + + /* Update symbols pertaining to the relocation directory */ + for ( sym = obfd->symtab ; *sym ; sym++ ) { + if ( strcmp ( (*sym)->name, "_reloc_memsz" ) == 0 ) { + (*sym)->value = size; + } else if ( strcmp ( (*sym)->name, "_reloc_filesz" ) == 0 ){ + (*sym)->value = raw_size; + } else if ( strcmp ( (*sym)->name, "_filesz" ) == 0 ) { + (*sym)->value += ( size - old_size ); + } + } +} + +int main ( int argc, const char *argv[] ) { + const char *iname; + const char *oname; + struct bfd_file *ibfd; + struct bfd_file *obfd; + asection *section; + arelent **reltab; + arelent **rel; + struct pe_relocs *pe_reltab = NULL; + asection *reloc_section; + + /* Initialise libbfd */ + bfd_init(); + + /* Identify intput and output files */ + if ( argc != 3 ) { + fprintf ( stderr, "Syntax: %s infile outfile\n", argv[0] ); + exit ( 1 ); + } + iname = argv[1]; + oname = argv[2]; + + /* Open BFD files */ + ibfd = open_input_bfd ( iname ); + obfd = open_output_bfd ( oname, ibfd ); + + /* Process relocations in all sections */ + for ( section = ibfd->bfd->sections ; section ; + section = section->next ) { + reltab = read_reltab ( ibfd, section ); + for ( rel = reltab ; *rel ; rel++ ) { + process_reloc ( section, *rel, &pe_reltab ); + } + free ( reltab ); + } + + /* Create modified .reloc section */ + reloc_section = bfd_get_section_by_name ( obfd->bfd, ".reloc" ); + if ( ! reloc_section ) { + fprintf ( stderr, "Cannot find .reloc section\n" ); + exit ( 1 ); + } + create_reloc_section ( obfd, reloc_section, pe_reltab ); + + /* Copy other section contents */ + for ( section = ibfd->bfd->sections ; section ; + section = section->next ) { + if ( section->output_section != reloc_section ) + copy_bfd_section ( obfd, ibfd, section ); + } + + /* Write out files and clean up */ + bfd_close ( obfd->bfd ); + bfd_close ( ibfd->bfd ); + + return 0; +} diff --git a/gpxe/src/util/geniso b/gpxe/src/util/geniso index 7642ed36..d7ddbd2b 100755 --- a/gpxe/src/util/geniso +++ b/gpxe/src/util/geniso @@ -52,5 +52,5 @@ do echo "" KERNEL $g cp -p $f $dir/$g done >> $cfg -mkisofs -l -o $out -c boot.cat -b isolinux.bin -no-emul-boot -boot-load-size 4 -boot-info-table $dir +mkisofs -q -l -o $out -c boot.cat -b isolinux.bin -no-emul-boot -boot-load-size 4 -boot-info-table $dir rm -fr $dir diff --git a/gpxe/src/util/mergerom.pl b/gpxe/src/util/mergerom.pl old mode 100644 new mode 100755 diff --git a/gpxe/src/util/mkconfig.pl b/gpxe/src/util/mkconfig.pl deleted file mode 100755 index e55c2ca8..00000000 --- a/gpxe/src/util/mkconfig.pl +++ /dev/null @@ -1,205 +0,0 @@ -#!/usr/bin/perl -w - -use File::Spec::Functions qw ( :ALL ); -use File::stat; -use strict; -use warnings; - -my $cfgdir = "config"; -my $config_h = shift || "config.h"; -my @input_files; - -# Read in a whole file -# -sub read_file { - my $file = shift; - - open my $fh, "<$file" or die "Could not open file $file: $!\n"; - local $/; - my $data = <$fh>; - close $fh; - return $data; -} - -# Write out a whole file -# -sub write_file { - my $file = shift; - my $data = shift; - - open my $fh, ">$file" or die "Could not write $file: $!\n"; - print $fh $data; - close $fh; -} - -# Delete a file -# -sub delete_file { - my $file = shift; - - unlink $file or die "Could not delete $file: $!\n"; -} - -# Get a file modification time -# -sub file_mtime { - my $file = shift; - - my $stat = stat ( $file ) or die "Could not stat $file: $!\n"; - return $stat->mtime; -} - -# Read all the .h files in a directory -# -sub read_dir { - my $dir = shift; - - opendir my $dh, $dir or die "Could not open directory $dir: $!\n"; - my @entries = grep { /\.h$/ } readdir $dh; - closedir $dh; - return @entries; -} - -# Get the current configuration by reading the configuration file -# fragments -# -sub current_config { - my $dir = shift; - - my $cfg = {}; - foreach my $file ( read_dir ( $dir ) ) { - $cfg->{$file} = read_file ( catfile ( $dir, $file ) ); - } - return $cfg; -} - -# Calculate guard name for a header file -# -sub guard { - my $name = shift; - - $name =~ s/\W/_/g; - return "CONFIG_".( uc $name ); -} - -# Calculate preamble for a header file -# -sub preamble { - my $name = shift; - my $master = shift; - - my $guard = guard ( $name ); - my $preamble = <<"EOF"; -/* - * This file is automatically generated from $master. Do not edit this - * file; edit $master instead. - * - */ - -#ifndef $guard -#define $guard -EOF - return $preamble; -} - -# Calculate postamble for a header file -# -sub postamble { - my $name = shift; - - my $guard = guard ( $name ); - return "\n#endif /* $guard */\n"; -} - -# Parse one config.h file into an existing configuration -# -sub parse_config { - my $file = shift; - my $cfg = shift; - my $cursor = ""; - - push ( @input_files, $file ); - - open my $fh, "<$file" or die "Could not open $file: $!\n"; - while ( <$fh> ) { - if ( ( my $newcursor, my $suffix ) = /\@BEGIN\s+(\w+\.h)(.*)$/ ) { - die "Missing \"\@END $cursor\" before \"\@BEGIN $1\"" - ." at $file line $.\n" if $cursor; - $cursor = $newcursor; - $cfg->{$cursor} = preamble ( $cursor, $file ) - unless exists $cfg->{$cursor}; - $cfg->{$cursor} .= "\n/*".$suffix."\n"; - } elsif ( ( my $prefix, my $oldcursor ) = /^(.*)\@END\s+(\w+\.h)/ ) { - die "Missing \"\@BEGIN $oldcursor\" before \"\@END $oldcursor\"" - ." at $file line $.\n" unless $cursor eq $oldcursor; - $cfg->{$cursor} .= $prefix."*/\n"; - $cursor = ""; - } elsif ( ( my $newfile ) = /\@TRYSOURCE\s+([\w\-]+\.h)/ ) { - die "Missing \"\@END $cursor\" before \"\@TRYSOURCE $newfile\"" - ." at $file line $.\n" if $cursor; - parse_config ( $newfile, $cfg ) if -e $newfile; - } else { - $cfg->{$cursor} .= $_ if $cursor; - } - } - close $fh; - die "Missing \"\@END $cursor\" in $file\n" if $cursor; -} - -# Get the new configuration by splitting config.h file using the -# @BEGIN/@END tags -# -sub new_config { - my $file = shift; - my $cfg = {}; - - parse_config ( $file, $cfg ); - - foreach my $cursor ( keys %$cfg ) { - $cfg->{$cursor} .= postamble ( $cursor ); - } - - return $cfg; -} - -############################################################################# -# -# Main program - -# Read in current config file fragments -# -my $current = current_config ( $cfgdir ); - -# Read in config.h and split it into fragments -# -my $new = new_config ( $config_h ); - -# Delete any no-longer-wanted config file fragments -# -foreach my $file ( keys %$current ) { - unlink catfile ( $cfgdir, $file ) unless exists $new->{$file}; -} - -# Write out any modified fragments, and find the oldest timestamp of -# any unmodified fragments. -# -my $oldest = time (); -foreach my $file ( keys %$new ) { - if ( $current->{$file} && $new->{$file} eq $current->{$file} ) { - # Unmodified - my $time = file_mtime ( catfile ( $cfgdir, $file ) ); - $oldest = $time if $time < $oldest; - } else { - write_file ( catfile ( $cfgdir, $file ), $new->{$file} ); - } -} - -# If we now have fragments that are older than config.h, set the -# timestamp on each input file to match the oldest fragment, to -# prevent make from always attempting to rebuild the fragments. -# -foreach my $file ( @input_files ) { - if ( $oldest < file_mtime ( $file ) ) { - utime time(), $oldest, $file or die "Could not touch $file: $!\n"; - } -} diff --git a/gpxe/src/util/sortobjdump.pl b/gpxe/src/util/sortobjdump.pl index 8ad7314b..1373a7ff 100755 --- a/gpxe/src/util/sortobjdump.pl +++ b/gpxe/src/util/sortobjdump.pl @@ -8,7 +8,7 @@ use warnings; # linker maps produced by "make bin/%.map" by also showing the values # of all non-global symbols. -my %section_idx = ( "*ABS*" => "." ); +my %section_idx = ( "*ABS*" => ".", "*UND*" => "_" ); my %lines; while ( <> ) { if ( /^\s+(\d+)\s+([\.\*]\S+)\s+[0-9a-fA-F]+\s+[0-9a-fA-F]/ ) { diff --git a/gpxe/src/util/zbin.c b/gpxe/src/util/zbin.c index b24f401e..c1082b31 100644 --- a/gpxe/src/util/zbin.c +++ b/gpxe/src/util/zbin.c @@ -6,6 +6,8 @@ #include "nrv2b.c" FILE *infile, *outfile; +#define DEBUG 0 + struct input_file { void *buf; size_t len; @@ -151,6 +153,11 @@ static int process_zinfo_copy ( struct input_file *input, return -1; } + if ( DEBUG ) { + fprintf ( stderr, "COPY [%#zx,%#zx) to [%#zx,%#zx)\n", offset, ( offset + len ), + output->len, ( output->len + len ) ); + } + memcpy ( ( output->buf + output->len ), ( input->buf + offset ), len ); output->len += len; @@ -184,6 +191,11 @@ static int process_zinfo_pack ( struct input_file *input, return -1; } + if ( DEBUG ) { + fprintf ( stderr, "PACK [%#zx,%#zx) to [%#zx,%#zx)\n", offset, ( offset + len ), + output->len, ( output->len + packed_len ) ); + } + output->len += packed_len; if ( output->len > output->max_len ) { fprintf ( stderr, "Output buffer overrun on pack\n" ); @@ -200,6 +212,8 @@ static int process_zinfo_subtract ( struct input_file *input, size_t offset = subtract->offset; void *target; long delta; + unsigned long old; + unsigned long new; if ( ( offset + datasize ) > output->len ) { fprintf ( stderr, "Subtract at %#zx outside output buffer\n", @@ -214,21 +228,34 @@ static int process_zinfo_subtract ( struct input_file *input, switch ( datasize ) { case 1: { uint8_t *byte = target; + old = *byte; *byte += delta; + new = *byte; break; } case 2: { uint16_t *word = target; + old = *word; *word += delta; + new = *word; break; } case 4: { uint32_t *dword = target; + old = *dword; *dword += delta; + new = *dword; break; } default: fprintf ( stderr, "Unsupported subtract datasize %d\n", datasize ); return -1; } + + if ( DEBUG ) { + fprintf ( stderr, "SUBx [%#zx,%#zx) (%#lx+(%#lx/%#lx)-(%#lx/%#lx)) = %#lx\n", + offset, ( offset + datasize ), old, output->len, subtract->divisor, + input->len, subtract->divisor, new ); + } + return 0; } -- cgit v1.2.1