Skip to content
Snippets Groups Projects
Commit 31d788f2 authored by Dimitris Lampridis's avatar Dimitris Lampridis
Browse files

[fmc-sw] support EEPROM reading through at24 in post 5.0 kernels.

parent 2f6fd5e9
No related branches found
No related tags found
No related merge requests found
Pipeline #1214225 passed
......@@ -15,8 +15,3 @@ errors during installation) in the following distributions:
However, there is no guarantee that things will properly work on these distributions, once
installed. In particular, there is a known issue with DMA transfers causing a kernel crash, which
prohibits for example the retrieval of ADC samples from the FMC-ADC-100M.
There is also another known issue with Linux kernels > v5.0. Due to a significant change in the at24
driver, it is no longer possible to access the SPEC/SVEC/FMC EEPROMs. The drivers have been modified
to bypass this issue and continue working when used with such a kernel, but the EEPROM will still
not be accessible.
diff --git a/drivers/fmc/fmc-eeprom.c b/drivers/fmc/fmc-eeprom.c
index a000a0d..e5f96b2 100644
index a000a0d..2bd2a6f 100644
--- a/drivers/fmc/fmc-eeprom.c
+++ b/drivers/fmc/fmc-eeprom.c
@@ -10,6 +10,10 @@
@@ -7,9 +7,14 @@
#include <linux/module.h>
#include <linux/memory.h>
#include <linux/fmc.h>
+#include <linux/slab.h>
#include "fmc-internal.h"
#include "fmc-compat.h"
......@@ -13,49 +17,31 @@ index a000a0d..e5f96b2 100644
#define FRU_EEPROM_NAME "fru_eeprom"
/**
@@ -17,12 +21,37 @@
@@ -17,11 +22,14 @@
*/
#define FMC_EEPROM_TYPE_DEFAULT "24c02"
+#if KERNEL_VERSION(5, 1, 0) <= LINUX_VERSION_CODE
+/* static int fmc_slot_eeprom_setup(struct notifier_block *nb, */
+/* unsigned long event, void *data) */
+/* { */
+/* struct nvmem_device *nvmem = data; */
+
+/* //dev_err(&nvmem->dev, "friendly notifier, action %ld\n", event); */
+/* if (strcmp(nvmem_dev_name(nvmem), "1-00500") != 0) */
+/* return NOTIFY_DONE; */
+
+/* return NOTIFY_OK; */
+/* }; */
+
+/* static struct notifier_block fmc_eeprom_nvmem_notifier = { */
+/* .notifier_call = fmc_slot_eeprom_setup, */
+/* }; */
+struct property_entry at24_properties[] = {
-/**
- * Setup function for the AT24C02 EEPROM. What we need to do here is to
- * quickly validate the EEPROM content. The EEPROM should contain a valid
- * FRU.
- */
+#if KERNEL_VERSION(4, 6, 0) <= LINUX_VERSION_CODE
+const struct property_entry at24_24c02[AT24_NUM_PROPERTIES] = {
+ PROPERTY_ENTRY_U32("size", 256),
+ PROPERTY_ENTRY_U32("pagesize", 8),
+ PROPERTY_ENTRY_U32("address-width", 16),
+ { }
+};
+#else
/**
* Setup function for the AT24C02 EEPROM. What we need to do here is to
* quickly validate the EEPROM content. The EEPROM should contain a valid
* FRU.
*/
+#if KERNEL_VERSION(4, 6, 0) <= LINUX_VERSION_CODE
+static void fmc_slot_eeprom_setup(struct nvmem_device *macc, void *context)
+#else
static void fmc_slot_eeprom_setup(struct memory_accessor *macc, void *context)
+#endif
{
struct fmc_slot *slot = context;
@@ -38,17 +67,26 @@ static const struct at24_platform_data at24_24c02 = {
@@ -38,9 +46,10 @@ static const struct at24_platform_data at24_24c02 = {
.flags = 0,
.setup = fmc_slot_eeprom_setup,
};
+#endif /* KERNEL_VERSION(5, 1, 0) <= LINUX_VERSION_CODE */
+#endif /* KERNEL_VERSION(4, 6, 0) <= LINUX_VERSION_CODE */
/**
- * Initialize I2C EEPROM info with standad values
......@@ -63,68 +49,92 @@ index a000a0d..e5f96b2 100644
*/
static void fmc_slot_eeprom_init(struct fmc_slot *slot,
struct i2c_board_info *info,
const char *name)
@@ -48,7 +57,11 @@ static void fmc_slot_eeprom_init(struct fmc_slot *slot,
{
+#if KERNEL_VERSION(5, 1, 0) <= LINUX_VERSION_CODE
+ struct property_entry **p_entry;
+#endif
strncpy(info->type, name, I2C_NAME_SIZE);
info->addr = FMC_EEPROM_ADDR_SPACE;
+#if KERNEL_VERSION(5, 1, 0) <= LINUX_VERSION_CODE
+ p_entry = (struct property_entry **)&info->properties;
+ *p_entry = at24_properties;
+#if KERNEL_VERSION(4, 6, 0) <= LINUX_VERSION_CODE
+ info->properties = slot->at24_data;
+#else
info->platform_data = &slot->at24_data;
+#endif
}
static void fmc_slot_eeprom_init_default(struct fmc_slot *slot,
@@ -56,8 +94,12 @@ static void fmc_slot_eeprom_init_default(struct fmc_slot *slot,
@@ -56,8 +69,12 @@ static void fmc_slot_eeprom_init_default(struct fmc_slot *slot,
{
memset(info, 0, sizeof(*info));
fmc_slot_eeprom_init(slot, info, FMC_EEPROM_TYPE_DEFAULT);
+#if KERNEL_VERSION(5, 1, 0) > LINUX_VERSION_CODE
+#if KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE
memcpy(&slot->at24_data, &at24_24c02, sizeof(slot->at24_data));
slot->at24_data.context = slot;
+/* #else */
+/* nvmem_register_notifier(&fmc_eeprom_nvmem_notifier); */
+#else
+ memcpy(slot->at24_data, &at24_24c02, sizeof(slot->at24_data));
+#endif
}
/**
@@ -70,9 +112,15 @@ ssize_t fmc_slot_eeprom_read(struct fmc_slot *slot,
@@ -66,13 +83,41 @@ static void fmc_slot_eeprom_init_default(struct fmc_slot *slot,
ssize_t fmc_slot_eeprom_read(struct fmc_slot *slot,
void *buf, off_t offset, size_t count)
{
+ int err = 0;
+#if KERNEL_VERSION(4, 6, 0) <= LINUX_VERSION_CODE
+ int idx;
+ size_t len;
+ struct nvmem_device *nvmem;
+ char *nvmem_name;
+ /*
+ * TODO Check if index can be anything else than zero and,
+ * if yes, how to get the proper value.
+ */
+ idx = 0;
+ len = strlen(dev_name(&slot->eeprom->dev)) + 2;
+ nvmem_name = kzalloc(len, GFP_KERNEL);
+ if (nvmem_name) {
+ snprintf(nvmem_name, len, "%s%d",
+ dev_name(&slot->eeprom->dev), idx);
+ nvmem = nvmem_device_get(&slot->dev, nvmem_name);
+ if (nvmem) {
+ err = nvmem_device_read(nvmem, offset, count, buf);
+#if KERNEL_VERSION(5, 1, 0) <= LINUX_VERSION_CODE
+ nvmem_device_put(nvmem);
+#endif
+ }
+ kfree(nvmem_name);
+ }
+#else
/*
* TODO if we export this function, do we have to lock it when we
* use it? Think about it
*/
- if (!slot->macc || !slot->macc->read)
+ if (!slot->macc)
+ return -ENODEV;
+#if KERNEL_VERSION(4, 6, 0) <= LINUX_VERSION_CODE
+ return nvmem_device_read(slot->macc, offset, count, buf);
+#else
+ if (!slot->macc->read)
if (!slot->macc || !slot->macc->read)
return -ENODEV;
return slot->macc->read(slot->macc, buf, offset, count);
- return slot->macc->read(slot->macc, buf, offset, count);
+ err = slot->macc->read(slot->macc, buf, offset, count);
+#endif
+ return err;
}
EXPORT_SYMBOL(fmc_slot_eeprom_read);
@@ -176,6 +224,9 @@ int fmc_slot_eeprom_type_set(struct fmc_slot *slot, const char *type)
struct i2c_board_info i2c_info;
unsigned int len;
int ret;
+#if KERNEL_VERSION(5, 1, 0) <= LINUX_VERSION_CODE
+ struct property_entry *p_entry;
@@ -152,7 +197,9 @@ void fmc_slot_eeprom_del(struct fmc_slot *slot)
sysfs_remove_link(&slot->dev.kobj, FRU_EEPROM_NAME);
i2c_unregister_device(slot->eeprom);
slot->eeprom = NULL;
+#if KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE
slot->macc = NULL;
+#endif
}
if (strncmp(type, "24c", 3)) {
if (strncmp(type, "at24c", 5)) {
@@ -197,19 +248,24 @@ int fmc_slot_eeprom_type_set(struct fmc_slot *slot, const char *type)
/**
@@ -197,19 +244,25 @@ int fmc_slot_eeprom_type_set(struct fmc_slot *slot, const char *type)
memset(&i2c_info, 0, sizeof(i2c_info));
+#if KERNEL_VERSION(5, 1, 0) > LINUX_VERSION_CODE
+#if KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE
memset(&slot->at24_data, 0, sizeof(slot->at24_data));
+#else
+ memset(slot->at24_data, 0, sizeof(slot->at24_data));
+#endif
len = (len * 1024) / 8;
......@@ -137,26 +147,27 @@ index a000a0d..e5f96b2 100644
- else if (len > 131072) /* 1024K 128KiB */
+ if (len > 131072) /* 1024K 128KiB */
return -EINVAL;
+#if KERNEL_VERSION(5, 1, 0) > LINUX_VERSION_CODE
+ else if (len > 4096) /* 32K 4KiB */
+ slot->at24_data.flags = AT24_FLAG_ADDR16;
+#endif
fmc_slot_eeprom_init(slot, &i2c_info, type);
+#if KERNEL_VERSION(5, 1, 0) > LINUX_VERSION_CODE
+
+#if KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE
+ if (len > 4096) /* 32K 4KiB */
+ slot->at24_data.flags = AT24_FLAG_ADDR16;
slot->at24_data.byte_len = len;
slot->at24_data.page_size = 1; /* 1Byte page to play safe */
slot->at24_data.setup = fmc_slot_eeprom_setup;
@@ -219,7 +275,12 @@ int fmc_slot_eeprom_type_set(struct fmc_slot *slot, const char *type)
@@ -219,7 +272,15 @@ int fmc_slot_eeprom_type_set(struct fmc_slot *slot, const char *type)
i2c_info.type, i2c_info.addr,
slot->at24_data.byte_len, slot->at24_data.page_size,
slot->at24_data.flags);
-
+#else
+ p_entry = (struct property_entry *)i2c_info.properties;
+ p_entry[0] = PROPERTY_ENTRY_U32("pagesize", 1);
+ dev_dbg(&slot->dev, "%s 0x%x\n",
+ i2c_info.type, i2c_info.addr);
+ slot->at24_data[0] = PROPERTY_ENTRY_U32("size", len);
+ slot->at24_data[1] = PROPERTY_ENTRY_U32("pagesize", 1);
+ if (len > 4096) /* 32K 4KiB */
+ slot->at24_data[2] = PROPERTY_ENTRY_U32("address-width", 16);
+ dev_dbg(&slot->dev, "%s 0x%x %d\n",
+ i2c_info.type, i2c_info.addr, len);
+#endif
return fmc_slot_eeprom_replace(slot, &i2c_info);
}
......@@ -185,7 +196,7 @@ index 35a1380..2fd95eb 100644
-
-#endif
diff --git a/include/linux/fmc.h b/include/linux/fmc.h
index 3bc5c12..f99886c 100644
index 3bc5c12..7fd835f 100644
--- a/include/linux/fmc.h
+++ b/include/linux/fmc.h
@@ -11,13 +11,13 @@
......@@ -204,16 +215,15 @@ index 3bc5c12..f99886c 100644
#ifndef _LINUX_FMC_H
#define _LINUX_FMC_H
@@ -84,8 +84,14 @@ struct fmc_slot {
@@ -84,8 +84,13 @@ struct fmc_slot {
struct i2c_client *eeprom;
+#if KERNEL_VERSION(4, 6, 0) <= LINUX_VERSION_CODE
+ struct nvmem_device *macc;
+#define AT24_NUM_PROPERTIES 4
+ struct property_entry at24_data[AT24_NUM_PROPERTIES];
+#else
struct memory_accessor *macc;
+#endif
+#if KERNEL_VERSION(5, 1, 0) > LINUX_VERSION_CODE
struct at24_platform_data at24_data;
+#endif
};
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment