Merge branch 'stable/broadcom.ibft' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6.git] / drivers / firmware / iscsi_ibft_find.c
index d6470ef..f032e44 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2007 Red Hat, Inc.
+ *  Copyright 2007-2010 Red Hat, Inc.
  *  by Peter Jones <pjones@redhat.com>
  *  Copyright 2007 IBM, Inc.
  *  by Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
@@ -22,6 +22,7 @@
 #include <linux/blkdev.h>
 #include <linux/ctype.h>
 #include <linux/device.h>
+#include <linux/efi.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/limits.h>
 #include <linux/stat.h>
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/acpi.h>
+#include <linux/iscsi_ibft.h>
 
 #include <asm/mmzone.h>
 
 /*
  * Physical location of iSCSI Boot Format Table.
  */
-struct ibft_table_header *ibft_addr;
+struct acpi_table_ibft *ibft_addr;
 EXPORT_SYMBOL_GPL(ibft_addr);
 
-#define IBFT_SIGN "iBFT"
+static const struct {
+       char *sign;
+} ibft_signs[] = {
+#ifdef CONFIG_ACPI
+       /*
+        * One spec says "IBFT", the other says "iBFT". We have to check
+        * for both.
+        */
+       { ACPI_SIG_IBFT },
+#endif
+       { "iBFT" },
+       { "BIFT" },     /* Broadcom iSCSI Offload */
+};
+
 #define IBFT_SIGN_LEN 4
 #define IBFT_START 0x80000 /* 512kB */
 #define IBFT_END 0x100000 /* 1MB */
 #define VGA_MEM 0xA0000 /* VGA buffer */
 #define VGA_SIZE 0x20000 /* 128kB */
 
+#ifdef CONFIG_ACPI
+static int __init acpi_find_ibft(struct acpi_table_header *header)
+{
+       ibft_addr = (struct acpi_table_ibft *)header;
+       return 0;
+}
+#endif /* CONFIG_ACPI */
 
-/*
- * Routine used to find the iSCSI Boot Format Table. The logical
- * kernel address is set in the ibft_addr global variable.
- */
-unsigned long __init find_ibft_region(unsigned long *sizep)
+static int __init find_ibft_in_mem(void)
 {
        unsigned long pos;
        unsigned int len = 0;
        void *virt;
-
-       ibft_addr = NULL;
+       int i;
 
        for (pos = IBFT_START; pos < IBFT_END; pos += 16) {
                /* The table can't be inside the VGA BIOS reserved space,
@@ -65,21 +83,48 @@ unsigned long __init find_ibft_region(unsigned long *sizep)
                if (pos == VGA_MEM)
                        pos += VGA_SIZE;
                virt = isa_bus_to_virt(pos);
-               if (memcmp(virt, IBFT_SIGN, IBFT_SIGN_LEN) == 0) {
-                       unsigned long *addr =
-                           (unsigned long *)isa_bus_to_virt(pos + 4);
-                       len = *addr;
-                       /* if the length of the table extends past 1M,
-                        * the table cannot be valid. */
-                       if (pos + len <= (IBFT_END-1)) {
-                               ibft_addr = (struct ibft_table_header *)virt;
-                               break;
+
+               for (i = 0; i < ARRAY_SIZE(ibft_signs); i++) {
+                       if (memcmp(virt, ibft_signs[i].sign, IBFT_SIGN_LEN) ==
+                           0) {
+                               unsigned long *addr =
+                                   (unsigned long *)isa_bus_to_virt(pos + 4);
+                               len = *addr;
+                               /* if the length of the table extends past 1M,
+                                * the table cannot be valid. */
+                               if (pos + len <= (IBFT_END-1)) {
+                                       ibft_addr = (struct acpi_table_ibft *)virt;
+                                       goto done;
+                               }
                        }
                }
        }
+done:
+       return len;
+}
+/*
+ * Routine used to find the iSCSI Boot Format Table. The logical
+ * kernel address is set in the ibft_addr global variable.
+ */
+unsigned long __init find_ibft_region(unsigned long *sizep)
+{
+       int i;
+       ibft_addr = NULL;
+
+#ifdef CONFIG_ACPI
+       for (i = 0; i < ARRAY_SIZE(ibft_signs) && !ibft_addr; i++)
+               acpi_table_parse(ibft_signs[i].sign, acpi_find_ibft);
+#endif /* CONFIG_ACPI */
+
+       /* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will
+        * only use ACPI for this */
+
+       if (!ibft_addr && !efi_enabled)
+               find_ibft_in_mem();
+
        if (ibft_addr) {
-               *sizep = PAGE_ALIGN(len);
-               return pos;
+               *sizep = PAGE_ALIGN(ibft_addr->header.length);
+               return (u64)isa_virt_to_bus(ibft_addr);
        }
 
        *sizep = 0;