Merge branch 'caps_next'
authorSimon Gerber <simon.gerber@inf.ethz.ch>
Tue, 7 Jun 2016 14:18:20 +0000 (16:18 +0200)
committerSimon Gerber <simon.gerber@inf.ethz.ch>
Tue, 7 Jun 2016 14:18:20 +0000 (16:18 +0200)
This merge changes capabilities for address ranges (e.g. RAM, PhysAddr, ...)
from power-of-two sizes given in bits to sizes given in bytes. The current
implementation restricts capabilities to be sized >= BASE_PAGE_SIZE.  In
addition, retype now can "cut out" a part of a large capability to create a
descendant without having to create descendants for the whole region.  To
ensure integrity of operations, calls to retype result in a range query on the
capability database to check for already existing, overlapping descendants of
the source capability.

Closes T191.

Signed-off-by: Simon Gerber <simon.gerber@inf.ethz.ch>

26 files changed:
errors/errno.fugu
lib/gmp/Hakefile
platforms/Hakefile
tools/harness/barrelfish.py
tools/harness/tests/irqtest.py [new file with mode: 0644]
tools/harness/tests/spantest.py
usr/acpi/acpi.c
usr/acpi/acpi_service.c
usr/acpi/acpi_shared.h
usr/monitor/capops/capsend.c
usr/monitor/capops/copy.c
usr/monitor/capops/delete.c
usr/monitor/capops/move.c
usr/monitor/capops/retrieve.c
usr/monitor/capops/retype.c
usr/monitor/capops/revoke.c
usr/pci/pci.c
usr/tests/irqtest/Hakefile [new file with mode: 0644]
usr/tests/irqtest/e1000n.h [new file with mode: 0644]
usr/tests/irqtest/e1000n_desc.h [new file with mode: 0644]
usr/tests/irqtest/e1000n_helpers.c [new file with mode: 0644]
usr/tests/irqtest/e1000n_hwinit.c [new file with mode: 0644]
usr/tests/irqtest/e1000n_hwinit.h [new file with mode: 0644]
usr/tests/irqtest/irqtest.c [new file with mode: 0644]
usr/tests/irqtest/irqtest_debug.h [new file with mode: 0644]
usr/tests/nkm/Hakefile

index a486e72..090bcf9 100755 (executable)
@@ -804,6 +804,8 @@ errors pci PCI_ERR_ {
 errors acpi ACPI_ERR_ {
     failure NO_MCFG_TABLE       "No MCFG Table found.",
     failure INVALID_PATH_NAME   "Invalid ACPI path name.",
+    failure INVALID_HANDLE      "Invalid ACPI handle.",
+    failure NO_CHILD_BRIDGE     "No matching child bridge found.",
     failure GET_RESOURCES       "Failed to execute _CRT method.",
     failure SET_IRQ             "Failed to set IRQ for device.",
     failure NO_MADT_TABLE       "No APIC found in ACPI.",
index e5dd454..c77e6b5 100644 (file)
@@ -31,11 +31,14 @@ let gmp_url = "https://gmplib.org/download/gmp/gmp-6.1.0.tar.bz2"
     -- would not find its headers.
 
     commonLinkFlags arch =
-        [ Str "-nostdlib",  NStr "-L", makeAbs $ NoDep BuildTree arch "/lib/" ]
-        ++ [ Str "-Wl,--start-group" ]
-        ++ (map makeAbs (optLibs (options arch)))
-        ++ (map makeAbs (extraLink arch))
-        ++ [
+        [ Str "-nostdlib",  NStr "-L", makeAbs $ NoDep BuildTree arch "/lib/" ] ++
+         [ Str "-Wl,--start-group" ]
+-- The following line seems to add libbarrelfish as an dependency which
+--
+--        ++ (map makeAbs (optLibs (options arch)))
+--        ++ (map makeAbs (extraLink arch))
+        ++
+        [
             Str "-Wl,--end-group",
 -- Enable the following flags for ld debugging
 --            Str "-Wl,-verbose=2",
@@ -61,7 +64,10 @@ let gmp_url = "https://gmplib.org/download/gmp/gmp-6.1.0.tar.bz2"
         ++ (compileCFLAGS arch)
         ++ [ Str "\"" ]
 
-    envCC arch = [ NStr "CC=" , Str (RuleDefs.compiler $ options arch) ]
+    envCC arch =
+        [ NStr "CC=\"" ]
+        ++ [Str (RuleDefs.compiler $ options arch)]
+        ++ [ Str "\"" ]
 
     convertArch arch = case arch of
         "x86_64"  -> "x86_64-unknown-none"
@@ -99,6 +105,7 @@ in [ ] ++ (getExternalDependency gmp_url gmp_archive) ++
         Target arch "configure"
         ]
     ),
+
     -- run configure
     Rule ( [
         -- this is tricky as configure produces Makefile in .
@@ -140,10 +147,10 @@ in [ ] ++ (getExternalDependency gmp_url gmp_archive) ++
         Str "sed -i.orig s/HAVE_OBSTACK_VPRINTF/HAVE_OBSTACK_VPRINTF_nope/g",
         Out arch "config.h"
         ]
-        ++
-        (map toDep (optLibs (options arch)))
-        ++
-        (map toDep (extraLink arch))
+--      ++
+--      (map toDep (optLibs (options arch)))
+--        ++
+--        (map toDep (extraLink arch))
     ),
     -- run make
     Rule ( [
index 7271e9b..22e8457 100644 (file)
@@ -7,10 +7,10 @@
 -- ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
 --
 -- Hakefile for /platforms/
--- 
+--
 --------------------------------------------------------------------------
 
-let bin_rcce_lu = [ "/sbin/" ++ f | f <- [ 
+let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
                         "rcce_lu_A1",
                         "rcce_lu_A2",
                         "rcce_lu_A4",
@@ -19,7 +19,7 @@ let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
                         "rcce_lu_A32",
                         "rcce_lu_A64" ]]
 
-    bin_rcce_bt = [ "/sbin/" ++ f | f <- [ 
+    bin_rcce_bt = [ "/sbin/" ++ f | f <- [
                         "rcce_bt_A1",
                         "rcce_bt_A4",
                         "rcce_bt_A9",
@@ -29,8 +29,6 @@ let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
 
     tests_common = [ "/sbin/" ++ f | f <- [
                         "fputest",
-                        "fread_test",
-                        "fscanf_test",
                         "hellotest",
                         "idctest",
                         "memtest",
@@ -42,12 +40,14 @@ let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
                         "testerror",
                         "yield_test" ] ]
 
-    tests_x86 = [ "/sbin/" ++ f | f <- [ 
+    tests_x86 = [ "/sbin/" ++ f | f <- [
                         "tests/luatest",
                         "tests/numatest" ] ] ++ tests_common
 
-    tests_x86_64 = [ "/sbin/" ++ f | f <- [ 
+    tests_x86_64 = [ "/sbin/" ++ f | f <- [
                         "arrakis_hellotest",
+                        "fread_test",
+                        "fscanf_test",
                         "ata_rw28_test",
                         "bomp_cpu_bound",
                         "bomp_cpu_bound_progress",
@@ -83,7 +83,10 @@ let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
                         "xcorecap",
                         "xcorecapserv" ] ] ++ tests_x86
 
-    tests_x86_32 = tests_x86
+    tests_x86_32 = [ "/sbin/" ++ f | f <- [
+                    "fread_test",
+                    "fscanf_test"
+                    ] ] ++ tests_x86
 
     tests_k1om = [ "/sbin/" ++ f | f <- [
                         "tests/dma_test",
@@ -91,14 +94,14 @@ let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
                         "tests/xeon_phi_test",
                         "tests/xphi_nameservice_test" ] ] ++ tests_x86
 
-    bench_common = [ "/sbin/" ++ f | f <- [ 
+    bench_common = [ "/sbin/" ++ f | f <- [
                         "channel_cost_bench",
                         "flounder_stubs_buffer_bench",
                         "flounder_stubs_empty_bench",
                         "flounder_stubs_payload_bench",
                         "xcorecapbench" ]]
 
-    bench_x86 =  [ "/sbin/" ++ f | f <- [ 
+    bench_x86 =  [ "/sbin/" ++ f | f <- [
                       "multihop_latency_bench",
                       "net_openport_test",
                       "perfmontest",
@@ -112,8 +115,8 @@ let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
                       "ump_send",
                       "ump_throughput" ]]
 
-    bench_x86_64 = bench_x86 ++ bin_rcce_bt ++ bin_rcce_lu ++ 
-                   [ "/sbin/" ++ f | f <- [ 
+    bench_x86_64 = bench_x86 ++ bin_rcce_bt ++ bin_rcce_lu ++
+                   [ "/sbin/" ++ f | f <- [
                         "ahci_bench",
                         "apicdrift_bench",
                         "benchmarks/bomp_mm",
@@ -145,7 +148,7 @@ let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
 
     bench_x86_32 = bench_x86 ++ bin_rcce_bt ++ bin_rcce_lu
 
-    bench_k1om = [ "/sbin/" ++ f | f <- [ 
+    bench_k1om = [ "/sbin/" ++ f | f <- [
                         "benchmarks/bomp_mm",
                         "benchmarks/dma_bench",
                         "benchmarks/xomp_share",
@@ -155,7 +158,7 @@ let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
                         "benchmarks/xphi_xump_bench" ] ] ++ bench_x86
 
     -- Default list of modules to build/install for all enabled architectures
-    modules_common = [ "/sbin/" ++ f | f <- [ 
+    modules_common = [ "/sbin/" ++ f | f <- [
                           "init",
                           "chips",
                           "skb",
@@ -172,8 +175,8 @@ let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
         "/sshd_ramfs.cpio.gz" ]
 
     -- x86_64-specific modules to build by default
-    -- this should shrink as targets are ported and move into the generic list above 
-    modules_x86_64  = [ "/sbin/" ++ f | f <- [ 
+    -- this should shrink as targets are ported and move into the generic list above
+    modules_x86_64  = [ "/sbin/" ++ f | f <- [
                            "elver",
                            "cpu",
                            "acpi",
@@ -223,17 +226,17 @@ let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
                            "xeon_phi",
                            "xeon_phi_mgr"
                            ]] ++ modules_common
-    
+
     -- the following are broken in the newidc system
-    modules_x86_64_broken  = [ "/sbin/" ++ f | f <- [ 
+    modules_x86_64_broken  = [ "/sbin/" ++ f | f <- [
                                   "barriers",
                                   "ipi_bench",
                                   "ring_barriers",
                                   "ssf_bcast",
                                   "lamport_bcast" ]]
-                             
+
     -- x86-32-specific module to build by default
-    modules_x86_32  = [ "/sbin/" ++ f | f <- [ 
+    modules_x86_32  = [ "/sbin/" ++ f | f <- [
                            "cpu",
                            "lpc_kbd",
                            "serial",
@@ -337,7 +340,7 @@ let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
    --
    -- Rules to build assorted platforms
    --
-   
+
     platform "X86_64_Basic" [ "x86_64" ]
       ([ ("x86_64", f) | f <- modules_x86_64 ]
        ++
@@ -395,7 +398,7 @@ let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
     platform "PandaboardES" [ "armv7" ]
     ([ ("armv7", f) | f <- pandaModules ] ++ [ ("root", "/pandaboard_image") ])
     "Standard Pandaboard ES build image and modules",
-    
+
     platform "ARMv8-GEM5" [ "armv8" ]
     ([ ("armv8", f) | f <- armv8_gem5Modules ] ++ [ ("root", "/armv8_gem5_image") ])
     "GEM5 emulator for ARM Cortex-A series multicore processors",
@@ -419,11 +422,11 @@ let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
     --
     -- Rules to build assorted boot images
     --
-    
+
     -- Build the default PandaBoard boot image
     Rule ([ In SrcTree "tools" "/tools/arm_molly/build_pandaboard_image.sh",
-            Str "--srcdir",   NoDep SrcTree "root" "/.", 
-            Str "--builddir", NoDep BuildTree "root" "/.", 
+            Str "--srcdir",   NoDep SrcTree "root" "/.",
+            Str "--builddir", NoDep BuildTree "root" "/.",
             Str "--arch armv7-a",
             Str "--menu",     In SrcTree "tools" "/hake/menu.lst.pandaboard",
             Str "--baseaddr", Str "0x82001000",
@@ -435,7 +438,7 @@ let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
 
     -- Build the (old) PandaBoard Cortex-M3 image
     Rule ([ In SrcTree "tools" "/tools/arm_molly/build_pandaboard_image.sh",
-            Str "--srcdir",   NoDep SrcTree "root" "/.", 
+            Str "--srcdir",   NoDep SrcTree "root" "/.",
             Str "--builddir", NoDep BuildTree "root" "/.",
             Str "--arch armv7-m",
             Str "--menu",     In SrcTree "tools" "/hake/menu.lst.armv7-m",
@@ -459,8 +462,8 @@ let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
 
     -- Build the ARMv7 GEM5 simulation image
     Rule ([ In SrcTree "tools" "/tools/arm_molly/build_pandaboard_image.sh",
-            Str "--srcdir",   NoDep SrcTree "root" "/.", 
-            Str "--builddir", NoDep BuildTree "root" "/.", 
+            Str "--srcdir",   NoDep SrcTree "root" "/.",
+            Str "--builddir", NoDep BuildTree "root" "/.",
             Str "--arch armv7-a",
             Str "--menu",     In SrcTree "tools" "/hake/menu.lst.arm_gem5_mc",
             Str "--baseaddr", Str "0x100000",
@@ -472,8 +475,8 @@ let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
 
     -- Build the ARMv8 GEM5 simulation image
     Rule ([ In SrcTree "tools" "/tools/arm_molly/build_pandaboard_image.sh",
-            Str "--srcdir",   NoDep SrcTree "root" "/.", 
-            Str "--builddir", NoDep BuildTree "root" "/.", 
+            Str "--srcdir",   NoDep SrcTree "root" "/.",
+            Str "--builddir", NoDep BuildTree "root" "/.",
             Str "--arch armv8-a",
             Str "--menu",     In SrcTree "tools" "/hake/menu.lst.armv8_gem5",
             Str "--baseaddr", Str "0x100000",
@@ -510,7 +513,7 @@ let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
     Rules [ copyFile SrcTree "root" ("/hake/menu.lst." ++ p)
                      "root" ("/platforms/x86/menu.lst." ++ p)
             | p <- [ "x86_32", "x86_64", "k1om" ] ],
-    
+
     -- Convenient functions for running GEM5
     boot "gem5_armv8" [ "armv8" ] [
       Str Config.gem5,
@@ -555,7 +558,7 @@ let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
       Str "--menu", In BuildTree "root" "/platforms/x86/menu.lst.x86_64",
       Str "--arch", Str "x86_64" ]
     "Boot QEMU in 64-bit x86 mode emulating a PC",
-    
+
     boot "qemu_x86_32" [ "x86_32" ] [
       In SrcTree "tools" "/tools/qemu-wrapper.sh",
       Str "--menu", In BuildTree "root" "/platforms/x86/menu.lst.x86_32",
@@ -568,7 +571,7 @@ let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
       Str "--arch", Str "x86_64",
       Str "--debug", In SrcTree "tools" "/tools/debug.gdb" ]
     "Boot QEMU under GDB in 64-bit x86 mode emulating a PC",
-    
+
     boot "qemu_x86_32_debug" [ "x86_32" ] [
       In SrcTree "tools" "/tools/qemu-wrapper.sh",
       Str "--menu", In BuildTree "root" "/platforms/x86/menu.lst.x86_32",
index 38e930a..e7243b0 100644 (file)
@@ -140,7 +140,7 @@ def default_bootmodules(build, machine):
 
         if machine.name == "sbrinz1" or machine.name == "sbrinz2" \
         or machine.name == "tomme1" or machine.name == "tomme2" \
-        or is_babybel == 1 :
+        or machine.name == "appenzeller" or is_babybel == 1 :
             # PCI allocation broken, use BIOS plan
             m.add_module("%s/sbin/pci" % a, ["auto",
                                              "skb_bridge_program=bridge_bios"] + machine.get_pci_args())
diff --git a/tools/harness/tests/irqtest.py b/tools/harness/tests/irqtest.py
new file mode 100644 (file)
index 0000000..ba47eef
--- /dev/null
@@ -0,0 +1,54 @@
+##########################################################################
+# Copyright (c) 2011, ETH Zurich.
+# All rights reserved.
+#
+# This file is distributed under the terms in the attached LICENSE file.
+# If you do not find this file, copies can be found by writing to:
+# ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+##########################################################################
+import datetime
+import re
+import tests
+from common import TestCommon
+from results import PassFailResult
+
+#IRQTEST_TIMEOUT = datetime.timedelta(minutes=5)
+
+@tests.add_test
+class IRQTest(TestCommon):
+    '''PCI IRQ test'''
+    name = "irqtest"
+
+    def get_machine_irqtest_args(self, machine):
+        '''For a given machine, return the paramaters passed to irqtest.
+        It should contain of the e1000 PCI device id, and if there are multiple
+        cards, also the PCI function.'''
+        mn = machine.get_machine_name()
+        if mn.startswith("sbrinz"):
+            return ["deviceid=0x1079", "function=0"]
+        elif mn == "gruyere":
+            return ["deviceid=0x1076"]
+        elif mn == "appenzeller":
+            return ["deviceid=0x10d3"]
+        elif mn.startswith("nos"):
+            return ["deviceid=0x107d"]
+        elif mn.startswith("tomme"):
+            return ["deviceid=0x10a7", "function=0"]
+        else:
+            raise Exception("Machine %s not supported" % mn)
+        
+    
+    def get_modules(self, build, machine):
+        modules = super(IRQTest, self).get_modules(build, machine)
+        modules.add_module("irqtest",
+                ["core=%d" % machine.get_coreids()[1]] + self.get_machine_irqtest_args(machine))
+        return modules
+
+    def is_finished(self, line):
+        return line.startswith("TEST ") 
+    
+    def process_data(self, testdir, rawiter):
+        for line in rawiter:
+            if line.startswith("TEST SUCCESS"):
+                return PassFailResult(True)
+        return PassFailResult(False)
index 1a783f6..2eaceeb 100644 (file)
@@ -112,13 +112,13 @@ class SpanTestExit(TestCommon):
             except TimeoutError as e:
                 if self.boot_phase:
                     if self.boot_attempts < MAX_BOOT_ATTEMPTS:
-                        yield BOOT_TIMEOUT_LINE_RETRY
+                        yield '[Error: boot timed out, retry]\n'
                         self.reboot(machine)
                         continue
                     else:
-                        yield BOOT_TIMEOUT_LINE_FAIL
+                        yield '[Error: boot timed out, retry limit reached]\n'
                 else:
-                    yield TEST_TIMEOUT_LINE
+                    yield '[Error: test timed out]\n'
                 debug.verbose("timeout encountered in collect_data");
                 self.has_timeout = True
                 if self.is_done :
index 62b346e..f0f9a1f 100644 (file)
@@ -28,6 +28,9 @@
 #include "intel_vtd.h"
 #include <trace/trace.h>
 
+#define PCI_LNK_DEV_STRING              "PNP0C0F"
+#define METHOD_NAME__DIS                "_DIS"
+
 struct pci_resources {
     uint8_t minbus, maxbus;
     lpaddr_t minmem, maxmem;
@@ -303,14 +306,25 @@ static void get_irq_routing(ACPI_HANDLE handle, uint8_t bus)
     char prtbuf[2048];
     ACPI_BUFFER bufobj = {.Length = sizeof(prtbuf), .Pointer = prtbuf};
 
+    char namebuf[256];
+    ACPI_BUFFER namebufobj = {.Length = sizeof(namebuf), .Pointer = namebuf};
+
+    as = AcpiGetName(handle, ACPI_FULL_PATHNAME, &namebufobj);
+    if (ACPI_FAILURE(as)) {
+        ACPI_DEBUG("No name found: %s\n", AcpiFormatException(as));
+        namebuf[0] = 0;
+    } else {
+        assert(namebufobj.Pointer == namebuf);
+    }
+
     /* do we have an interrupt routing table? */
     as = AcpiGetIrqRoutingTable(handle, &bufobj);
     if (ACPI_FAILURE(as)) {
-        ACPI_DEBUG("No IRQ routing table found: %s\n", AcpiFormatException(as));
+        ACPI_DEBUG("No PCI IRQ routing table for (%s) bus %"PRIu8": %s\n", namebuf, bus, AcpiFormatException(as));
         return;
     }
 
-    //printf("PCI IRQ routing table:\n");
+    ACPI_DEBUG("PCI IRQ routing table for (%s) bus %"PRIu8":\n", namebuf, bus);
     ACPI_PCI_ROUTING_TABLE *prt = bufobj.Pointer;
     for (; prt->Length; prt = (void *)prt + prt->Length) {
         uint16_t device = (prt->Address >> 16) & 0xffff;
@@ -418,47 +432,35 @@ static void get_irq_routing(ACPI_HANDLE handle, uint8_t bus)
     }
 }
 
-void acpi_get_irqtable_device(ACPI_HANDLE parent,
+errval_t acpi_get_irqtable_device(ACPI_HANDLE parent,
         acpi_pci_address_t device, ACPI_HANDLE *child, uint8_t bus)
 {
-/*     char b[128]; */
-/*     ACPI_BUFFER buf = { .Length = 128, .Pointer = b }; */
-/*     ACPI_STATUS s; */
 
     *child = NULL;
 
     if(parent == NULL) {
-        return;
+        return ACPI_ERR_INVALID_PATH_NAME;
     }
 
-/*     s = AcpiGetName(parent, ACPI_FULL_PATHNAME, &buf); */
-/*     assert(ACPI_SUCCESS(s)); */
-/*     printf("Parent: %s\n", b); */
-
+    // For each children of parent
     for(;;) {
         ACPI_STATUS as =
             AcpiGetNextObject(ACPI_TYPE_DEVICE, parent, *child, child);
 
         if(as == AE_NOT_FOUND || *child == NULL) {
-            return;
+            break; //Goto error out
         }
 
         if(ACPI_FAILURE(as)) {
-            ACPI_DEBUG("Error looking up ACPI children\n");
+            ACPI_DEBUG("Error looking up ACPI children.\n");
             abort();
         }
 
-/*         s = AcpiGetName(*child, ACPI_FULL_PATHNAME, &buf); */
-/*         if(ACPI_FAILURE(s)) { */
-/*             printf("Name lookup failure: %d\n", s); */
-/*         } else { */
-/*             printf("Current: %s\n", b); */
-/*         } */
-
-        /* look for a _ADR node, which tells us the bridge's configuration space */
+        // look for a _ADR node, which tells us the bridge's configuration space
         ACPI_INTEGER addr;
         as = acpi_eval_integer(*child, "_ADR", &addr);
         if (ACPI_FAILURE(as)) {
+            ACPI_DEBUG("No _ADR method found !?!.\n");
             continue;
         }
 
@@ -469,12 +471,48 @@ void acpi_get_irqtable_device(ACPI_HANDLE parent,
 
         if(device.device == bridgeaddr.device
            && device.function == bridgeaddr.function) {
-/*             printf("Found corresponding ACPI bridge device!\n"); */
             get_irq_routing(*child, bus);
+            return SYS_ERR_OK;
         }
     }
+
+    // Error output
+    char namebuf[128];
+    ACPI_BUFFER buf = { .Length = sizeof(namebuf), .Pointer = namebuf };
+    ACPI_STATUS s;
+    s = AcpiGetName(parent, ACPI_FULL_PATHNAME, &buf);
+    assert(ACPI_SUCCESS(s));
+    // LH: It seems this is not a fatal condition, but I am really not sure.
+    ACPI_DEBUG("acpi_service: No matching child bridge found. Parent '%s'. Child %"PRIu8
+           ", %"PRIu8", %"PRIu8" \n", namebuf, bus, device.device, device.function);
+    return ACPI_ERR_NO_CHILD_BRIDGE;
+}
+
+static ACPI_STATUS add_pci_lnk_device(ACPI_HANDLE handle, UINT32 level,
+                                  void *context, void **retval)
+{
+    ACPI_STATUS as;
+    char namebuf[128];
+    ACPI_BUFFER bufobj = {.Length = sizeof(namebuf), .Pointer = namebuf};
+
+    /* get the node's name */
+    as = AcpiGetName(handle, ACPI_FULL_PATHNAME, &bufobj);
+    if (ACPI_FAILURE(as)) {
+        ACPI_DEBUG("Cannot resolve name of PCI Link device\n");
+        return as;
+    }
+    assert(bufobj.Pointer == namebuf);
+    ACPI_DEBUG("Discovered PCI Link device (%s). Disabling\n", namebuf);
+    as = AcpiEvaluateObject(handle, METHOD_NAME__DIS, NULL, NULL);
+    if (ACPI_FAILURE(as)) {
+        ACPI_DEBUG("Cannot execute _DIS of PCI Link device (%s)\n", namebuf);
+        return as;
+    }
+
+    return as;
 }
 
+
 static ACPI_STATUS add_pci_device(ACPI_HANDLE handle, UINT32 level,
                                   void *context, void **retval)
 {
@@ -847,8 +885,10 @@ int init_acpi(void)
     ACPI_DEBUG("Switching to APIC mode...\n");
     as = set_apic_mode();
     if(ACPI_FAILURE(as)) {
-        ACPI_DEBUG("Warning: Could not set system to APIC mode! "
-                  "Continuing anyway...\n");
+        printf("ACPI: Warning: Could not set system to APIC mode! "
+                  "Continuing anyway... status: %s\n", AcpiFormatException(as));
+    } else {
+        printf("ACPI: Switched to APIC mode.\n");
     }
 
     /* look for an MCFG table
@@ -911,6 +951,10 @@ int init_acpi(void)
     as = AcpiGetDevices(PCI_ROOT_HID_STRING, add_pci_device, NULL, NULL);
     assert(ACPI_SUCCESS(as));
 
+    ACPI_DEBUG("Walking for PCI Link devices\n");
+    as = AcpiGetDevices(PCI_LNK_DEV_STRING, add_pci_lnk_device, NULL, NULL);
+    assert(ACPI_SUCCESS(as));
+
     //ACPI_DEBUG("Programming PCI BARs and bridge windows\n");
     //pci_program_bridges();
     //ACPI_DEBUG("PCI programming completed\n");
index 70b3287..3cccd9c 100644 (file)
@@ -135,7 +135,8 @@ static void get_path_name(ACPI_HANDLE handle, char* name, size_t len)
 static void read_irq_table(struct acpi_binding* b, char* pathname,
         acpi_pci_address_t addr, uint8_t bus)
 {
-    ACPI_DEBUG("read_irq_table: %s\n", pathname);
+    ACPI_DEBUG("read_irq_table: (parent)%s, (%"PRIu8",%"PRIu8",%"PRIu8"), %"PRIu8"\n",
+            pathname == NULL ? "NULL" : pathname, addr.bus, addr.device, addr.function, bus);
 
     errval_t err;
     ACPI_STATUS as;
@@ -144,14 +145,20 @@ static void read_irq_table(struct acpi_binding* b, char* pathname,
     as = AcpiGetHandle(NULL, pathname, &handle);
     if (ACPI_SUCCESS(as)) {
         ACPI_HANDLE child;
-        acpi_get_irqtable_device(handle, addr, &child, bus);
-
-        char name[128];
-        get_path_name(child, name, 128);
-        ACPI_DEBUG("Sending back path name: %s\n", name);
-
-        err = b->tx_vtbl.read_irq_table_response(b, NOP_CONT, SYS_ERR_OK, name);
-        assert(err_is_ok(err));
+        err = acpi_get_irqtable_device(handle, addr, &child, bus);
+
+        if(err_is_fail(err)){
+            ACPI_DEBUG("get_irq_table failed.\n");
+            err = b->tx_vtbl.read_irq_table_response(b, NOP_CONT, err, NULL);
+            assert(err_is_ok(err));
+        } else {
+            char name[128];
+            get_path_name(child, name, 128);
+            ACPI_DEBUG("Sending back path name: %s\n", name);
+
+            err = b->tx_vtbl.read_irq_table_response(b, NOP_CONT, SYS_ERR_OK, name);
+            assert(err_is_ok(err));
+        }
     }
     else {
         ACPI_DEBUG("Unknown ACPI Handle for path: %s\n", pathname);
index 463b0dc..d10ea90 100644 (file)
@@ -28,7 +28,7 @@ errval_t find_all_apics(void);
 
 int init_acpi(void);
 ACPI_STATUS acpi_eval_integer(ACPI_HANDLE handle, char *name, ACPI_INTEGER *ret);
-void acpi_get_irqtable_device(ACPI_HANDLE parent, acpi_pci_address_t device,
+errval_t acpi_get_irqtable_device(ACPI_HANDLE parent, acpi_pci_address_t device,
         ACPI_HANDLE *child, uint8_t bus);
 void video_init(void);
 void buttons_init(void);
index e2e806d..af5e674 100644 (file)
@@ -298,6 +298,18 @@ find_cap_result_send_cont(struct intermon_binding *b, struct intermon_msg_queue_
     struct find_cap_result_msg_st *msg_st = (struct find_cap_result_msg_st*)e;
 
     err = intermon_capops_find_cap_result__tx(b, NOP_CONT, msg_st->result, msg_st->st);
+
+    if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+        DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__);
+        struct intermon_state *inter_st = (struct intermon_state *)b->st;
+        // requeue send request at front and return
+        err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset,
+                                             (struct msg_queue_elem *)e);
+        GOTO_IF_ERR(err, handle_err);
+        return;
+    }
+
+handle_err:
     if (err_is_fail(err)) {
         USER_PANIC_ERR(err, "failed to send find_cap_result message");
     }
@@ -450,6 +462,18 @@ find_descendants_result_send_cont(struct intermon_binding *b, struct intermon_ms
     struct find_descendants_result_msg_st *msg_st;
     msg_st = (struct find_descendants_result_msg_st*)e;
     err = intermon_capops_find_descendants_result__tx(b, NOP_CONT, msg_st->status, msg_st->st);
+
+    if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+        DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__);
+        struct intermon_state *inter_st = (struct intermon_state *)b->st;
+        // requeue send request at front and return
+        err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset,
+                                             (struct msg_queue_elem *)e);
+        GOTO_IF_ERR(err, handle_err);
+        return;
+    }
+
+handle_err:
     free(msg_st);
     if (err_is_fail(err)) {
         USER_PANIC_ERR(err, "could not send find_descendants_result");
@@ -573,6 +597,18 @@ owner_updated_send_cont(struct intermon_binding *b, struct intermon_msg_queue_el
     struct owner_updated_msg_st *msg_st = (struct owner_updated_msg_st*)e;
 
     err = intermon_capops_owner_updated__tx(b, NOP_CONT, msg_st->st);
+
+    if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+        DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__);
+        struct intermon_state *inter_st = (struct intermon_state *)b->st;
+        // requeue send request at front and return
+        err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset,
+                                             (struct msg_queue_elem *)e);
+        GOTO_IF_ERR(err, handle_err);
+        return;
+    }
+
+handle_err:
     if (err_is_fail(err)) {
         USER_PANIC_ERR(err, "failed to send owner_updated message");
     }
index 83ff49a..1f0adf6 100644 (file)
@@ -80,6 +80,18 @@ recv_copy_result_send__rdy(struct intermon_binding *b,
     err = intermon_capops_recv_copy_result__tx(b, NOP_CONT, msg_st->status,
                                                msg_st->capaddr, msg_st->vbits,
                                                msg_st->slot, msg_st->st);
+
+    if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+        DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__);
+        struct intermon_state *inter_st = (struct intermon_state *)b->st;
+        // requeue send request at front and return
+        err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset,
+                                             (struct msg_queue_elem *)e);
+        GOTO_IF_ERR(err, handle_err);
+        return;
+    }
+
+handle_err:
     PANIC_IF_ERR(err, "failed to send recv_copy_result");
     free(msg_st);
 }
@@ -146,6 +158,17 @@ owner_copy_send__rdy(struct intermon_binding *b,
     err = intermon_capops_recv_copy__tx(b, NOP_CONT, msg_st->caprep,
                                         msg_st->owner_relations, msg_st->st);
 
+    if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+        DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__);
+        struct intermon_state *inter_st = (struct intermon_state *)b->st;
+        // requeue send request at front and return
+        err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset,
+                                             (struct msg_queue_elem *)e);
+        GOTO_IF_ERR(err, handle_err);
+        return;
+    }
+
+handle_err:
     if (err_is_fail(err)) {
         // send failed, report result
         rpc_st->recv_handler(err, 0, 0, 0, rpc_st);
@@ -297,6 +320,18 @@ request_copy_send__rdy(struct intermon_binding *b,
     err = intermon_capops_request_copy__tx(b, NOP_CONT, msg_st->dest,
                                            msg_st->caprep,
                                            (lvaddr_t)msg_st->st);
+
+    if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+        DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__);
+        struct intermon_state *inter_st = (struct intermon_state *)b->st;
+        // requeue send request at front and return
+        err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset,
+                                             (struct msg_queue_elem *)e);
+        GOTO_IF_ERR(err, handle_err);
+        return;
+    }
+
+handle_err:
     if (err_is_fail(err)) {
         assert(msg_st->st);
         struct cap_copy_rpc_st *rpc_st = (struct cap_copy_rpc_st*)msg_st->st;
index 444027b..57909c3 100644 (file)
@@ -178,6 +178,18 @@ delete_remote_result__send(struct intermon_binding *b, struct intermon_msg_queue
     errval_t err;
     struct delete_remote_result_msg_st *msg_st = (struct delete_remote_result_msg_st*)e;
     err = intermon_capops_delete_remote_result__tx(b, NOP_CONT, msg_st->status, msg_st->st);
+
+    if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+        DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__);
+        struct intermon_state *inter_st = (struct intermon_state *)b->st;
+        // requeue send request at front and return
+        err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset,
+                                             (struct msg_queue_elem *)e);
+        GOTO_IF_ERR(err, handle_err);
+        return;
+    }
+
+handle_err:
     PANIC_IF_ERR(err, "failed to send delete_remote_result msg");
     free(msg_st);
 }
index aa5fe98..68a216a 100644 (file)
@@ -46,7 +46,20 @@ move_request_send_cont(struct intermon_binding *b, struct intermon_msg_queue_ele
 {
     errval_t err;
     struct move_request_msg_st *msg_st = (struct move_request_msg_st*)e;
-    err = intermon_capops_move_request__tx(b, NOP_CONT, msg_st->caprep, msg_st->relations, (lvaddr_t)msg_st->st);
+    err = intermon_capops_move_request__tx(b, NOP_CONT, msg_st->caprep,
+                                           msg_st->relations, (lvaddr_t)msg_st->st);
+
+    if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+        DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__);
+        struct intermon_state *inter_st = (struct intermon_state *)b->st;
+        // requeue send request at front and return
+        err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset,
+                                             (struct msg_queue_elem *)e);
+        GOTO_IF_ERR(err, handle_err);
+        return;
+    }
+
+handle_err:
     if (err_is_fail(err)) {
         struct cap_move_rpc_st *rpc_st = (struct cap_move_rpc_st*)msg_st->st;
         if (rpc_st->result_handler) {
@@ -106,6 +119,18 @@ move_result_send_cont(struct intermon_binding *b, struct intermon_msg_queue_elem
     errval_t err;
     struct move_result_msg_st *msg_st = (struct move_result_msg_st*)e;
     err = intermon_capops_move_result__tx(b, NOP_CONT, msg_st->status, msg_st->st);
+
+    if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+        DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__);
+        struct intermon_state *inter_st = (struct intermon_state *)b->st;
+        // requeue send request at front and return
+        err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset,
+                                             (struct msg_queue_elem *)e);
+        GOTO_IF_ERR(err, handle_err);
+        return;
+    }
+
+handle_err:
     if (err_is_fail(err)) {
         USER_PANIC_ERR(err, "failed to send move_result");
     }
index 49d006d..c53d363 100644 (file)
@@ -133,6 +133,15 @@ retrieve_owner__send(struct intermon_binding *b,
 
     capability_to_caprep(&st->rawcap, &caprep);
     err = intermon_capops_retrieve_request__tx(b, NOP_CONT, caprep, (lvaddr_t)st);
+
+    if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+        DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__);
+        struct intermon_state *inter_st = (struct intermon_state *)b->st;
+        // requeue send request at front and return
+        err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset,
+                                             (struct msg_queue_elem *)e);
+    }
+
     GOTO_IF_ERR(err, report_error);
 
     return;
@@ -226,6 +235,18 @@ retrieve_result__send(struct intermon_binding *b,
 
     err = intermon_capops_retrieve_result__tx(b, NOP_CONT, st->status,
                                               st->relations, st->st);
+
+    if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+        DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__);
+        struct intermon_state *inter_st = (struct intermon_state *)b->st;
+        // requeue send request at front and return
+        err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset,
+                                             (struct msg_queue_elem *)e);
+        GOTO_IF_ERR(err, handle_err);
+        return;
+    }
+
+handle_err:
     PANIC_IF_ERR(err, "sending retrieve result");
     free(st);
 }
index c6dcf23..ebf9780 100644 (file)
@@ -77,6 +77,18 @@ retype_result__send(struct intermon_binding *b, struct intermon_msg_queue_elem *
     struct requested_retype_st *req_st = (struct requested_retype_st*)e;
     err = intermon_capops_retype_response__tx(b, NOP_CONT, req_st->status,
                                               req_st->request_st);
+
+    if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+        DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__);
+        struct intermon_state *inter_st = (struct intermon_state *)b->st;
+        // requeue send request at front and return
+        err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset,
+                                             (struct msg_queue_elem *)e);
+        GOTO_IF_ERR(err, handle_err);
+        return;
+    }
+
+handle_err:
     PANIC_IF_ERR(err, "sending retype result message");
     free(req_st);
 }
@@ -224,6 +236,18 @@ retype_request__send(struct intermon_binding *b, struct intermon_msg_queue_elem
                                              req_st->check.count,
                                              (lvaddr_t)req_st);
 
+
+    if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+        DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__);
+        struct intermon_state *inter_st = (struct intermon_state *)b->st;
+        // requeue send request at front and return
+        err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset,
+                                             (struct msg_queue_elem *)e);
+        GOTO_IF_ERR(err, handle_err);
+        return;
+    }
+
+handle_err:
     if (err_is_fail(err)) {
         retype_result__rx(err, req_st);
     }
index f0e47ed..2bbb073 100644 (file)
@@ -287,6 +287,18 @@ revoke_ready__send(struct intermon_binding *b,
     errval_t err;
     struct revoke_slave_st *rvk_st = (struct revoke_slave_st*)e;
     err = intermon_capops_revoke_ready__tx(b, NOP_CONT, rvk_st->st);
+
+    if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+        DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__);
+        struct intermon_state *inter_st = (struct intermon_state *)b->st;
+        // requeue send request at front and return
+        err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset,
+                                             (struct msg_queue_elem *)e);
+        GOTO_IF_ERR(err, handle_err);
+        return;
+    }
+
+handle_err:
     PANIC_IF_ERR(err, "sending revoke_ready");
 }
 
@@ -398,6 +410,18 @@ revoke_done__send(struct intermon_binding *b,
     errval_t err;
     struct revoke_slave_st *rvk_st = (struct revoke_slave_st*)e;
     err = intermon_capops_revoke_done__tx(b, NOP_CONT, rvk_st->st);
+
+    if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+        DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__);
+        struct intermon_state *inter_st = (struct intermon_state *)b->st;
+        // requeue send request at front and return
+        err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset,
+                                             (struct msg_queue_elem *)e);
+        GOTO_IF_ERR(err, handle_err);
+        return;
+    }
+
+handle_err:
     PANIC_IF_ERR(err, "sending revoke_done");
     remove_slave_from_list(rvk_st);
     free(rvk_st);
index 3224951..43e488f 100644 (file)
@@ -674,7 +674,7 @@ static void assign_bus_numbers(struct pci_address parentaddr,
                 //ACPI_HANDLE child;
                 char* child = NULL;
                 errval_t error_code;
-                PCI_DEBUG("get irq table for (%hhu,%hhu,%hhu)\n", (*busnum) + 1,
+                PCI_DEBUG("get irq table for (%hhu,%hhu,%hhu)\n", (*busnum) + 2,
                           addr.device, addr.function);
                 struct acpi_rpc_client* cl = get_acpi_rpc_client();
                 // XXX: why do we have two different types for the same thing?
@@ -683,11 +683,12 @@ static void assign_bus_numbers(struct pci_address parentaddr,
                     .device = addr.device,
                     .function = addr.function,
                 };
-                cl->vtbl.read_irq_table(cl, handle, xaddr, (*busnum) + 1,
+                errval_t err = cl->vtbl.read_irq_table(cl, handle, xaddr, (*busnum) + 2,
                                         &error_code, &child);
-                if (err_is_fail(error_code)) {
+                if (err_is_ok(err) && error_code == ACPI_ERR_NO_CHILD_BRIDGE){
+                    PCI_DEBUG("No corresponding ACPI entry for bridge found\n");
+                } else if (err_is_fail(err) || err_is_fail(error_code)) {
                     DEBUG_ERR(error_code, "Reading IRQs failed");
-                    assert(!"Check ACPI code");
                 }
 
                 // Increase by 2 to leave room for SR-IOV
@@ -1072,6 +1073,9 @@ static void assign_bus_numbers(struct pci_address parentaddr,
                 }
             }
 
+            if(hdr_type.fmt == pci_hdr0_cardbus) {
+                printf("PCI: WARNING: Found cardbus bridge.\n");
+            }
             // is this a multi-function device?
             if (addr.function == 0 && !hdr_type.multi) {
                 break;
diff --git a/usr/tests/irqtest/Hakefile b/usr/tests/irqtest/Hakefile
new file mode 100644 (file)
index 0000000..cd42277
--- /dev/null
@@ -0,0 +1,18 @@
+--------------------------------------------------------------------------
+-- Copyright (c) 2007-2009, ETH Zurich.
+-- All rights reserved.
+--
+-- This file is distributed under the terms in the attached LICENSE file.
+-- If you do not find this file, copies can be found by writing to:
+-- ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for /usr/tests/irqtest
+--
+--------------------------------------------------------------------------
+
+[ build application { target = "irqtest",
+                      cFiles = [ "irqtest.c", "e1000n_helpers.c", "e1000n_hwinit.c" ],
+                      addLibraries = libDeps [ "pci" ],
+                      mackerelDevices = [ "e1000" ]
+                    }
+]
diff --git a/usr/tests/irqtest/e1000n.h b/usr/tests/irqtest/e1000n.h
new file mode 100644 (file)
index 0000000..608a29d
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2008, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef E1000_H__
+#define E1000_H__
+
+#include <barrelfish/barrelfish.h>
+#include <pci/pci.h>
+
+#include <dev/e1000_dev.h>      /* auto generated by Mackerel */
+#include "e1000n_desc.h"
+#include "irqtest_debug.h"
+
+#define DRIVER_STRING "e1000: "
+
+/**
+ * Default message print format.
+ */
+#define E1000_PRINT(fmt, ...)        printf(DRIVER_STRING fmt, ##__VA_ARGS__)
+#define E1000_PRINT_ERROR(fmt, ...)  fprintf(stderr, DRIVER_STRING fmt, ##__VA_ARGS__)
+
+#define E1000_USE_LEGACY_DESC 1
+/*
+ * Global constants
+ */
+#define MAC_ADDRESS_LEN     6
+
+
+/*
+ * e1000 (e1000) device family id's.
+ */
+#define E1000_DEVICE_82542               0x1000
+#define E1000_DEVICE_82543GC_FIBER       0x1001
+#define E1000_DEVICE_82543GC_COPPER      0x1004
+#define E1000_DEVICE_82544EI_COPPER      0x1008
+#define E1000_DEVICE_82544EI_FIBER       0x1009
+#define E1000_DEVICE_82544GC_COPPER      0x100C
+#define E1000_DEVICE_82544GC_LOM         0x100D
+#define E1000_DEVICE_82540EM             0x100E
+#define E1000_DEVICE_82540EM_LOM         0x1015
+#define E1000_DEVICE_82540EP_LOM         0x1016
+#define E1000_DEVICE_82540EP             0x1017
+#define E1000_DEVICE_82540EP_LP          0x101E
+#define E1000_DEVICE_82545EM_COPPER      0x100F
+#define E1000_DEVICE_82545EM_FIBER       0x1011
+#define E1000_DEVICE_82545GM_COPPER      0x1026
+#define E1000_DEVICE_82545GM_FIBER       0x1027
+#define E1000_DEVICE_82545GM_SERDES      0x1028
+#define E1000_DEVICE_82546EB_COPPER      0x1010
+#define E1000_DEVICE_82546EB_FIBER       0x1012
+#define E1000_DEVICE_82546EB_QUAD_COPPER 0x101D
+#define E1000_DEVICE_82541EI             0x1013
+#define E1000_DEVICE_82541EI_MOBILE      0x1018
+#define E1000_DEVICE_82541ER_LOM         0x1014
+#define E1000_DEVICE_82541ER             0x1078
+#define E1000_DEVICE_82547GI             0x1075
+#define E1000_DEVICE_82541GI             0x1076
+#define E1000_DEVICE_82541GI_MOBILE      0x1077
+#define E1000_DEVICE_82541GI_LF          0x107C
+#define E1000_DEVICE_82546GB_COPPER      0x1079
+#define E1000_DEVICE_82546GB_FIBER       0x107A
+#define E1000_DEVICE_82546GB_SERDES      0x107B
+#define E1000_DEVICE_82546GB_PCIE        0x108A
+#define E1000_DEVICE_82546GB_QUAD_COPPER 0x1099
+#define E1000_DEVICE_82563EB             0x1096
+#define E1000_DEVICE_82547EI             0x1019
+#define E1000_DEVICE_82547EI_MOBILE      0x101A
+#define E1000_DEVICE_82571EB_COPPER      0x105E
+#define E1000_DEVICE_82571EB_FIBER       0x105F
+#define E1000_DEVICE_82571EB_SERDES      0x1060
+#define E1000_DEVICE_82571EB_QUAD_COPPER 0x10A4
+#define E1000_DEVICE_82571EB_QUAD_FIBER  0x10A5
+#define E1000_DEVICE_82571EB_QUAD_COPPER_LOWPROFILE  0x10BC
+#define E1000_DEVICE_82571EB_SERDES_DUAL 0x10D9
+#define E1000_DEVICE_82571EB_SERDES_QUAD 0x10DA
+#define E1000_DEVICE_82572EI_COPPER      0x107D
+#define E1000_DEVICE_82572EI_FIBER       0x107E
+#define E1000_DEVICE_82572EI_SERDES      0x107F
+#define E1000_DEVICE_82572EI             0x10B9
+#define E1000_DEVICE_82573E              0x108B
+#define E1000_DEVICE_82573E_IAMT         0x108C
+#define E1000_DEVICE_82573L              0x109A
+#define E1000_DEVICE_82574L              0x10D3
+#define E1000_DEVICE_82575EB             0x10A7 // TODO(gz): This cards needs more work
+#define E1000_DEVICE_82576EG             0x10C9 // TODO(gz): This cards needs more work
+#define E1000_DEVICE_I210                0x1533
+#define E1000_DEVICE_I350_EEPROM_LESS    0x151F
+#define E1000_DEVICE_I350_COPPER         0x1521
+#define E1000_DEVICE_I350_FIBER          0x1522
+#define E1000_DEVICE_I350_BACKPANE       0x1523
+#define E1000_DEVICE_I350_SGMII          0x1524
+#define E1000_DEVICE_I350_DUMMY          0x10A6
+#define E1000_DEVICE_82546GB_QUAD_COPPER_KSP3 0x10B5
+
+
+/**
+ * Group definitions for cards that share specification and quirks.
+ *
+ * e1000_82542 should be split into:
+ *   e1000_82542_rev_2_1 and e1000_82542_rev_2_2.
+ * This can be figured out reading the PCI bus.
+ */
+typedef enum {
+    e1000_undefined = 0,
+    e1000_82542,        /* revision 2.1 and 2.2 merged */
+    e1000_82543,
+    e1000_82544,
+    e1000_82540,
+    e1000_82545,
+    e1000_82545_rev_3,
+    e1000_82546,
+    e1000_82546_rev_3,
+    e1000_82541,
+    e1000_82541_rev_2,
+    e1000_82547,
+    e1000_82547_rev_2,
+    e1000_82563,
+    e1000_82571,
+    e1000_82572,
+    e1000_82573,
+    e1000_82574,
+    e1000_82575,
+    e1000_82576,
+    e1000_I210,
+    e1000_I350,
+    e1000_num_macs
+} e1000_mac_type_t;
+
+
+/**
+ * Hardware supported buffer sizes.
+ */
+typedef enum {
+    bsize_256 = 256,
+    bsize_512 = 512,
+    bsize_1024 = 1024,
+    bsize_2048 = 2048,
+    bsize_4096 = 4096,
+    bsize_8192 = 8192,
+    bsize_16384 = 16384
+} e1000_rx_bsize_t;
+
+/**
+ * Media types.
+ */
+typedef enum {
+    e1000_media_type_undefined,
+    e1000_media_type_fiber,
+    e1000_media_type_copper,
+    e1000_media_type_serdes,
+    e1000_num_media_types
+} e1000_media_type_t;
+
+
+
+/**
+ * Internal device info.
+ */
+typedef struct {
+    e1000_t *device;
+    uint32_t device_id;
+    e1000_media_type_t media_type;
+    e1000_mac_type_t mac_type;
+    e1000_rx_bsize_t rx_bsize;
+    bool tbi_combaility;
+} e1000_device_t ;
+
+
+e1000_mac_type_t e1000_get_mac_type(uint32_t vendor, uint32_t device_id);
+bool e1000_supported_device(uint32_t vendor, uint32_t device_id);
+bool e1000_link_up_led_status(e1000_device_t *dev);
+bool e1000_check_link_up(e1000_device_t *dev);
+bool e1000_auto_negotiate_link(e1000_device_t *dev);
+void *alloc_map_frame(vregion_flags_t attr, size_t size, struct capref *retcap);
+void e1000_hwinit(e1000_device_t *device, struct device_mem *bar_info,
+                  int nr_allocated_bars,
+                  volatile struct tx_desc **transmit_ring,
+                  volatile union rx_desc **receive_ring,
+                  int receive_buffers, int transmit_buffers,
+                  uint8_t *macaddr,
+                  bool user_macaddr, bool use_interrupt);
+
+
+/*****************************************************************
+ * On the i82541xx GPI_SP2 and GPI_SP3 are merged into one register
+ * value of bits.
+ *
+ ****************************************************************/
+static inline uint8_t i82541xx_get_icr_gpi_sdp(e1000_t *dev)
+{
+    e1000_intreg_t intreg = e1000_icr_rawrd(dev);
+    uint8_t sdp2 = e1000_intreg_gpi_sdp2_extract(intreg);
+    uint8_t sdp3 = e1000_intreg_gpi_sdp3_extract(intreg);
+    uint8_t sdp = sdp2 | (sdp3 << 1);
+
+    return sdp;
+}
+
+
+/*****************************************************************
+ * Barrelfish has no delay. We do it like this instead.
+ ****************************************************************/
+
+#include <barrelfish/sys_debug.h>
+
+#if 0
+/* apparently this does not work... getting usertrap #13 */
+extern cycles_t tscperms;
+
+static inline void usec_delay(unsigned int ms)
+{
+    if (tscperms == 0) {
+        errval_t err = sys_debug_get_tsc_per_ms(&tscperms);
+        assert(err_is_ok(err));
+    }
+    cycles_t end = (cycles_t)ms * tscperms + rdtsc();
+    while(rdtsc() < end) {
+        thread_yield();
+    }
+
+}
+#else
+static inline void usec_delay(unsigned int count)
+{
+    while(count--) {
+        __asm__ __volatile__("inb $0x80, %b0" :: "a"(0));
+    }
+}
+#endif
+
+#endif
diff --git a/usr/tests/irqtest/e1000n_desc.h b/usr/tests/irqtest/e1000n_desc.h
new file mode 100644 (file)
index 0000000..50a90e6
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2008, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef __E1000_DESC_H__
+#define __E1000_DESC_H__
+
+typedef union {
+    uint16_t   vlan;
+    struct {
+        uint16_t vlan :12;
+        uint16_t cfi  :1;
+        uint16_t pri  :3;
+    } __attribute__((packed)) bits;
+} __attribute__((packed)) vlan_tag_t;
+
+
+union rx_desc {
+    uint64_t raw[2] __attribute__((packed));
+    struct {
+        uint64_t buffer_address;
+        struct {
+            uint16_t   length;
+            uint16_t   checksum;        /* reserved on: 82544GC/EI */
+            struct {
+                unsigned int   dd      :1;
+                unsigned int   eop     :1;
+                unsigned int   ixsm    :1;
+                unsigned int   vp      :1;
+                unsigned int   udpcs   :1;  /* reserved on: 8254x */
+                unsigned int   tcpcs   :1;
+                unsigned int   ipcs    :1;
+                unsigned int   pif     :1;
+            } __attribute__ ((packed)) status;
+
+            union {
+                uint8_t errors;
+                struct {
+                    uint8_t ce   :1;
+                    uint8_t seq  :1;        /* reserved on: 82541xx, 82547GI/EI, and 82540EP/EM only. */
+                    uint8_t res0 :1;        /* reserved on: 8254x */
+                    uint8_t cxe  :1;        /* 82544GC/EI only */
+                    uint8_t tcpe :1;
+                    uint8_t ipe  :1;
+                    uint8_t rxe  :1;
+                } __attribute__ ((packed)) bits;
+            } __attribute__ ((packed)) errors;
+
+            vlan_tag_t vlan;
+
+        } __attribute__ ((packed)) info;
+
+    } __attribute__ ((packed)) rx_read_format;
+
+} __attribute__ ((packed));
+
+
+struct tx_desc {
+    uint64_t buffer_address;
+    union {
+        uint64_t raw;
+        struct {
+            uint16_t data_len;
+            uint8_t cso;
+            union {
+                uint8_t raw;
+                struct {
+                    uint8_t eop  :1;
+                    uint8_t ifcs :1;
+                    uint8_t ic   :1;
+                    uint8_t rs   :1;
+                    uint8_t rsv  :1;
+                    uint8_t dext :1;
+                    uint8_t vle  :1;
+                    uint8_t ide  :1;
+                } __attribute__ ((packed)) d;
+            } __attribute__ ((packed)) cmd;
+            union {
+                uint8_t raw;
+                struct {
+                    uint8_t dd  :1;
+                    uint8_t ec  :1;
+                    uint8_t lc  :1;
+                    uint8_t res :5;
+                } __attribute__ ((packed)) d;
+            } __attribute__ ((packed)) stat_rsv;
+            uint8_t  css;
+            uint16_t special;
+        } __attribute__ ((packed)) legacy;
+
+        struct {
+            uint64_t data_len :20;
+            uint64_t dtype    :4;
+            union {
+                uint8_t raw;
+                struct {
+                    uint8_t eop  :1;
+                    uint8_t ifcs :1;
+                    uint8_t tse  :1;
+                    uint8_t rs   :1;
+                    uint8_t rsv  :1;
+                    uint8_t dext :1;
+                    uint8_t vle  :1;
+                    uint8_t ide  :1;
+                } __attribute__ ((packed)) d;
+            } __attribute__ ((packed)) dcmd;
+
+            union {
+                uint8_t raw;
+                struct {
+                    uint8_t dd  :1;
+                    uint8_t res :7;
+                } __attribute__ ((packed)) d;
+            } __attribute__ ((packed)) stat_rsv;
+
+            union {
+                uint8_t  raw;
+                struct {
+                    uint8_t ixsm : 1;
+                    uint8_t txsm : 1;
+                    uint8_t  res : 6;
+                } __attribute__ ((packed)) d;
+            } __attribute__ ((packed)) popts;
+
+            vlan_tag_t vlan;
+
+        } __attribute__ ((packed)) extended_tcpip;
+    } __attribute__ ((packed)) ctrl;
+} __attribute__ ((packed));
+
+/*
+ * TCP/IP Context Descriptor Layout
+ *
+ * Provides access to enhanced checksum offload facility
+ * available in the Ethernet controllerfor TCP and UDP packets.
+ */
+union context_desc {
+    uint64_t raw;
+    struct {
+        uint8_t ipcss;
+        uint8_t ipcso;
+        uint16_t ipcse;
+        uint8_t tucss;
+        uint8_t tucso;
+        uint16_t tucse;
+        struct {
+            uint32_t paylen :20;
+            uint32_t dtype  :4;
+        } __attribute__ ((packed)) pd;
+
+        union {
+            uint8_t raw;
+            struct {
+                uint8_t tcp  :1;
+                uint8_t ip   :1;
+                uint8_t tse  :1;
+                uint8_t rs   :1;
+                uint8_t rsv  :1;
+                uint8_t dext :1;
+                uint8_t snap :1;
+                uint8_t ide  :1;
+            } __attribute__ ((packed)) d;
+        } __attribute__ ((packed)) tucmd;
+
+        union {
+            uint8_t raw;
+            struct {
+                uint8_t dd  :1;
+                uint8_t res :7;
+            } __attribute__ ((packed)) d;
+        } __attribute__ ((packed)) stat_rsv;
+
+        uint8_t hdrlen;
+        uint16_t mss;
+
+    } __attribute__ ((packed)) d;
+} __attribute__ ((packed));
+
+
+#endif
diff --git a/usr/tests/irqtest/e1000n_helpers.c b/usr/tests/irqtest/e1000n_helpers.c
new file mode 100644 (file)
index 0000000..ffde359
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2008, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+/*
+ * e1000_helpers.c
+ *
+ *  Created on: Feb 14, 2013
+ *      Author: mao
+ */
+#include "e1000n.h"
+#include "irqtest_debug.h"
+
+/*****************************************************************
+ *
+ *
+ ****************************************************************/
+e1000_mac_type_t e1000_get_mac_type(uint32_t vendor, uint32_t device_id)
+{
+    if (vendor == PCI_VENDOR_INTEL) {
+
+        switch (device_id) {
+        case E1000_DEVICE_82542:
+            return e1000_82542;
+        case E1000_DEVICE_82543GC_FIBER:
+        case E1000_DEVICE_82543GC_COPPER:
+            return e1000_82543;
+        case E1000_DEVICE_82544EI_COPPER:
+        case E1000_DEVICE_82544EI_FIBER:
+        case E1000_DEVICE_82544GC_COPPER:
+        case E1000_DEVICE_82544GC_LOM:
+            return e1000_82544;
+        case E1000_DEVICE_82540EM:
+        case E1000_DEVICE_82540EM_LOM:
+        case E1000_DEVICE_82540EP:
+        case E1000_DEVICE_82540EP_LOM:
+        case E1000_DEVICE_82540EP_LP:
+            return e1000_82540;
+        case E1000_DEVICE_82545EM_COPPER:
+        case E1000_DEVICE_82545EM_FIBER:
+            return e1000_82545;
+        case E1000_DEVICE_82545GM_COPPER:
+        case E1000_DEVICE_82545GM_FIBER:
+        case E1000_DEVICE_82545GM_SERDES:
+            return e1000_82545_rev_3;
+        case E1000_DEVICE_82546EB_COPPER:
+        case E1000_DEVICE_82546EB_FIBER:
+        case E1000_DEVICE_82546EB_QUAD_COPPER:
+            return e1000_82546;
+        case E1000_DEVICE_82546GB_COPPER:
+        case E1000_DEVICE_82546GB_FIBER:
+        case E1000_DEVICE_82546GB_SERDES:
+        case E1000_DEVICE_82546GB_PCIE:
+        case E1000_DEVICE_82546GB_QUAD_COPPER:
+        case E1000_DEVICE_82546GB_QUAD_COPPER_KSP3:
+            return e1000_82546_rev_3;
+        case E1000_DEVICE_82541EI:
+        case E1000_DEVICE_82541EI_MOBILE:
+        case E1000_DEVICE_82541ER_LOM:
+            return e1000_82541;
+        case E1000_DEVICE_82541ER:
+        case E1000_DEVICE_82541GI:
+        case E1000_DEVICE_82541GI_LF:
+        case E1000_DEVICE_82541GI_MOBILE:
+            return e1000_82541_rev_2;
+        case E1000_DEVICE_82547EI:
+        case E1000_DEVICE_82547EI_MOBILE:
+            return e1000_82547;
+        case E1000_DEVICE_82547GI:
+            return e1000_82547_rev_2;
+        case E1000_DEVICE_82563EB:
+            return e1000_82563;
+        case E1000_DEVICE_82571EB_COPPER:
+        case E1000_DEVICE_82571EB_FIBER:
+        case E1000_DEVICE_82571EB_SERDES:
+        case E1000_DEVICE_82571EB_SERDES_DUAL:
+        case E1000_DEVICE_82571EB_SERDES_QUAD:
+        case E1000_DEVICE_82571EB_QUAD_COPPER:
+        case E1000_DEVICE_82571EB_QUAD_FIBER:
+        case E1000_DEVICE_82571EB_QUAD_COPPER_LOWPROFILE:
+            return e1000_82571;
+        case E1000_DEVICE_82572EI_COPPER:
+        case E1000_DEVICE_82572EI_FIBER:
+        case E1000_DEVICE_82572EI_SERDES:
+        case E1000_DEVICE_82572EI:
+            return e1000_82572;
+        case E1000_DEVICE_82573E:
+        case E1000_DEVICE_82573E_IAMT:
+        case E1000_DEVICE_82573L:
+            return e1000_82573;
+        case E1000_DEVICE_82574L:
+            return e1000_82574;
+        case E1000_DEVICE_82575EB:
+            return e1000_82575;
+        case E1000_DEVICE_82576EG:
+            return e1000_82576;
+        case E1000_DEVICE_I210:
+            return e1000_I210;
+        case E1000_DEVICE_I350_EEPROM_LESS:
+        case E1000_DEVICE_I350_COPPER:
+        case E1000_DEVICE_I350_FIBER:
+        case E1000_DEVICE_I350_BACKPANE:
+        case E1000_DEVICE_I350_SGMII:
+        case E1000_DEVICE_I350_DUMMY:
+            return e1000_I350;
+        default:
+            IRQ_DEBUG("Unsupported device: vendor: 0x%x,  device id: 0x%x\n", PCI_VENDOR_INTEL, device_id);
+            return e1000_undefined;
+        }
+    }
+
+    return e1000_undefined;
+}
+
+
+/*****************************************************************
+ * allocate a single frame, mapping it into our vspace with given
+ * attributes
+ ****************************************************************/
+void *alloc_map_frame(vregion_flags_t attr, size_t size, struct capref *retcap)
+{
+    struct capref frame;
+    errval_t err;
+    void *va;
+
+    err = frame_alloc(&frame, size, NULL);
+    if (err_is_fail(err)) {
+        IRQ_DEBUG("ERROR: frame_alloc failed.\n");
+        return NULL;
+    }
+
+    err = vspace_map_one_frame_attr(&va, size, frame, attr, NULL, NULL);
+
+    if (err_is_fail(err)) {
+        IRQ_DEBUG("Error: vspace_map_one_frame failed\n");
+        return NULL;
+    }
+
+    if (retcap != NULL) {
+        *retcap = frame;
+    }
+
+    return va;
+}
+
+cycles_t tscperms;
+
+
+
+
diff --git a/usr/tests/irqtest/e1000n_hwinit.c b/usr/tests/irqtest/e1000n_hwinit.c
new file mode 100644 (file)
index 0000000..1670242
--- /dev/null
@@ -0,0 +1,1006 @@
+/*
+ * Copyright (c) 2008, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+/*
+ * e1000_hwinit.c
+ *
+ *  Created on: Feb 12, 2013
+ *      Author: mao
+ *
+ * Much referencing has been done against iPXE - Open Source Boot Firmware
+ * and the Linux kernel.
+ */
+#include "e1000n.h"
+#include "e1000n_hwinit.h"
+
+
+/*****************************************************************
+ * PHY
+ *
+ ****************************************************************/
+/*****************************************************************
+ * Writes a value to a PHY register
+ *
+ *****************************************************************/
+/* TODO */
+
+/***************************************************************************
+ * Is EEPROM NVM or FLASH.
+ *
+ * Returns true if EEPROM is of NVM type, else false.
+ *
+ ****************************************************************************/
+static bool e1000_is_onboard_nvm_eeprom(e1000_device_t *dev)
+{
+    if (dev->mac_type == e1000_82573) {
+        e1000_eecd_t eecd = e1000_eecd_rd(dev->device);
+        /* Isolate bits 15 & 16 */
+        uint8_t eecd_flash = ((eecd >> 15) & 0x03);
+
+        /* If both bits are set, device is Flash type */
+        if (eecd_flash == 0x03) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+/*****************************************************************
+ * Read e1000 EEPROM.
+ *
+ * TODO: Fix semaphore support and eeprom release on devices that
+ *       need this.
+ *
+ * dev     - device to read eeprom from.
+ * offset  - eeprom offset.
+ * data    - returns data read.
+ * Returns:  0 on success, 1 on timeout and 2 if no eeprom.
+ ****************************************************************/
+static errval_t e1000_read_eeprom(e1000_device_t *dev, uint64_t offset,
+                                  uint16_t *data)
+{
+    int timeout = 1000;
+
+    /* Make shore there are no direct access requests on
+     * devices that support this.
+     */
+    if (dev->mac_type != e1000_82544) {
+        e1000_eecd_ee_req_wrf(dev->device, 1);
+    }
+
+    if (dev->mac_type != e1000_I210) {
+        while (!e1000_eecd_ee_gnt_rdf(dev->device)) {
+            usec_delay(1000);
+        }
+    }
+
+    /* EEPROM present */
+    // TODO(gz): Why does e1000 82574 have ee_pres == 0?
+    if (e1000_eecd_ee_pres_rdf(dev->device) ||
+            dev->mac_type == e1000_82574) {
+        e1000_eerd_ms_t eerd_ms = 0;
+        e1000_eerd_nm_t eerd_nm = 0;
+
+        switch (dev->mac_type) {
+        case e1000_82571:
+        case e1000_82572:
+        case e1000_82573:
+        case e1000_82574:
+        case e1000_82575:
+               case e1000_I210:
+               case e1000_I350:
+            /* These devices have SPI or Microwire EEPROMs */
+            eerd_ms = e1000_eerd_ms_start_insert(eerd_ms, 1);
+            eerd_ms = e1000_eerd_ms_addr_insert(eerd_ms, offset);
+            e1000_eerd_ms_wr(dev->device, eerd_ms);
+
+            while (e1000_eerd_ms_done_rdf(dev->device) == 0 && 0 < timeout--) {
+                usec_delay(1000);
+            }
+
+            *data = e1000_eerd_ms_data_rdf(dev->device);
+            break;
+        default:
+            /* These devices have standard EEPROMs */
+            eerd_nm = e1000_eerd_nm_start_insert(eerd_nm, 1);
+            eerd_nm = e1000_eerd_nm_addr_insert(eerd_nm, offset);
+            e1000_eerd_nm_wr(dev->device, eerd_nm);
+
+            while (e1000_eerd_ms_done_rdf(dev->device) == 0 && 0 < timeout--) {
+                usec_delay(1000);
+            }
+
+            *data = e1000_eerd_nm_data_rdf(dev->device);
+            break;
+        }
+    } else {
+        IRQ_DEBUG("No EEPROM pressent.\n");
+        e1000_eecd_ee_req_wrf(dev->device, 0);
+        return -1;
+    }
+
+    if (timeout) {
+        e1000_eecd_ee_req_wrf(dev->device, 0);
+        return 0; /* Success */
+    }
+
+    IRQ_DEBUG("EEPROM read timed out\n");
+
+    e1000_eecd_ee_req_wrf(dev->device, 0);
+    return 1;
+}
+
+/*****************************************************************
+ * Check for EEPROM Auto Read bit done.
+ *
+ ****************************************************************/
+static errval_t e1000_get_auto_rd_done(e1000_device_t *dev)
+{
+    uint16_t data;
+    errval_t err;
+
+    err = e1000_read_eeprom(dev, 0, &data);
+
+    /* PHY configuration from NVM just starts after EECD_AUTO_RD sets to high.
+     * Need to wait for PHY configuration completion before accessing NVM
+     * and PHY. */
+    if (dev->mac_type == e1000_82573) {
+        usec_delay(2500);
+    }
+
+    return err;
+}
+
+/******************************************************************************
+ * Reads the adapter's MAC address from the EEPROM and inverts the LSB for the
+ * second function of dual function devices
+ *
+ *****************************************************************************/
+static errval_t e1000_read_mac_addr(e1000_device_t *dev, uint8_t *mac_addr)
+{
+    uint16_t offset;
+    uint16_t eeprom_data, i;
+    e1000_status_t status;
+
+    for (i = 0; i < MAC_ADDRESS_LEN; i += 2) {
+        offset = i >> 1;
+        if (e1000_read_eeprom(dev, offset, &eeprom_data) != 0) {
+            return 1;
+        }
+        mac_addr[i] = (uint8_t) (eeprom_data & 0x00FF);
+        mac_addr[i + 1] = (uint8_t) (eeprom_data >> 8);
+    }
+
+    switch (dev->mac_type) {
+    default:
+        break;
+    case e1000_82546:
+    case e1000_82546_rev_3:
+    case e1000_82571:
+        /* test LAN ID to see if we need to modify the MAC from EEPROM */
+        status = e1000_status_rd(dev->device);
+        if (e1000_status_func_id_extract(status) == e1000_lan_b) {
+            mac_addr[5] ^= e1000_lan_b_mask;
+        }
+        break;
+    }
+
+    return 0;
+}
+
+/*****************************************************************
+ * Reset the device and disable interrupts.
+ *
+ ****************************************************************/
+static int e1000_reset(e1000_device_t *dev)
+{
+    errval_t err = 0;
+    int timeout;
+
+    /* disable interrupts */
+    if (dev->mac_type == e1000_I350) {
+        e1000_eimc_wr(dev->device, 0xffffffff);
+    } else {
+        e1000_imc_rawwr(dev->device, 0xffffffff);
+    }
+
+    /* disable receive and transmit */
+    e1000_rctl_rawwr(dev->device, 0);
+    e1000_tctl_rawwr(dev->device, 0);
+
+    /* Delay to allow outstanding PCI transactions to complete before
+     * reseting the device */
+    usec_delay(1000);
+
+    /* Exit from GIO management mode */
+    if (dev->mac_type == e1000_82571 || dev->mac_type == e1000_82563
+            || dev->mac_type == e1000_82573) {
+        IRQ_DEBUG("Disabling GIO management.\n");
+
+        e1000_ctrl_gio_md_wrf(dev->device, 1);
+
+        timeout = 1000;
+        do {
+            usec_delay(10);
+        } while (e1000_ctrl_gio_md_rdf(dev->device) && 0 < timeout--);
+
+        if (timeout <= 0) {
+            IRQ_DEBUG("Error: Failed to disable GIO management.\n");
+            // return -1;
+        }
+    }
+
+    if (dev->mac_type == e1000_I350) {
+        IRQ_DEBUG("Disabling GIO management.\n");
+        e1000_ctrl_gio_md_wrf(dev->device, 1);
+        timeout = 1000;
+        do {
+            usec_delay(10);
+        } while (e1000_status_I350_gio_mes_rdf(dev->device) && 0 < timeout--);
+
+        if (timeout <= 0) {
+            IRQ_DEBUG("Error: Failed to disable GIO management.\n");
+        }
+    }
+
+    /* Must reset PHY before reseting the MAC */
+    if (dev->mac_type == e1000_82541 || dev->mac_type == e1000_82547) {
+        e1000_ctrl_phy_rst_wrf(dev->device, 1);
+    }
+
+    /* Must acquire MDIO ownership before MAC reset
+     * Ownership defaults to firmware after a reset */
+    if (dev->mac_type == e1000_82573) {
+        timeout = 1000;
+        do {
+            e1000_extcnf_ctrl_mdio_swown_wrf(dev->device, 1);
+            usec_delay(200);
+        } while (e1000_extcnf_ctrl_mdio_swown_rdf(dev->device) == 0
+                 && 0 < timeout--);
+    }
+
+    IRQ_DEBUG("Resetting device.\n");
+
+    switch (dev->mac_type) {
+    case e1000_82545_rev_3:
+    case e1000_82546_rev_3:
+        /* Reset is performed on a shadow of the control register
+         * Where is this mentioned?
+         */
+        e1000_ctrldup_rst_wrf(dev->device, 1);
+        break;
+    case e1000_82540:
+    case e1000_82541:
+    case e1000_82541_rev_2:
+    case e1000_82544:
+    case e1000_82545:
+    case e1000_82546:
+        /* These controllers can't ack the 64-bit write when issuing the
+         * reset, so use IO-mapping as a workaround to issue the reset
+         * We don't support IO-mapped writing yet */
+    case e1000_I350:
+        e1000_ctrl_rst_wrf(dev->device, 1);
+        usec_delay(3000);
+        timeout = 1000;
+        timeout = 1000;
+        do {
+            usec_delay(10);
+        } while (e1000_ctrl_rst_rdf(dev->device) != 0 && 0 < timeout--);
+
+        if (timeout <= 0 || !e1000_status_pf_rst_done_rdf(dev->device)) {
+            IRQ_DEBUG("Error: Failed to reset device.\n");
+        }
+        break;
+    default:
+        e1000_ctrl_rst_wrf(dev->device, 1);
+
+        /* Wait for reset to clear */
+        timeout = 1000;
+        do {
+            usec_delay(10);
+        } while (e1000_ctrl_rst_rdf(dev->device) != 0 && 0 < timeout--);
+
+        if (timeout <= 0) {
+            IRQ_DEBUG("Error: Failed to reset device.\n");
+        }
+        break;
+    }
+
+
+    /* After MAC reset, force reload of EEPROM to restore power-on settings to
+     * device.  Later controllers reload the EEPROM automatically, so just wait
+     * for reload to complete.
+     */
+    switch (dev->mac_type) {
+    case e1000_82542:
+    case e1000_82543:
+    case e1000_82544:
+        e1000_ctrlext_ee_rst_wrf(dev->device, 1);
+        /* Wait for EEPROM reload */
+        usec_delay(2000);
+        break;
+    case e1000_82541:
+    case e1000_82541_rev_2:
+    case e1000_82547:
+    case e1000_82547_rev_2:
+        /* Wait for EEPROM reload */
+        usec_delay(20000);
+        break;
+    case e1000_82573:
+        if (e1000_is_onboard_nvm_eeprom(dev) == false) {
+            usec_delay(100);
+            e1000_ctrlext_ee_rst_wrf(dev->device, 1);
+        }
+        err = e1000_get_auto_rd_done(dev);
+        break;
+    case e1000_I350:
+        timeout = 1000;
+        while(!e1000_eec_auto_rd_rdf(dev->device) && timeout--) {
+            usec_delay(100);
+        }
+        if (timeout <= 0) {
+            IRQ_DEBUG("Error: Autoloading of the EEPROM failed.\n");
+        }
+        usec_delay(3000);
+        break;
+    default:
+        err = e1000_get_auto_rd_done(dev);
+
+        break;
+    }
+
+    if (err) {
+        IRQ_DEBUG("Auto read by HW from EEPROM did not complete.\n");
+    }
+
+    /* Disable HW ARPs on ASF enabled adapters */
+    if (dev->mac_type >= e1000_82540 && dev->mac_type <= e1000_82547_rev_2) {
+        e1000_manc_arp_req_en_wrf(dev->device, 0);
+    }
+
+    if (dev->mac_type == e1000_82541 || dev->mac_type == e1000_82547) {
+        /* Configure activity LED after PHY reset */
+        e1000_ledctl_t ledctl;
+
+        // TODO:
+//      e1000_phy_init_script(dev);
+
+        /* I guess this is not realy needed to setup card LEDs */
+        ledctl = e1000_ledctl_rd(dev->device);
+        ledctl &= IGP_ACTIVITY_LED_MASK;
+        ledctl = e1000_ledctl_led0_mode_insert(ledctl, 0x2);
+        ledctl = e1000_ledctl_led3_mode_insert(ledctl, 0x3);
+        e1000_ledctl_wr(dev->device, ledctl);
+    }
+
+    /* disable interrupts */
+    if (dev->mac_type == e1000_I350) {
+        e1000_eimc_wr(dev->device, 0xffffffff);
+    } else {
+        e1000_imc_rawwr(dev->device, 0xffffffff);
+    }
+
+    /* clear any pending interrupts */
+    e1000_icr_rd(dev->device);
+
+    debug_printf("Reset done..\n");
+
+    return 0;
+}
+
+/*****************************************************************
+ * Get media type.
+ *
+ ****************************************************************/
+static void e1000_set_media_type(e1000_device_t *dev)
+{
+    e1000_status_t status;
+
+    if (dev->mac_type != e1000_82543) {
+        dev->tbi_combaility = false;
+    }
+
+    switch (dev->device_id) {
+    case E1000_DEVICE_82545GM_SERDES:
+    case E1000_DEVICE_82546GB_SERDES:
+    case E1000_DEVICE_82571EB_SERDES:
+    case E1000_DEVICE_82571EB_SERDES_DUAL:
+    case E1000_DEVICE_82571EB_SERDES_QUAD:
+    case E1000_DEVICE_82572EI_SERDES:
+        dev->media_type = e1000_media_type_serdes;
+        break;
+    default:
+        switch (dev->mac_type) {
+            /*
+             * According to: 1.3.7 Additional Ethernet Controller Features
+             */
+        case e1000_82546:
+        case e1000_82545:
+            dev->media_type = e1000_media_type_serdes;
+            break;
+        case e1000_82542:
+            dev->media_type = e1000_media_type_fiber;
+            break;
+        case e1000_82573:
+            /* The STATUS.tbimode bit is reserved or reused for the this
+             * device.
+             */
+            dev->media_type = e1000_media_type_copper;
+            break;
+        default:
+            status = e1000_status_rd(dev->device);
+            if (e1000_status_tbimode_extract(status)) {
+                dev->media_type = e1000_media_type_fiber;
+                dev->tbi_combaility = false;
+            } else {
+                dev->media_type = e1000_media_type_copper;
+            }
+            break;
+        }
+        break;
+    }
+}
+
+/*****************************************************************
+ * Check link connection status.
+ *
+ ****************************************************************/
+bool e1000_check_link_up(e1000_device_t *dev)
+{
+    e1000_status_t status = e1000_status_rd(dev->device);
+
+    if (e1000_status_lu_extract(status)) {
+        return true;
+    }
+
+    return false;
+}
+
+/*****************************************************************
+ * Setup link auto-negotiation.
+ *
+ ****************************************************************/
+bool e1000_auto_negotiate_link(e1000_device_t *dev)
+{
+    bool link_up = false;
+
+    e1000_ctrlext_t ctrlext = e1000_ctrlext_rd(dev->device);
+    if (e1000_ctrlext_link_mode_extract(ctrlext) == e1000_serdes) {
+        IRQ_DEBUG("Auto-negotiation: serdes mode");
+        int timeout = 4000;
+        e1000_txcw_ane_wrf(dev->device, 1);
+        e1000_ctrl_lrst_wrf(dev->device, 1);
+
+        while (e1000_rxcw_anc_rdf(dev->device) == 0 && 0 < timeout--) {
+            usec_delay(10);
+        }
+
+        if (timeout > 0) {
+            link_up = true;
+        }
+
+        if (!link_up) {
+            e1000_txcw_ane_wrf(dev->device, 0);
+        }
+    } else {
+        int timeout = 4000;
+
+        // XXX: find out which cards really need this?
+        if (dev->mac_type < e1000_82571) {
+            e1000_ctrl_asde_wrf(dev->device, 1);
+        }
+
+        if (dev->mac_type == e1000_I350) {
+            e1000_ctrl_slu_wrf(dev->device, 1);
+            e1000_ctrl_frcspd_wrf(dev->device, 0);
+            e1000_ctrl_frcdplx_wrf(dev->device, 0);
+        }
+
+        while (e1000_check_link_up(dev) == false && 0 < timeout--) {
+            usec_delay(10);
+        }
+
+        link_up = e1000_check_link_up(dev);
+    }
+
+    IRQ_DEBUG("Auto-negotiate link status: %s\n", e1000_check_link_up(dev) ? "link-up" : "link-down");
+    return link_up;
+}
+
+/*****************************************************************
+ * Set RX buffer size and enable receive unit.
+ *
+ ****************************************************************/
+static void e1000_set_rxbsize(e1000_device_t *dev, e1000_rx_bsize_t rx_bsize)
+{
+    uint8_t bsize;
+    uint8_t bsex;
+    e1000_rctl_t rctl;
+
+    switch (rx_bsize) {
+    case bsize_16384:
+        bsize = 0x1;
+        bsex = 1;
+        break;
+    case bsize_8192:
+        bsize = 0x2;
+        bsex = 1;
+        break;
+    case bsize_4096:
+        bsize = 0x3;
+        bsex = 1;
+        break;
+    case bsize_2048:
+        bsize = 0x0;
+        bsex = 0;
+        break;
+    case bsize_1024:
+        bsize = 0x1;
+        bsex = 0;
+        break;
+    case bsize_512:
+        bsize = 0x2;
+        bsex = 0;
+        break;
+    case bsize_256:
+    default:
+        bsize = 0x3;
+        bsex = 0;
+        break;
+    }
+
+    rctl = e1000_rctl_rd(dev->device);
+    rctl = e1000_rctl_bsize_insert(rctl, bsize);
+    rctl = e1000_rctl_bsex_insert(rctl, bsex);
+    rctl = e1000_rctl_bam_insert(rctl, 1);
+    e1000_rctl_wr(dev->device, rctl);
+
+    e1000_rctl_en_wrf(dev->device, 1);
+}
+
+/*****************************************************************
+ * Set serial interface mode.
+ *
+ ****************************************************************/
+static void e1000_set_serial_interface_mode(e1000_device_t *dev)
+{
+    e1000_ctrlext_t ctrlext = e1000_ctrlext_rd(dev->device);
+
+    if (dev->mac_type == e1000_82544) {
+        assert(!"XXX: How do we set these ones up?");
+        return;
+    }
+
+    if (dev->mac_type == e1000_82573) {
+        ctrlext = e1000_ctrlext_link_mode_insert(ctrlext, e1000_l82573);
+    }
+    else if (dev->media_type == e1000_media_type_serdes) {
+        ctrlext = e1000_ctrlext_link_mode_insert(ctrlext, e1000_serdes);
+    }
+    else {
+        ctrlext = e1000_ctrlext_link_mode_insert(ctrlext, e1000_glci);
+    }
+    /* write serial interface mode */
+    e1000_ctrlext_wr(dev->device, ctrlext);
+}
+
+/*****************************************************************
+ * Set Transmit Inter Packet Gap (TIPG)
+ *
+ ****************************************************************/
+static void e1000_set_tipg(e1000_device_t *dev)
+{
+    e1000_tipg_t tipg = 0;
+
+    if ((dev->mac_type <= e1000_82547_rev_2)
+            && (dev->media_type == e1000_media_type_fiber
+                || dev->media_type == e1000_media_type_serdes)) {
+        tipg = e1000_tipg_ipgt_insert(tipg, DEFAULT_825XX_TIPG_IPGT_FIBER);
+    } else {
+        tipg = e1000_tipg_ipgt_insert(tipg, DEFAULT_825XX_TIPG_IPGT_COPPER);
+    }
+
+    switch (dev->mac_type) {
+    case e1000_82542:
+        tipg = e1000_tipg_ipgt_insert(tipg, DEFAULT_825XX_TIPG_IPGT);
+        tipg = e1000_tipg_ipgr1_insert(tipg, DEFAULT_82542_TIPG_IPGR1);
+        tipg = e1000_tipg_ipgr2_insert(tipg, DEFAULT_82542_TIPG_IPGR2);
+        break;
+    case e1000_82575:
+    case e1000_82576:
+    case e1000_I210:
+    case e1000_I350:
+        tipg = e1000_tipg_ipgr1_insert(tipg, DEFAULT_82575_TIPG_IPGR1);
+        tipg = e1000_tipg_ipgr2_insert(tipg, DEFAULT_82575_TIPG_IPGR2);
+        break;
+    default:
+        tipg = e1000_tipg_ipgr1_insert(tipg, DEFAULT_82543_TIPG_IPGR1);
+        tipg = e1000_tipg_ipgr2_insert(tipg, DEFAULT_82543_TIPG_IPGR2);
+        break;
+    }
+
+    e1000_tipg_wr(dev->device, tipg);
+}
+
+/*****************************************************************
+ * Configure card transmit
+ *
+ ****************************************************************/
+static void e1000_configure_tx(e1000_device_t *dev)
+{
+    // TODO: configure_tx
+    if (dev->mac_type >= e1000_82571 && dev->mac_type < e1000_82575) {
+        /* Reset delay timers after every interrupt */
+        e1000_ctrlext_int_tca_wrf(dev->device, 1);
+    }
+
+    /* Set Transmit Inter-Packet Gap (TIPG)*/
+    e1000_set_tipg(dev);
+}
+
+/*****************************************************************
+ * Configure device receive
+ *
+ ****************************************************************/
+static void e1000_configure_rx(e1000_device_t *dev)
+{
+    /* set buffer size and enable receive unit */
+    e1000_set_rxbsize(dev, dev->rx_bsize);
+}
+
+/*****************************************************************
+ * Initialize the hardware
+ *
+ ****************************************************************/
+void e1000_hwinit(e1000_device_t *dev, struct device_mem *bar_info,
+                  int nr_allocated_bars, volatile struct tx_desc **transmit_ring,
+                  volatile union rx_desc **receive_ring, int receive_buffers,
+                  int transmit_buffers, uint8_t *mac_addr,
+                  bool user_mac_addr, bool use_interrupt)
+{
+    struct frame_identity frameid = { .base = 0, .bits = 0 };
+    struct capref frame;
+    errval_t err;
+
+    IRQ_DEBUG("Initializing network device.\n");
+
+    if (nr_allocated_bars < 1) {
+        E1000_PRINT_ERROR("Error: Not enough PCI bars allocated. Can not initialize network device.\n");
+        exit(1);
+    }
+
+    err = map_device(&bar_info[0]);
+    if (err_is_fail(err)) {
+        E1000_PRINT_ERROR("Error: map_device failed. Can not initialize network device.\n");
+        exit(err);
+    }
+
+    e1000_initialize(dev->device, (void *) bar_info[0].vaddr);
+       
+       /*
+        * XXX: This is a check if we are using legacy descriptors and virtual functions
+        *      are enabled to display an error message and abort execution.
+        */
+    if (dev->mac_type == e1000_I350 && E1000_USE_LEGACY_DESC) {
+        if(e1000_txswc_loopback_en_rdf(dev->device)
+               || e1000_status_I350_vfe_rdf(dev->device)
+               || e1000_txswc_macas_rdf(dev->device)
+               || e1000_txswc_vlanas_rdf(dev->device)) {
+            debug_printf("ERROR: legacy descriptors used with Advanced Features!\n");
+            exit(1);
+        };
+
+    }
+
+    IRQ_DEBUG("Setting media type.\n");
+    e1000_set_media_type(dev);
+
+    err = e1000_reset(dev);
+    if (err) {
+        IRQ_DEBUG("Error during e1000_reset! Exiting.");
+        exit(1);
+    }
+
+    IRQ_DEBUG("Deasserting PHY reset.\n");
+    e1000_ctrl_phy_rst_wrf(dev->device, 0);
+
+    IRQ_DEBUG("Setting serial interface mode.\n");
+    e1000_set_serial_interface_mode(dev);
+
+    IRQ_DEBUG("Auto negotiating link.\n");
+    if (!e1000_auto_negotiate_link(dev)) {
+        IRQ_DEBUG("Auto negotiating link failed, force link-up in driver.\n");
+        e1000_ctrl_slu_wrf(dev->device, 0x1);
+        //set full-duplex
+        e1000_ctrl_fd_wrf(dev->device, 0x1);
+        e1000_ctrl_speed_wrf(dev->device, e1000_status_speed_rdf(dev->device));
+    }
+
+    if (dev->mac_type == e1000_I350) {
+        e1000_ctrl_rfce_wrf(dev->device, 0);
+        e1000_ctrl_tfce_wrf(dev->device, 0);
+    }
+    /* set flow control */
+    e1000_fcal_wr(dev->device, 0);
+    e1000_fcah_wr(dev->device, 0);
+    e1000_fct_wr(dev->device, 0);
+
+    /* initialize statistic counters */
+    for (int i = 0; i < e1000_statsregs_length; i++) {
+        e1000_statsregs_rd(dev->device, i);
+    }
+
+    /* --------------------- MAC address setup --------------------- */
+    IRQ_DEBUG("Setting up MAC address.\n");
+
+    /* is a valid MAC already present? */
+    /* This will always return false due to hardware/software reset */
+    bool mac_present = e1000_rah_av_rdf(dev->device, 0);
+
+    if (user_mac_addr || !mac_present) {
+        uint16_t mac_word0, mac_word1, mac_word2;
+        e1000_rah_t rah = 0;
+
+        if (user_mac_addr == false)
+            /* read MAC from EEPROM */
+        {
+            e1000_read_mac_addr(dev, mac_addr);
+        }
+
+        mac_word0 = (((uint16_t) mac_addr[1]) << 8) | mac_addr[0];
+        mac_word1 = (((uint16_t) mac_addr[3]) << 8) | mac_addr[2];
+        mac_word2 = (((uint16_t) mac_addr[5]) << 8) | mac_addr[4];
+
+        if (user_mac_addr == false && mac_word0 == 0 && mac_word1 == 0
+                && mac_word2 == 0) {
+            E1000_PRINT_ERROR("Error: Failed to read MAC address from EEPROM.\n");
+            E1000_PRINT_ERROR("Try setting it manually. Use -h for help.\n");
+            exit(1);
+        }
+
+        /* program card's address with MAC */
+        e1000_rah_wr(dev->device, 0, 0);
+        e1000_ral_wr(dev->device, 0, (mac_word0 | ((mac_word1) << 16)));
+        rah = e1000_rah_rah_insert(rah, mac_word2);
+        rah = e1000_rah_av_insert(rah, 1);
+        e1000_rah_wr(dev->device, 0, rah);
+    }
+
+    /* cache MAC for stack to see */
+    uint64_t mac_hi = e1000_rah_rah_rdf(dev->device, 0);
+    uint64_t mac = e1000_ral_rd(dev->device, 0) + (mac_hi << 32);
+    mac_addr[0] = mac & 0xff;
+    mac_addr[1] = (mac >> 8) & 0xff;
+    mac_addr[2] = (mac >> 16) & 0xff;
+    mac_addr[3] = (mac >> 24) & 0xff;
+    mac_addr[4] = (mac >> 32) & 0xff;
+    mac_addr[5] = (mac >> 40) & 0xff;
+
+    IRQ_DEBUG("MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+                mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
+
+    /* clear all other filers (clear high-to-low (13.4.3)) */
+    for (int i = 1; i < e1000_ral_length; i++) {
+        e1000_rah_wr(dev->device, i, 0);
+        e1000_ral_wr(dev->device, i, 0);
+    }
+
+    /* clear MTA table */
+    for (int i = 0; i < e1000_mta_length; i++) {
+        e1000_mta_wr(dev->device, i, 0);
+    }
+
+    /* --------------------- receive setup --------------------- */
+    /* receive descriptor control */
+    if (dev->mac_type == e1000_82575
+        || dev->mac_type == e1000_82576
+        || dev->mac_type == e1000_I210) {
+        e1000_rxdctl_82575_t rxdctl = 0;
+
+        rxdctl = e1000_rxdctl_82575_enable_insert(rxdctl, 1);
+        rxdctl = e1000_rxdctl_82575_wthresh_insert(rxdctl, 1);
+        e1000_rxdctl_82575_wr(dev->device, 0, rxdctl);
+    }  else if (dev->mac_type != e1000_I350) {
+        e1000_rxdctl_t rxdctl = 0;
+
+        rxdctl = e1000_rxdctl_gran_insert(rxdctl, 1);
+        rxdctl = e1000_rxdctl_wthresh_insert(rxdctl, 1);
+        e1000_rxdctl_wr(dev->device, 0, rxdctl);
+
+        e1000_rfctl_exsten_wrf(dev->device, 0);
+    }
+
+    /* Allocate and map frame for receive ring */
+    *receive_ring = alloc_map_frame(VREGION_FLAGS_READ_WRITE_NOCACHE,
+                                    sizeof(union rx_desc) * receive_buffers, &frame);
+
+    if (*receive_ring == NULL) {
+        E1000_PRINT_ERROR("Error: Failed to allocate map frame.\n");
+        exit(1);
+    }
+
+    err = invoke_frame_identify(frame, &frameid);
+    if (err_is_fail(err)) {
+        E1000_PRINT_ERROR("Error: Failed to invoke frame identify.\n");
+        exit(1);
+    }
+
+    if (dev->mac_type == e1000_I350) {
+        /* If VLANs are not used, software should clear VFE. */
+        e1000_rctl_vfe_wrf(dev->device, 0);
+
+         /* Set up the MTA (Multicast Table Array) by software. This means
+          * zeroing all entries initially and adding in entries as requested. */
+        for (int i = 0; i < 128; ++i) {
+            e1000_mta_wr(dev->device, i, 0);
+        }
+
+        /*  Software should program RDLEN[n] register only when queue is disabled */
+        e1000_rdbal_I350_wr(dev->device, 0, frameid.base & 0xffffffff);
+        e1000_rdbah_I350_wr(dev->device, 0, (frameid.base >> 32) & 0xffffffff);
+        e1000_rdlen_I350_len_wrf(dev->device, 0, (receive_buffers / 8));
+
+        /* Initialize receive head and tail pointers */
+        e1000_rdh_I350_wr(dev->device, 0, 0);
+        e1000_rdt_I350_wr(dev->device, 0, 0);
+
+        /* Program SRRCTL of the queue according to the size of the buffers,
+         * the required header handling and the drop policy. */
+        e1000_srrctl_t srrctl = 0;
+        srrctl = e1000_srrctl_bsizeheader_insert(srrctl, 0);
+        e1000_srrctl_wr(dev->device, 0, srrctl);
+
+        /* Enable the queue by setting RXDCTL.ENABLE. In the case of queue zero,
+         * the enable bit is set by default - so the ring parameters should be
+         * set before RCTL.RXEN is set. */
+        e1000_rxdctl_I350_t rxdctl = 0;
+        rxdctl = e1000_rxdctl_I350_enable_insert(rxdctl, 1);
+        rxdctl = e1000_rxdctl_I350_wthresh_insert(rxdctl, 1);
+        e1000_rxdctl_I350_wr(dev->device, 0, rxdctl);
+
+        /* Poll the RXDCTL register until the ENABLE bit is set. The tail should
+         * not be bumped before this bit was read as one. */
+        uint16_t timeout = 1000;
+        while(!e1000_rxdctl_I350_enable_rdf(dev->device, 0) && timeout--) {
+            usec_delay(10);
+        }
+        if (timeout <= 0) {
+            IRQ_DEBUG("ERROR: failed to enable the RX queue\n");
+        }
+
+    } else {
+        /* tell card where receive ring is */
+        e1000_rdbal_wr(dev->device, 0, frameid.base & 0xffffffff);
+        e1000_rdbah_wr(dev->device, 0, (frameid.base >> 32) & 0xffffffff);
+        e1000_rdlen_len_wrf(dev->device, 0, (receive_buffers / 8));
+
+        /* Initialize receive head and tail pointers */
+        e1000_rdh_wr(dev->device, 0, 0);
+        e1000_rdt_wr(dev->device, 0, 0);
+    }
+    e1000_configure_rx(dev);
+
+
+    /* --------------------- transmit setup --------------------- */
+    if (dev->mac_type == e1000_82575
+        || dev->mac_type == e1000_82576
+        || dev->mac_type == e1000_I210) {
+        e1000_txdctl_82575_t txdctl = 0;
+        txdctl = e1000_txdctl_82575_enable_insert(txdctl, 1);
+        txdctl = e1000_txdctl_82575_priority_insert(txdctl, 1);
+        e1000_txdctl_82575_wr(dev->device, 0, txdctl);
+    } else if (dev->mac_type != e1000_I350){
+        e1000_txdctl_t txdctl = 0;
+        txdctl = e1000_txdctl_gran_insert(txdctl, 1);
+        e1000_txdctl_wr(dev->device, 0, txdctl);
+    }
+
+    /* allocate and map frame for transmit ring */
+    *transmit_ring = alloc_map_frame(VREGION_FLAGS_READ_WRITE_NOCACHE,
+                                     sizeof(struct tx_desc) * transmit_buffers, &frame);
+
+    if (*transmit_ring == NULL) {
+        E1000_PRINT_ERROR("Error: Failed to allocate map frame.\n");
+        exit(1);
+    }
+
+    err = invoke_frame_identify(frame, &frameid);
+    if (err_is_fail(err)) {
+        E1000_PRINT_ERROR("Error: Failed to invoke frame identify.\n");
+        exit(1);
+    }
+
+    if (dev->mac_type == e1000_I350) {
+        /* Software should program TDLEN[n] register only when queue is disabled */
+        e1000_tdbal_I350_wr(dev->device, 0, frameid.base & 0xffffffff);
+        e1000_tdbah_I350_wr(dev->device, 0, frameid.base >> 32);
+        e1000_tdlen_I350_len_wrf(dev->device, 0, (transmit_buffers / 8));
+        e1000_tdh_I350_wr(dev->device, 0, 0);
+        e1000_tdt_I350_wr(dev->device, 0, 0);
+
+        /* Program the TXDCTL register with the desired TX descriptor write
+         * back policy. Suggested values are:
+                — WTHRESH = 1b
+                — All other fields 0b.
+         */
+        e1000_txdctl_I350_t txdctl = 0;
+        txdctl = e1000_txdctl_I350_priority_insert(txdctl, 1);
+        txdctl = e1000_txdctl_I350_wthresh_insert(txdctl, 1);
+        e1000_txdctl_I350_wr(dev->device, 0, txdctl);
+
+        /* If needed, set the TDWBAL/TWDBAH to enable head write back */
+        e1000_tdwbal_wr(dev->device, 0, 0);
+        e1000_tdwbah_wr(dev->device, 0, 0);
+
+        /* Enable the queue using TXDCTL.ENABLE (queue zero is enabled by default). */
+        e1000_txdctl_I350_enable_wrf(dev->device, 0, 1);
+
+        /* Poll the TXDCTL register until the ENABLE bit is set. */
+        uint16_t timeout = 1000;
+        while(!e1000_txdctl_I350_enable_rdf(dev->device, 0) && timeout--) {
+            usec_delay(10);
+        }
+        if (timeout <= 0) {
+            IRQ_DEBUG("ERROR: failed to enable the TX queue\n");
+        }
+
+    } else {
+        /* tell card about our transmit ring */
+        e1000_tdbal_wr(dev->device, 0, frameid.base & 0xffffffff);
+        e1000_tdbah_wr(dev->device, 0, frameid.base >> 32);
+        e1000_tdlen_len_wrf(dev->device, 0, (transmit_buffers / 8));
+        e1000_tdh_wr(dev->device, 0, 0);
+        e1000_tdt_wr(dev->device, 0, 0);
+    }
+    e1000_configure_tx(dev);
+
+    /* enable transmit */
+
+    e1000_tctl_t tctl = 0;
+    if (dev->mac_type == e1000_I350) {
+        tctl = e1000_tctl_ct_insert(tctl, 0xf);
+    } else {
+        tctl = e1000_tctl_ct_insert(tctl, 0x10);
+    }
+    tctl = e1000_tctl_en_insert(tctl, 1);
+    tctl = e1000_tctl_psp_insert(tctl, 1);
+    tctl = e1000_tctl_bst_insert(tctl, 0x40);
+    e1000_tctl_wr(dev->device, tctl);
+
+    /* Enable interrupts */
+    if (use_interrupt) {
+
+        /* Enable interrupt throttling rate.
+         *
+         * The optimal performance setting for this register is very system and
+         * configuration specific. A initial suggested range is 651-5580 (28Bh - 15CCh).
+         * The value 0 will disable interrupt throttling
+         */
+        if (dev->mac_type == e1000_82575
+            || dev->mac_type == e1000_82576
+            || dev->mac_type == e1000_I210
+            || dev->mac_type == e1000_I350) {
+            e1000_eitr_interval_wrf(dev->device, 0, 5580);
+            //e1000_eitr_interval_wrf(dev->device, 0, 10);
+        }
+        else {
+            e1000_itr_interval_wrf(dev->device, 5580);
+            //e1000_itr_interval_wrf(dev->device, 10);
+        }
+
+        e1000_intreg_t intreg = 0;
+
+        intreg = e1000_intreg_lsc_insert(intreg, 1);
+        intreg = e1000_intreg_rxt0_insert(intreg, 1);
+
+        intreg = e1000_intreg_txqe_insert(intreg, 1);
+        intreg = e1000_intreg_txdw_insert(intreg, 1);
+        e1000_ims_wr(dev->device, intreg);
+    }
+}
+
diff --git a/usr/tests/irqtest/e1000n_hwinit.h b/usr/tests/irqtest/e1000n_hwinit.h
new file mode 100644 (file)
index 0000000..83b6289
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2008, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+/*
+ * e1000_hw.h
+ *
+ *  Created on: Feb 13, 2013
+ *      Author: mao
+ */
+
+#ifndef E1000_HWINIT_H_
+#define E1000_HWINIT_H_
+
+
+/* Default values for the transmit IPG register */
+#define DEFAULT_825XX_TIPG_IPGT        10
+#define DEFAULT_825XX_TIPG_IPGT_FIBER  9
+#define DEFAULT_825XX_TIPG_IPGT_COPPER 8
+#define DEFAULT_82544_TIPG_IPGT_FIBER  6
+#define DEFAULT_82544_TIPG_IPGT_COPPER 8  
+
+#define DEFAULT_82575_TIPG_IPGR1 8
+#define DEFAULT_82542_TIPG_IPGR1 2
+#define DEFAULT_82543_TIPG_IPGR1 10
+
+#define DEFAULT_82575_TIPG_IPGR2 7
+#define DEFAULT_82542_TIPG_IPGR2 10
+#define DEFAULT_82543_TIPG_IPGR2 10
+
+#define IGP_ACTIVITY_LED_MASK   0xFFFFF0FF
+
+#endif /* E1000_HW_H_ */
diff --git a/usr/tests/irqtest/irqtest.c b/usr/tests/irqtest/irqtest.c
new file mode 100644 (file)
index 0000000..44618b4
--- /dev/null
@@ -0,0 +1,300 @@
+/**
+ * \file
+ * \brief A simple test for checking if lpc_timer works
+ * It tests periodic timers implemented by timer library.
+ * test_A: When no arguments are given, then timer_test will run test_A
+ * which starts two periodic timers and stops them after 100 callbacks
+ * from each of them.
+ *
+ * test_B: When there are command line arguments given, then timer_test
+ * will run test_B.  This test registers three periodic timer and stops
+ * when 100 callbacks are received from all three timers.
+ *
+ * It is advised to run both test_A and test_B at same time.  It can be
+ * done by inserting following lines into the menu.lst
+ * module      /x86_64/sbin/lpc_timer core=1
+ * module      /x86_64/sbin/timer_test core=2
+ * module      /x86_64/sbin/timer_test core=3 B
+ *
+ */
+
+/*
+ * Copyright (c) 2007, 2008, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/nameservice_client.h>
+#include <barrelfish/waitset.h>
+#include <pci/pci.h>
+#include "irqtest_debug.h"
+#include "e1000n.h"
+#include "stdint.h"
+
+/*****************************************************************
+ * Local states:
+ *****************************************************************/
+static uint32_t class = PCI_CLASS_ETHERNET;
+static uint32_t subclass = PCI_DONT_CARE;
+static uint32_t bus = PCI_DONT_CARE;
+static uint32_t device = PCI_DONT_CARE;
+static uint32_t function = PCI_DONT_CARE;
+//static uint32_t deviceid = 0x1079; //sbrinz1/2
+static uint32_t deviceid = 0x107d; //appenzeller
+static uint32_t vendor = PCI_VENDOR_INTEL;
+static uint32_t program_interface = PCI_DONT_CARE;
+static e1000_mac_type_t mac_type = e1000_undefined;
+
+/*****************************************************************
+ * Local states:
+ *****************************************************************/
+static uint64_t minbase = -1;
+static uint64_t maxbase = -1;
+
+/*****************************************************************
+ * e1000 states:
+ *****************************************************************/
+static e1000_t e1000;
+static e1000_device_t e1000_device;
+static bool e1000_initialized = false;
+static uint8_t mac_address[MAC_ADDRESS_LEN]; /* buffers the card's MAC address upon card reset */
+
+/*****************************************************************
+ * Receive and transmit
+ *****************************************************************/
+static e1000_rx_bsize_t receive_buffer_size = bsize_16384;
+static volatile struct tx_desc *transmit_ring;
+
+//receive
+static volatile union rx_desc *receive_ring;
+
+
+//static uint32_t receive_bufptr = 0;
+
+static void **receive_opaque = NULL;
+
+
+#define DRIVER_RECEIVE_BUFFERS      (1024 * 8)
+#define DRIVER_TRANSMIT_BUFFERS     (1024 * 8)
+
+#define PACKET_SIZE_LIMIT       1073741824      /* 1 Gigabyte */
+
+
+
+
+
+
+
+static void setup_internal_memory(void)
+{
+    receive_opaque = calloc(sizeof(void *), DRIVER_RECEIVE_BUFFERS);
+    assert(receive_opaque != NULL );
+}
+
+
+
+
+static void e1000_init_fn(struct device_mem *bar_info, int nr_allocated_bars)
+{
+    IRQ_DEBUG("Starting hardware initialization.\n");
+    e1000_hwinit(&e1000_device, bar_info, nr_allocated_bars, &transmit_ring,
+                 &receive_ring, DRIVER_RECEIVE_BUFFERS, DRIVER_TRANSMIT_BUFFERS,
+                 mac_address, false, 1);
+
+    // Disable interrupt throttling
+    e1000_itr_interval_wrf(e1000_device.device, 0);
+    e1000_eitr_interval_wrf(e1000_device.device, 0, 0);
+
+    e1000_initialized = true;
+    IRQ_DEBUG("Hardware initialization complete.\n");
+
+    setup_internal_memory();
+
+}
+
+/*****************************************************************
+ * e1000 interrupt handler
+ *
+ ****************************************************************/
+static int64_t interrupt_counter = 0;
+static int64_t int_trigger_counter = 0;
+static void e1000_interrupt_handler_fn(void *arg)
+{
+    /* Read interrupt cause, this also acknowledges the interrupt */
+    e1000_intreg_t icr = e1000_icr_rd(e1000_device.device);
+
+    printf("#### interrupt handler called: %"PRIi64"\n", interrupt_counter);
+    ++interrupt_counter;
+
+    if (e1000_intreg_rxt0_extract(icr) == 0) {
+        return;
+    }
+}
+
+static void e1000_reregister_handler(void *arg)
+{
+    errval_t err;
+    printf("%s:%s:%d:\n", __FILE__, __FUNCTION__, __LINE__);
+    err = pci_reregister_irq_for_device(
+            class, subclass, program_interface,
+            vendor, deviceid, bus, device, function,
+            e1000_interrupt_handler_fn, NULL,
+            e1000_reregister_handler, NULL);
+    if (err_is_fail(err)) {
+        DEBUG_ERR(err, "pci_reregister_irq_for_device");
+    }
+
+    return;
+}
+
+
+int main(int argc, char **argv)
+{
+    errval_t err;
+
+    /** Parse command line arguments. */
+    IRQ_DEBUG("irq test started.\n");
+
+    IRQ_DEBUG("argc = %d\n", argc);
+
+
+
+    for (int i = 1; i < argc; i++) {
+        IRQ_DEBUG("arg %d = %s\n", i, argv[i]);
+        if (strcmp(argv[i], "auto") == 0) {
+            continue;
+        }
+        if (strncmp(argv[i], "affinitymin=", strlen("affinitymin=")) == 0) {
+            minbase = atol(argv[i] + strlen("affinitymin="));
+            IRQ_DEBUG("minbase = %lu\n", minbase);
+        } else if (strncmp(argv[i], "affinitymax=", strlen("affinitymax="))
+                 == 0) {
+            maxbase = atol(argv[i] + strlen("affinitymax="));
+            IRQ_DEBUG("maxbase = %lu\n", maxbase);
+        } else if(strncmp(argv[i],"bus=",strlen("bus=")-1)==0) {
+            bus = atol(argv[i] + strlen("bus="));
+            IRQ_DEBUG("bus = %ul\n", bus);
+        } else if (strncmp(argv[i], "device=", strlen("device=")) == 0) {
+            device = atol(argv[i] + strlen("device="));
+            IRQ_DEBUG("device = %ul\n", device);
+        } else if (strncmp(argv[i], "function=", strlen("function=")) == 0) {
+            function = atol(argv[i] + strlen("function="));
+            IRQ_DEBUG("function = %u\n", function);
+        } else if (strncmp(argv[i], "deviceid=", strlen("deviceid=")) == 0) {
+            deviceid = strtoul(argv[i] + strlen("deviceid="), NULL, 0);
+            IRQ_DEBUG("deviceid = %u\n", deviceid);
+        } else if (strcmp(argv[i], "-h") == 0 ||
+                 strcmp(argv[i], "--help") == 0) {
+            //exit_help(argv[0]);
+        } else {
+            IRQ_DEBUG("Parsed Kaluga device address %s.\n", argv[i]);
+        }
+    } // end for :
+
+    if ((minbase != -1) && (maxbase != -1)) {
+        IRQ_DEBUG("set memory affinity [%lx, %lx]\n", minbase, maxbase);
+        ram_set_affinity(minbase, maxbase);
+    }
+
+
+    IRQ_DEBUG("Starting standalone driver.\n");
+
+    /* Check if forced device id and vendor is known to be supported. */
+    mac_type = e1000_get_mac_type(vendor, deviceid);
+    if(mac_type == e1000_undefined){
+        IRQ_DEBUG("WARNING: Passed deviceid unknown.\n");
+    }
+
+
+    /* Setup known device info */
+    e1000_device.device = &e1000;
+    e1000_device.mac_type = mac_type;
+    e1000_device.device_id = deviceid;
+    if (e1000_device.mac_type == e1000_82575
+        || e1000_device.mac_type == e1000_82576
+        || e1000_device.mac_type == e1000_I210
+        || e1000_device.mac_type == e1000_I350) {
+        // These cards do not have a bsex reg entry
+        // therefore, we can't use 16384 buffer size.
+        // If we use smaller buffers than 2048 bytes the
+        // eop bit on received packets might not be set in case the package
+        // is biger than the receive buffer size and we don't handle these
+        // cases currently.
+        e1000_device.rx_bsize = bsize_2048;
+    } else {
+        e1000_device.rx_bsize = receive_buffer_size;
+    }
+    e1000_device.media_type = e1000_media_type_undefined;
+
+
+    IRQ_DEBUG("Connecting to PCI.\n");
+
+    err = pci_client_connect();
+    assert(err_is_ok(err));
+
+    err = pci_register_driver_movable_irq(e1000_init_fn, class, subclass, program_interface,
+                                          vendor, deviceid, bus, device, function,
+                                          e1000_interrupt_handler_fn, NULL,
+                                          e1000_reregister_handler,
+                                          NULL);
+    IRQ_DEBUG("########### Driver with interrupts ###########\n");
+
+
+    if (err_is_fail(err)) {
+        E1000_PRINT_ERROR("Error: %u, pci_register_driver failed\n", (unsigned int)err);
+        exit(err);
+    }
+
+    IRQ_DEBUG("Registered driver.\n");
+
+    IRQ_DEBUG("#### starting dispatch loop.\n");
+    uint64_t ticks_per_msec, current_tick;
+    uint64_t last_int_trigger_ticks = 0;
+    sys_debug_get_tsc_per_ms(&ticks_per_msec);
+    IRQ_DEBUG("Ticks per msec: %"PRIu64".\n", ticks_per_msec);
+    assert(err_is_ok(err));
+
+    while(true){
+        err = event_dispatch_non_block(get_default_waitset());
+        if(!err_is_ok(err) && err != LIB_ERR_NO_EVENT) {
+            IRQ_DEBUG("Error in event_dispatch_non_block, returned %s\n",
+                    err_getstring(err));
+        }
+
+        if(int_trigger_counter >= 20){
+            if(abs(int_trigger_counter - interrupt_counter) < 3){
+                printf("triggerred: %"PRIi64" and received %"PRIi64" interrupts. (+-2 is okay).\n",
+                        int_trigger_counter, interrupt_counter);
+                printf("TEST SUCCESS\n");
+            }
+            else {
+                printf("triggerred: %"PRIi64" and received %"PRIi64" interrupts. (+-2 is okay).\n",
+                        int_trigger_counter, interrupt_counter);
+                printf("TEST FAILURE\n");
+            }
+            exit(0);
+        }
+        if(e1000_initialized){
+            current_tick = rdtsc();
+            if(last_int_trigger_ticks + ticks_per_msec*100 < current_tick){
+                last_int_trigger_ticks = current_tick;
+                IRQ_DEBUG("Creating Link change interrupt...\n");
+
+                // Cause an (artificial) interrupt
+                e1000_intreg_t ics = 0;
+                ics = e1000_intreg_lsc_insert(ics, 1);
+                e1000_ics_wr(e1000_device.device, ics);
+                int_trigger_counter++;
+            }
+        }
+    }
+
+    return 1;
+}
diff --git a/usr/tests/irqtest/irqtest_debug.h b/usr/tests/irqtest/irqtest_debug.h
new file mode 100644 (file)
index 0000000..183f251
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2008, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef __IRQTEST_DEBUG_H__
+#define __IRQTEST_DEBUG_H__
+
+/*****************************************************************
+ * Debug printer:
+ *****************************************************************/
+#define IRQTEST_DEBUG 1
+
+#if defined(IRQTEST_DEBUG) || defined(GLOBAL_DEBUG)
+#define IRQ_DEBUG(fmt, ...) printf("irq test: " fmt, ##__VA_ARGS__)
+#else
+#define IRQ_DEBUG(fmt, ...) ((void)0)
+#endif
+
+#endif // __IRQTEST_DEBUG_H__
index eb03dc1..1bd186a 100644 (file)
@@ -31,7 +31,7 @@
                                  "modify_flags.c", "nkmtest.c",
                                  "vspace_dump.c" ],
                       addLibraries = [ "cap_predicates" ],
-                      architectures = [ "x86_64" ]
+                      architectures = [ "x86_64", "k1om" ]
                     },
   build application { target = "nkmtest_all",
                       cFiles = [ "main.c",