[PATCH 3/3] x86: intel-mid: allow sfi_device() to be used by modules

From: David Cohen
Date: Tue Nov 12 2013 - 17:09:49 EST


This patch implements support for sfi_device() to be called from
driver modules. This is useful to bring SFI support to out-of-tree
modules.

Signed-off-by: David Cohen <david.a.cohen@xxxxxxxxxxxxxxx>
---
arch/x86/include/asm/intel-mid.h | 13 +++++++++
arch/x86/platform/intel-mid/sfi.c | 59 ++++++++++++++++++++++++++++++---------
2 files changed, 59 insertions(+), 13 deletions(-)

diff --git a/arch/x86/include/asm/intel-mid.h b/arch/x86/include/asm/intel-mid.h
index 971cbb1abab3..92b6dc333197 100644
--- a/arch/x86/include/asm/intel-mid.h
+++ b/arch/x86/include/asm/intel-mid.h
@@ -11,6 +11,7 @@
#ifndef _ASM_X86_INTEL_MID_H
#define _ASM_X86_INTEL_MID_H

+#include <linux/module.h>
#include <linux/sfi.h>
#include <linux/platform_device.h>

@@ -21,6 +22,7 @@ extern int __init sfi_parse_mrtc(struct sfi_table_header *table, void *const pri
extern int __init sfi_parse_mtmr(struct sfi_table_header *table, void *const priv);
extern int sfi_mrtc_num;
extern struct sfi_rtc_table_entry sfi_mrtc_array[];
+extern int sfi_parse_one_dev(struct sfi_table_header *table, void *const priv);

/*
* Here defines the array of devices platform data that IAFW would export
@@ -37,9 +39,20 @@ struct devs_id {
struct devs_id *dev);
};

+#ifndef MODULE
#define sfi_device(i) \
static const struct devs_id *const __intel_mid_sfi_##i##_dev __used \
__attribute__((__section__(".x86_intel_mid_dev.init"))) = &i
+#else
+#define sfi_device(i) \
+ static int __init i##_as_module(void) \
+ { \
+ sfi_table_parse(SFI_SIG_DEVS, NULL, NULL, sfi_parse_one_dev, \
+ (void *const)&i); \
+ return 0; \
+ } \
+ module_init(i##_as_module);
+#endif

/*
* Medfield is the follow-up of Moorestown, it combines two chip solution into
diff --git a/arch/x86/platform/intel-mid/sfi.c b/arch/x86/platform/intel-mid/sfi.c
index 2c66024b7067..fb62fad61392 100644
--- a/arch/x86/platform/intel-mid/sfi.c
+++ b/arch/x86/platform/intel-mid/sfi.c
@@ -227,6 +227,7 @@ int get_gpio_by_name(const char *name)
}
return -EINVAL;
}
+EXPORT_SYMBOL_GPL(get_gpio_by_name);

void __init intel_scu_device_register(struct platform_device *pdev)
{
@@ -318,10 +319,10 @@ void intel_scu_devices_destroy(void)
}
EXPORT_SYMBOL_GPL(intel_scu_devices_destroy);

-static void __init install_irq_resource(struct platform_device *pdev, int irq)
+static void install_irq_resource(struct platform_device *pdev, int irq)
{
/* Single threaded */
- static struct resource res __initdata = {
+ static struct resource res = {
.name = "IRQ",
.flags = IORESOURCE_IRQ,
};
@@ -329,8 +330,8 @@ static void __init install_irq_resource(struct platform_device *pdev, int irq)
platform_device_add_resources(pdev, &res, 1);
}

-static void __init sfi_handle_ipc_dev(struct sfi_device_table_entry *pentry,
- struct devs_id *dev)
+static void sfi_handle_ipc_dev(struct sfi_device_table_entry *pentry,
+ struct devs_id *dev)
{
struct platform_device *pdev;
void *pdata = NULL;
@@ -353,8 +354,8 @@ static void __init sfi_handle_ipc_dev(struct sfi_device_table_entry *pentry,
platform_device_add(pdev);
}

-static void __init sfi_handle_spi_dev(struct sfi_device_table_entry *pentry,
- struct devs_id *dev)
+static void sfi_handle_spi_dev(struct sfi_device_table_entry *pentry,
+ struct devs_id *dev)
{
struct spi_board_info spi_info;
void *pdata = NULL;
@@ -383,8 +384,8 @@ static void __init sfi_handle_spi_dev(struct sfi_device_table_entry *pentry,
spi_register_board_info(&spi_info, 1);
}

-static void __init sfi_handle_i2c_dev(struct sfi_device_table_entry *pentry,
- struct devs_id *dev)
+static void sfi_handle_i2c_dev(struct sfi_device_table_entry *pentry,
+ struct devs_id *dev, int from_module)
{
struct i2c_board_info i2c_info;
void *pdata = NULL;
@@ -405,14 +406,20 @@ static void __init sfi_handle_i2c_dev(struct sfi_device_table_entry *pentry,

if (dev->delay)
intel_scu_i2c_device_register(pentry->host_num, &i2c_info);
- else
+ else if (!from_module)
+ /*
+ * Despite i2c_register_board_info() is __init, we have a
+ * false-positive section mismatch here: this function is not
+ * allowed to be called from non-__init source with
+ * @from_module == 0.
+ */
i2c_register_board_info(pentry->host_num, &i2c_info, 1);
}

extern struct devs_id *const __x86_intel_mid_dev_start[],
*const __x86_intel_mid_dev_end[];

-static struct devs_id __init *get_device_id(u8 type, char *name)
+static struct devs_id *get_device_id(u8 type, char *name)
{
struct devs_id *const *dev_table;

@@ -428,8 +435,9 @@ static struct devs_id __init *get_device_id(u8 type, char *name)
return NULL;
}

-static int __init sfi_parse_devs(struct sfi_table_header *table, void *const priv)
+static int __sfi_parse_devs(struct sfi_table_header *table, void *const priv)
{
+ struct devs_id *const devid = priv;
struct sfi_table_simple *sb;
struct sfi_device_table_entry *pentry;
struct devs_id *dev = NULL;
@@ -480,7 +488,16 @@ static int __init sfi_parse_devs(struct sfi_table_header *table, void *const pri
irq = 0; /* No irq */
}

- dev = get_device_id(pentry->type, pentry->name);
+ /*
+ * If @devid is NULL we want to go through the whole static
+ * dev_ids list by calling get_device_id()
+ */
+ if (likely(!devid))
+ dev = get_device_id(pentry->type, pentry->name);
+ else if (devid->type == pentry->type &&
+ !strncmp(devid->name, pentry->name,
+ sizeof(devid->name)))
+ dev = devid;

if (!dev)
continue;
@@ -496,7 +513,7 @@ static int __init sfi_parse_devs(struct sfi_table_header *table, void *const pri
sfi_handle_spi_dev(pentry, dev);
break;
case SFI_DEV_TYPE_I2C:
- sfi_handle_i2c_dev(pentry, dev);
+ sfi_handle_i2c_dev(pentry, dev, !!devid);
break;
case SFI_DEV_TYPE_UART:
case SFI_DEV_TYPE_HSI:
@@ -504,10 +521,26 @@ static int __init sfi_parse_devs(struct sfi_table_header *table, void *const pri
break;
}
}
+ if (unlikely(devid))
+ /* We found the one we're looking for */
+ return 0;
}
+
return 0;
}

+int sfi_parse_one_dev(struct sfi_table_header *table, void *const priv)
+{
+ return priv ? __sfi_parse_devs(table, priv) : -EINVAL;
+}
+EXPORT_SYMBOL_GPL(sfi_parse_one_dev);
+
+static int __init
+sfi_parse_devs(struct sfi_table_header *table, void *const priv)
+{
+ return __sfi_parse_devs(table, NULL);
+}
+
static int __init intel_mid_platform_init(void)
{
sfi_table_parse(SFI_SIG_GPIO, NULL, NULL, sfi_parse_gpio, NULL);
--
1.8.4.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/