diff --git a/README.md b/README.md index 3c7b9e12ce58e12a267d2d805a813a83ee1b7cb7..c5ff6cc9c416ceab9b45aa216b17daa2eec0c96f 100644 --- a/README.md +++ b/README.md @@ -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/patches/fmc-sw.diff b/patches/fmc-sw.diff index f5cc6f76ea70f7e13a7651fed63d30b54d604f84..4272729abb20debda32975a48e6899fe4fcbaff5 100644 --- a/patches/fmc-sw.diff +++ b/patches/fmc-sw.diff @@ -1,8 +1,12 @@ 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 };