mtd: support multiple instances

This commit is contained in:
Beat Küng 2020-09-04 15:16:59 +02:00
parent 2b5b6b9430
commit c6cd0536d7
1 changed files with 132 additions and 80 deletions

View File

@ -80,6 +80,8 @@ int mtd_main(int argc, char *argv[])
#else
struct mtd_instance_s;
# if defined(BOARD_HAS_MTD_PARTITION_OVERRIDE)
# define MTD_PARTITION_TABLE BOARD_HAS_MTD_PARTITION_OVERRIDE
# else
@ -88,28 +90,45 @@ int mtd_main(int argc, char *argv[])
#ifdef CONFIG_MTD_RAMTRON
static int ramtron_attach(void);
static int ramtron_attach(mtd_instance_s &instance);
#else
#ifndef PX4_I2C_BUS_MTD
#error "Board needs to define PX4_I2C_BUS_MTD for onboard EEPROM bus"
#endif
static int at24xxx_attach(void);
#endif
static int mtd_start(const char *partition_names[], unsigned n_partitions);
static int mtd_erase(const char *partition_names[], unsigned n_partitions);
static int mtd_readtest(const char *partition_names[], unsigned n_partitions);
static int mtd_rwtest(const char *partition_names[], unsigned n_partitions);
static int mtd_print_info(void);
static int mtd_get_geometry(unsigned long *blocksize, unsigned long *erasesize, unsigned long *neraseblocks,
unsigned *blkpererase, unsigned *nblocks, unsigned *partsize, unsigned n_partitions);
static bool attached = false;
static bool started = false;
static struct mtd_dev_s *mtd_dev;
static unsigned n_partitions_current = 0;
#ifdef PX4_I2C_BUS_MTD
static int at24xxx_attach(mtd_instance_s &instance);
#endif
static int mtd_start(mtd_instance_s &instance, const char *partition_names[], unsigned n_partitions);
static int mtd_erase(const char *partition_names[], unsigned n_partitions);
static int mtd_readtest(const mtd_instance_s &instance, const char *partition_names[], unsigned n_partitions);
static int mtd_rwtest(const mtd_instance_s &instance, const char *partition_names[], unsigned n_partitions);
static int mtd_print_info(int instance);
static int mtd_get_geometry(const mtd_instance_s &instance, unsigned long *blocksize, unsigned long *erasesize,
unsigned long *neraseblocks,
unsigned *blkpererase, unsigned *nblocks, unsigned *partsize);
struct mtd_instance_s {
int (*attach)(mtd_instance_s &instance);
bool attached;
bool started;
struct mtd_dev_s *mtd_dev;
unsigned n_partitions_current;
};
static mtd_instance_s instances[] = {
#ifdef CONFIG_MTD_RAMTRON
{&ramtron_attach, false, false, nullptr, 0},
#endif
#ifdef PX4_I2C_BUS_MTD
{&at24xxx_attach, false, false, nullptr, 0},
#endif
};
static constexpr int num_instances = arraySize(instances);
/* note, these will be equally sized */
static const char *partition_names_default[] = MTD_PARTITION_TABLE;
@ -118,12 +137,22 @@ static const int n_partitions_default = arraySize(partition_names_default);
static int
mtd_status(void)
{
if (!attached) {
PX4_ERR("MTD driver not started");
int ret = 0;
bool running = false;
for (int i = 0; i < num_instances; ++i) {
if (instances[i].attached) {
ret |= mtd_print_info(i);
running = true;
}
}
if (!running) {
PX4_INFO("MTD driver not started");
return 1;
}
return mtd_print_info();
return ret;
}
static void print_usage(void)
@ -137,6 +166,10 @@ static void print_usage(void)
PRINT_MODULE_USAGE_COMMAND_DESCR("readtest", "Perform read test");
PRINT_MODULE_USAGE_COMMAND_DESCR("rwtest", "Perform read-write test");
PRINT_MODULE_USAGE_COMMAND_DESCR("erase", "Erase partition(s)");
PRINT_MODULE_USAGE_COMMAND_DESCR("has-secondary", "Check if the board has configured a secondary device");
PRINT_MODULE_USAGE_PARAM_COMMENT("The commands 'start', 'readtest' and 'rwtest' have an optional instance index:");
PRINT_MODULE_USAGE_PARAM_INT('i', 0, 0, 1, "storage index (if the board has multiple storages)", true);
PRINT_MODULE_USAGE_PARAM_COMMENT("The commands 'start', 'readtest', 'rwtest' and 'erase' have an optional parameter:");
PRINT_MODULE_USAGE_ARG("<partition_name1> [<partition_name2> ...]",
@ -146,32 +179,46 @@ static void print_usage(void)
int mtd_main(int argc, char *argv[])
{
if (argc >= 2) {
int instance = 0;
int partition_index = 2;
if (argc > 3 && !strcmp(argv[2], "-i")) {
instance = strtol(argv[3], nullptr, 10);
if (instance < 0 || instance >= num_instances) {
PX4_ERR("invalid instance");
return -1;
}
partition_index += 2;
}
if (!strcmp(argv[1], "start")) {
/* start mapping according to user request */
if (argc >= 3) {
return mtd_start((const char **)(argv + 2), argc - 2);
if (argc > partition_index) {
return mtd_start(instances[instance], (const char **)(argv + partition_index), argc - partition_index);
} else {
return mtd_start(partition_names_default, n_partitions_default);
return mtd_start(instances[instance], partition_names_default, n_partitions_default);
}
}
if (!strcmp(argv[1], "readtest")) {
if (argc >= 3) {
return mtd_readtest((const char **)(argv + 2), argc - 2);
if (argc > partition_index) {
return mtd_readtest(instances[instance], (const char **)(argv + partition_index), argc - partition_index);
} else {
return mtd_readtest(partition_names_default, n_partitions_default);
return mtd_readtest(instances[instance], partition_names_default, n_partitions_default);
}
}
if (!strcmp(argv[1], "rwtest")) {
if (argc >= 3) {
return mtd_rwtest((const char **)(argv + 2), argc - 2);
if (argc > partition_index) {
return mtd_rwtest(instances[instance], (const char **)(argv + partition_index), argc - partition_index);
} else {
return mtd_rwtest(partition_names_default, n_partitions_default);
return mtd_rwtest(instances[instance], partition_names_default, n_partitions_default);
}
}
@ -180,13 +227,17 @@ int mtd_main(int argc, char *argv[])
}
if (!strcmp(argv[1], "erase")) {
if (argc >= 3) {
return mtd_erase((const char **)(argv + 2), argc - 2);
if (argc > partition_index) {
return mtd_erase((const char **)(argv + partition_index), argc - partition_index);
} else {
return mtd_erase(partition_names_default, n_partitions_default);
}
}
if (!strcmp(argv[1], "has-secondary")) {
return num_instances > 1 ? 0 : 1;
}
}
print_usage();
@ -199,7 +250,7 @@ struct mtd_dev_s *mtd_partition(FAR struct mtd_dev_s *mtd,
#ifdef CONFIG_MTD_RAMTRON
static int
ramtron_attach(void)
ramtron_attach(mtd_instance_s &instance)
{
/* initialize the right spi */
struct spi_dev_s *spi = px4_spibus_initialize(px4_find_spi_bus(SPIDEV_FLASH(0)));
@ -218,9 +269,9 @@ ramtron_attach(void)
/* start the RAMTRON driver, attempt 5 times */
for (int i = 0; i < 5; i++) {
mtd_dev = ramtron_initialize(spi);
instance.mtd_dev = ramtron_initialize(spi);
if (mtd_dev) {
if (instance.mtd_dev) {
/* abort on first valid result */
if (i > 0) {
PX4_WARN("mtd needed %d attempts to attach", i + 1);
@ -231,12 +282,12 @@ ramtron_attach(void)
}
/* if last attempt is still unsuccessful, abort */
if (mtd_dev == nullptr) {
if (instance.mtd_dev == nullptr) {
PX4_ERR("failed to initialize mtd driver");
return 1;
}
int ret = mtd_dev->ioctl(mtd_dev, MTDIOC_SETSPEED, (unsigned long)10 * 1000 * 1000);
int ret = instance.mtd_dev->ioctl(instance.mtd_dev, MTDIOC_SETSPEED, (unsigned long)10 * 1000 * 1000);
if (ret != OK) {
// FIXME: From the previous warning call, it looked like this should have been fatal error instead. Tried
@ -245,13 +296,15 @@ ramtron_attach(void)
PX4_WARN("failed to set bus speed");
}
attached = true;
instance.attached = true;
return 0;
}
#else
#endif
#ifdef PX4_I2C_BUS_MTD
static int
at24xxx_attach(void)
at24xxx_attach(mtd_instance_s &instance)
{
/* find the right I2C */
struct i2c_master_s *i2c = px4_i2cbus_initialize(PX4_I2C_BUS_MTD);
@ -263,9 +316,9 @@ at24xxx_attach(void)
/* start the MTD driver, attempt 5 times */
for (int i = 0; i < 5; i++) {
mtd_dev = at24c_initialize(i2c);
instance.mtd_dev = at24c_initialize(i2c);
if (mtd_dev) {
if (instance.mtd_dev) {
/* abort on first valid result */
if (i > 0) {
PX4_WARN("EEPROM needed %d attempts to attach", i + 1);
@ -276,47 +329,44 @@ at24xxx_attach(void)
}
/* if last attempt is still unsuccessful, abort */
if (mtd_dev == nullptr) {
if (instance.mtd_dev == nullptr) {
PX4_ERR("failed to initialize EEPROM driver");
return 1;
}
attached = true;
instance.attached = true;
return 0;
}
#endif
static int
mtd_start(const char *partition_names[], unsigned n_partitions)
mtd_start(mtd_instance_s &instance, const char *partition_names[], unsigned n_partitions)
{
int ret;
if (started) {
if (instance.started) {
PX4_ERR("mtd already mounted");
return 1;
}
if (!attached) {
#ifdef CONFIG_MTD_RAMTRON
ret = ramtron_attach();
#else
ret = at24xxx_attach();
#endif
if (!instance.attached) {
ret = instance.attach(instance);
if (ret != 0) {
return ret;
}
}
if (!mtd_dev) {
PX4_ERR("Failed to create RAMTRON FRAM MTD instance");
if (!instance.mtd_dev) {
PX4_ERR("Failed to create MTD instance");
return 1;
}
unsigned long blocksize, erasesize, neraseblocks;
unsigned blkpererase, nblocks, partsize;
ret = mtd_get_geometry(&blocksize, &erasesize, &neraseblocks, &blkpererase, &nblocks, &partsize, n_partitions);
instance.n_partitions_current = n_partitions;
ret = mtd_get_geometry(instance, &blocksize, &erasesize, &neraseblocks, &blkpererase, &nblocks, &partsize);
if (ret) {
return ret;
@ -334,7 +384,7 @@ mtd_start(const char *partition_names[], unsigned n_partitions)
/* Create the partition */
part[i] = mtd_partition(mtd_dev, offset, nblocks);
part[i] = mtd_partition(instance.mtd_dev, offset, nblocks);
if (!part[i]) {
PX4_ERR("mtd_partition failed. offset=%lu nblocks=%lu",
@ -344,13 +394,21 @@ mtd_start(const char *partition_names[], unsigned n_partitions)
/* Initialize to provide an FTL block driver on the MTD FLASH interface */
snprintf(blockname, sizeof(blockname), "/dev/mtdblock%d", i);
ret = -1;
ret = ftl_initialize(i, part[i]);
for (int dev_index = 0; ret != 0; ++dev_index) {
snprintf(blockname, sizeof(blockname), "/dev/mtdblock%d", i + dev_index);
if (ret < 0) {
PX4_ERR("ftl_initialize %s failed: %d", blockname, ret);
return 1;
ret = ftl_initialize(i + dev_index, part[i]);
if (ret == -EEXIST) {
continue;
}
if (ret < 0 || dev_index >= 9) {
PX4_ERR("ftl_initialize %s failed: %d", blockname, ret);
return 1;
}
}
/* Now create a character device on the block device */
@ -363,20 +421,19 @@ mtd_start(const char *partition_names[], unsigned n_partitions)
}
}
n_partitions_current = n_partitions;
started = true;
instance.started = true;
return 0;
}
int mtd_get_geometry(unsigned long *blocksize, unsigned long *erasesize, unsigned long *neraseblocks,
unsigned *blkpererase, unsigned *nblocks, unsigned *partsize, unsigned n_partitions)
int mtd_get_geometry(const mtd_instance_s &instance, unsigned long *blocksize, unsigned long *erasesize,
unsigned long *neraseblocks,
unsigned *blkpererase, unsigned *nblocks, unsigned *partsize)
{
/* Get the geometry of the FLASH device */
FAR struct mtd_geometry_s geo;
int ret = mtd_dev->ioctl(mtd_dev, MTDIOC_GEOMETRY, (unsigned long)((uintptr_t)&geo));
int ret = instance.mtd_dev->ioctl(instance.mtd_dev, MTDIOC_GEOMETRY, (unsigned long)((uintptr_t)&geo));
if (ret < 0) {
PX4_ERR("mtd->ioctl failed: %d", ret);
@ -393,7 +450,7 @@ int mtd_get_geometry(unsigned long *blocksize, unsigned long *erasesize, unsigne
*/
*blkpererase = geo.erasesize / geo.blocksize;
*nblocks = (geo.neraseblocks / n_partitions) * *blkpererase;
*nblocks = (geo.neraseblocks / instance.n_partitions_current) * *blkpererase;
*partsize = *nblocks * geo.blocksize;
return ret;
@ -402,13 +459,12 @@ int mtd_get_geometry(unsigned long *blocksize, unsigned long *erasesize, unsigne
/*
get partition size in bytes
*/
static ssize_t mtd_get_partition_size(void)
static ssize_t mtd_get_partition_size(const mtd_instance_s &instance)
{
unsigned long blocksize, erasesize, neraseblocks;
unsigned blkpererase, nblocks, partsize = 0;
int ret = mtd_get_geometry(&blocksize, &erasesize, &neraseblocks, &blkpererase, &nblocks, &partsize,
n_partitions_current);
int ret = mtd_get_geometry(instance, &blocksize, &erasesize, &neraseblocks, &blkpererase, &nblocks, &partsize);
if (ret != OK) {
PX4_ERR("Failed to get geometry");
@ -418,28 +474,24 @@ static ssize_t mtd_get_partition_size(void)
return partsize;
}
int mtd_print_info(void)
int mtd_print_info(int instance)
{
if (!attached) {
return 1;
}
unsigned long blocksize, erasesize, neraseblocks;
unsigned blkpererase, nblocks, partsize;
int ret = mtd_get_geometry(&blocksize, &erasesize, &neraseblocks, &blkpererase, &nblocks, &partsize,
n_partitions_current);
int ret = mtd_get_geometry(instances[instance], &blocksize, &erasesize, &neraseblocks, &blkpererase, &nblocks,
&partsize);
if (ret) {
return ret;
}
PX4_INFO("Flash Geometry:");
PX4_INFO("Flash Geometry of instance %i:", instance);
printf(" blocksize: %lu\n", blocksize);
printf(" erasesize: %lu\n", erasesize);
printf(" neraseblocks: %lu\n", neraseblocks);
printf(" No. partitions: %u\n", n_partitions_current);
printf(" No. partitions: %u\n", instances[instance].n_partitions_current);
printf(" Partition size: %u Blocks (%u bytes)\n", nblocks, partsize);
printf(" TOTAL SIZE: %u KiB\n", neraseblocks * erasesize / 1024);
@ -479,9 +531,9 @@ mtd_erase(const char *partition_names[], unsigned n_partitions)
bad reads (the ramtron driver does return an error)
*/
int
mtd_readtest(const char *partition_names[], unsigned n_partitions)
mtd_readtest(const mtd_instance_s &instance, const char *partition_names[], unsigned n_partitions)
{
ssize_t expected_size = mtd_get_partition_size();
ssize_t expected_size = mtd_get_partition_size(instance);
if (expected_size == 0) {
return 1;
@ -522,9 +574,9 @@ mtd_readtest(const char *partition_names[], unsigned n_partitions)
data isn't the same
*/
int
mtd_rwtest(const char *partition_names[], unsigned n_partitions)
mtd_rwtest(const mtd_instance_s &instance, const char *partition_names[], unsigned n_partitions)
{
ssize_t expected_size = mtd_get_partition_size();
ssize_t expected_size = mtd_get_partition_size(instance);
if (expected_size == 0) {
return 1;