* false otherwise. This feedback may be misleading because users
* may get an "unlocked" status even though a subpart of the region
* is effectively locked.
+ *
+ * If in doubt during development, check-out the debugfs output which tries to
+ * be more user friendly.
*/
struct spi_nor_locking_ops {
int (*lock)(struct spi_nor *nor, loff_t ofs, u64 len);
const struct sfdp_bfpt *bfpt);
void spi_nor_init_default_locking_ops(struct spi_nor *nor);
+bool spi_nor_has_default_locking_ops(struct spi_nor *nor);
void spi_nor_try_unlock_all(struct spi_nor *nor);
void spi_nor_cache_sr_lock_bits(struct spi_nor *nor, u8 *sr);
void spi_nor_set_mtd_locking_ops(struct spi_nor *nor);
return !nor->info->size;
}
+u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor);
+void spi_nor_get_locked_range_sr(struct spi_nor *nor, const u8 *sr, loff_t *ofs, u64 *len);
+bool spi_nor_is_locked_sr(struct spi_nor *nor, loff_t ofs, u64 len, const u8 *sr);
+
#ifdef CONFIG_DEBUG_FS
void spi_nor_debugfs_register(struct spi_nor *nor);
void spi_nor_debugfs_shutdown(void);
// SPDX-License-Identifier: GPL-2.0
#include <linux/debugfs.h>
+#include <linux/math64.h>
#include <linux/mtd/spi-nor.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
static int spi_nor_params_show(struct seq_file *s, void *data)
{
struct spi_nor *nor = s->private;
+ u64 min_prot_len = spi_nor_get_min_prot_length_sr(nor);
struct spi_nor_flash_parameter *params = nor->params;
struct spi_nor_erase_map *erase_map = ¶ms->erase_map;
struct spi_nor_erase_region *region = erase_map->regions;
const struct flash_info *info = nor->info;
char buf[16], *str;
+ loff_t lock_start;
+ u64 lock_length;
unsigned int i;
seq_printf(s, "name\t\t%s\n", info->name);
region[i].overlaid ? "yes" : "no");
}
+ if (!spi_nor_has_default_locking_ops(nor))
+ return 0;
+
+ seq_puts(s, "\nlocked sectors\n");
+ seq_puts(s, " region (in hex) | status | #sectors\n");
+ seq_puts(s, " ------------------+----------+---------\n");
+
+ spi_nor_get_locked_range_sr(nor, nor->dfs_sr_cache, &lock_start, &lock_length);
+ if (!lock_length || lock_length == params->size) {
+ seq_printf(s, " %08llx-%08llx | %s | %llu\n", 0ULL, params->size - 1,
+ lock_length ? " locked" : "unlocked",
+ div_u64(params->size, min_prot_len));
+ } else if (!lock_start) {
+ seq_printf(s, " %08llx-%08llx | %s | %llu\n", 0ULL, lock_length - 1,
+ " locked", div_u64(lock_length, min_prot_len));
+ seq_printf(s, " %08llx-%08llx | %s | %llu\n", lock_length, params->size - 1,
+ "unlocked", div_u64(params->size - lock_length, min_prot_len));
+ } else {
+ seq_printf(s, " %08llx-%08llx | %s | %llu\n", 0ULL, lock_start - 1,
+ "unlocked", div_u64(lock_start, min_prot_len));
+ seq_printf(s, " %08llx-%08llx | %s | %llu\n", lock_start, params->size - 1,
+ " locked", div_u64(lock_length, min_prot_len));
+ }
+
return 0;
}
DEFINE_SHOW_ATTRIBUTE(spi_nor_params);
return 0;
}
-static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor)
+u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor)
{
unsigned int bp_slots, bp_slots_needed;
/*
return sector_size;
}
-static void spi_nor_get_locked_range_sr(struct spi_nor *nor, const u8 *sr, loff_t *ofs,
- u64 *len)
+void spi_nor_get_locked_range_sr(struct spi_nor *nor, const u8 *sr, loff_t *ofs,
+ u64 *len)
{
u64 min_prot_len;
u8 bp_mask = spi_nor_get_sr_bp_mask(nor);
return (ofs >= lock_offs_max) || (offs_max <= lock_offs);
}
-static bool spi_nor_is_locked_sr(struct spi_nor *nor, loff_t ofs, u64 len, const u8 *sr)
+bool spi_nor_is_locked_sr(struct spi_nor *nor, loff_t ofs, u64 len, const u8 *sr)
{
return spi_nor_check_lock_status_sr(nor, ofs, len, sr, true);
}
nor->params->locking_ops = &spi_nor_sr_locking_ops;
}
+bool spi_nor_has_default_locking_ops(struct spi_nor *nor)
+{
+ return nor->params->locking_ops == &spi_nor_sr_locking_ops;
+}
+
static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, u64 len)
{
struct spi_nor *nor = mtd_to_spi_nor(mtd);