table.h/pci: add suggested style of linker tables and example

Based on feedback here's a v2 style for linker tables with
more Linux coding style in mind. This goes with an example
of how to use it.

For now we don't remove the old linker table solution.

Signed-off-by: Luis R. Rodriguez <mcgrof@kernel.org>
diff --git a/Makefile b/Makefile
index 893d5cb..8d900eb 100644
--- a/Makefile
+++ b/Makefile
@@ -40,6 +40,7 @@
 	kasan.o\
 	arch/x86/kernel/init.o \
 	pci.o \
+	pci-quirks.o \
 	beta.o \
 	alpha.o \
 	driver.o \
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index db08020..cbbae39 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -69,7 +69,7 @@
   PROVIDE (__etext = .);
   PROVIDE (_etext = .);
   PROVIDE (etext = .);
-  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata         : { *(.rodata) *(SORT(.rodata.*)) *(.gnu.linkonce.r.*) }
   .rodata1        : { *(.rodata1) }
   .eh_frame_hdr : { *(.eh_frame_hdr) }
   .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 7f7f560..8518c46 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1,3 +1,7 @@
 #include <linux/types.h>
 
+struct pci_fixup {
+	void (*hook)(void);
+};
+
 bool detect_pci(void);
diff --git a/include/linux/tables.h b/include/linux/tables.h
index 6fa9174..c6650a0 100644
--- a/include/linux/tables.h
+++ b/include/linux/tables.h
@@ -148,6 +148,49 @@
  *   }
  */
 
+#define DECLARE_LINKTABLE_RO(type, name)				\
+	 extern const type name[], name##__end[];
+
+#define DEFINE_LINKTABLE_RO(type, name)					\
+	DECLARE_LINKTABLE_RO(type, name);				\
+	const type __attribute__((used,					\
+				  section(".rodata.tbl."		\
+					  #name ".")))			\
+				name[0] = {};				\
+	const type __attribute__((used,					\
+				  section(".rodata.tbl."		\
+					  #name ".~")))			\
+				name##__end[0] = {};
+
+#define LINKTABLE_RO(name, level)					\
+	static const __typeof__(name[0])					\
+		__attribute__((used, section(".rodata.tbl." 		\
+					     #name "." #level)))
+
+#define LINKTABLE_SIZE(name)	((name##__end) - (name))
+
+#define LINKTABLE_RUN_ALL(tbl, func, args...)				\
+do {									\
+	size_t i;							\
+	for (i = 0; i < LINKTABLE_SIZE(tbl); i++)			\
+		(tbl[i]) func (args);					\
+} while (0);
+
+#define LINKTABLE_RUN_ERR(tbl, func, args...)				\
+({									\
+	size_t i;							\
+	int err = 0;							\
+	for (i = 0; !err && i < LINKTABLE_SIZE(tbl); i++)		\
+		err = (tbl[i]) func (args);				\
+		err; \
+})
+
+#define LINKTABLE_FOR_EACH(pointer, tbl)				\
+	for (pointer = tbl;						\
+	     pointer < tbl##__end;					\
+	     pointer++)
+
+
 /*
  * __table - Declares a linker table
  *
diff --git a/pci-quirks.c b/pci-quirks.c
new file mode 100644
index 0000000..2cd1116
--- /dev/null
+++ b/pci-quirks.c
@@ -0,0 +1,13 @@
+#include <linux/kernel.h>
+#include <linux/tables.h>
+#include <linux/pci.h>
+
+DEFINE_LINKTABLE_RO(struct pci_fixup, pci_fixup_early);
+
+static void foo_fixup(void) {
+	pr_info("foo_fixup\n");
+};
+
+LINKTABLE_RO(pci_fixup_early, 50) quirk_foo = {
+	.hook = foo_fixup,
+};
diff --git a/pci.c b/pci.c
index 7dadadc..f1d18a0 100644
--- a/pci.c
+++ b/pci.c
@@ -4,8 +4,15 @@
 
 #include <linux/pci.h>
 
+DECLARE_LINKTABLE_RO(struct pci_fixup, pci_fixup_early);
+
 void early_init_pci(void) {
+
+	const struct pci_fixup *fixup;
+
 	sleep(1);
+	LINKTABLE_FOR_EACH(fixup, pci_fixup_early)
+		fixup->hook();
 }
 
 bool detect_pci(void) {