Is there any interest in providing a query lock to go with lock and unlock?
Richard J. Broberg
rjb at ayrnetworks.com
Mon Aug 5 11:19:40 EDT 2002
We have a parochial need which I have met in a heavy
handed way by adding a mtd vector and an ioctl.
The files changed in our 2.4.16 kernel are
drivers/mtd/mtdchar.c
drivers/mtd/chips/amd_flash.c
drivers/mtd/chips/cfi_cmdset_0001.c
include/linux/mtd/mtd.h
If somebody has a less invasive way, I would love to hear
about it.
If some others find this approach useful, I will try to get an
acceptable patch.
Thanks,
Dick Broberg
===================================================================
RCS file: /cvs/public/linux/drivers/mtd/mtdchar.c,v
retrieving revision 1.3
diff -c -b -B -r1.3 mtdchar.c
*** drivers/mtd/mtdchar.c 2002/04/16 20:01:07 1.3
--- drivers/mtd/mtdchar.c 2002/08/01 21:08:33
***************
*** 282,287 ****
--- 282,323 ----
break;
}
+ case MEMGETREGIONLOCKS:
+ {
+ int blocks,i,es;
+ char *stati;
+ struct region_info_lock ul;
+
+ if (copy_from_user( &ul,
+ (struct region_info_lock *)arg,
+ sizeof(struct region_info_lock))) {
+ ret = -EFAULT;
+ } else if (ul.regionindex >= mtd->numeraseregions) {
+ ret = -EINVAL;
+ } else {
+ blocks = mtd->eraseregions[ul.regionindex].numblocks;
+ es = mtd->eraseregions[ul.regionindex].erasesize;
+ stati = kmalloc(blocks,GFP_KERNEL);
+ if (!stati) {
+ ret = -ENOMEM;
+ } else {
+ memset(stati,0,blocks);
+ if (mtd->is_it_locked) {
+ for (i = 0; i < blocks; i++) {
+ stati[i] = mtd->is_it_locked(mtd,
+ i * es,
+ es);
+ }
+ }
+ if (copy_to_user(ul.block_stati,stati,blocks)) {
+ ret = -EFAULT;
+ }
+ kfree(stati);
+ }
+ }
+ break;
+ }
+
case MEMGETINFO:
if (copy_to_user((struct mtd_info *)arg, mtd,
sizeof(struct mtd_info_user)))
Index: drivers/mtd/chips/amd_flash.c
===================================================================
RCS file: /cvs/public/linux/drivers/mtd/chips/amd_flash.c,v
retrieving revision 1.2
diff -c -b -B -r1.2 amd_flash.c
*** drivers/mtd/chips/amd_flash.c 2002/03/15 00:29:21 1.2
--- drivers/mtd/chips/amd_flash.c 2002/08/01 21:08:33
***************
*** 295,300 ****
--- 295,332 ----
return amd_flash_do_unlock(mtd, ofs, len, 1);
}
+ static int amd_flash_is_it_locked(struct mtd_info *mtd, loff_t ofs, size_t len)
+ {
+ struct map_info *map = mtd->priv;
+ struct mtd_erase_region_info *merip;
+ int eraseoffset, erasesize, eraseblocks;
+ int i;
+ int lock_status = 0;
+
+ /* Pass the whole chip through sector by sector and check for each
+ sector if the sector and the given interval overlap */
+ for(i = 0; i < mtd->numeraseregions; i++) {
+ merip = &mtd->eraseregions[i];
+
+ eraseoffset = merip->offset;
+ erasesize = merip->erasesize;
+ eraseblocks = merip->numblocks;
+
+ if (ofs > eraseoffset + erasesize)
+ continue;
+ while (eraseblocks > 0) {
+ if (ofs < eraseoffset + erasesize && ofs + len > eraseoffset) {
+ lock_status = is_sector_locked(map, eraseoffset);
+ goto have_lock_status;
+ }
+ eraseoffset += erasesize;
+ eraseblocks --;
+ }
+ }
+ have_lock_status:
+ return lock_status;
+ }
+
static int amd_flash_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
{
return amd_flash_do_unlock(mtd, ofs, len, 0);
***************
*** 748,753 ****
--- 780,786 ----
mtd->resume = amd_flash_resume;
mtd->lock = amd_flash_lock;
mtd->unlock = amd_flash_unlock;
+ mtd->is_it_locked = amd_flash_is_it_locked;
private = kmalloc(sizeof(*private) + (sizeof(struct flchip) *
temp.numchips), GFP_KERNEL);
Index: drivers/mtd/chips/cfi_cmdset_0001.c
===================================================================
RCS file: /cvs/public/linux/drivers/mtd/chips/cfi_cmdset_0001.c,v
retrieving revision 1.3
diff -c -b -B -r1.3 cfi_cmdset_0001.c
*** drivers/mtd/chips/cfi_cmdset_0001.c 2002/03/27 23:35:42 1.3
--- drivers/mtd/chips/cfi_cmdset_0001.c 2002/08/01 21:08:33
***************
*** 51,56 ****
--- 51,57 ----
struct mtd_info *cfi_cmdset_0001(struct map_info *, int);
static struct mtd_info *cfi_intelext_setup (struct map_info *);
+ static int cfi_is_it_locked(struct mtd_info *mtd, loff_t ofs, size_t len);
static struct mtd_chip_driver cfi_intelext_chipdrv = {
probe: NULL, /* Not usable directly */
***************
*** 264,269 ****
--- 265,271 ----
mtd->sync = cfi_intelext_sync;
mtd->lock = cfi_intelext_lock;
mtd->unlock = cfi_intelext_unlock;
+ mtd->is_it_locked = cfi_is_it_locked;
mtd->suspend = cfi_intelext_suspend;
mtd->resume = cfi_intelext_resume;
mtd->flags = MTD_CAP_NORFLASH;
***************
*** 1067,1084 ****
return 0;
}
-
- typedef int (*varsize_frob_t)(struct map_info *map, struct flchip *chip,
- unsigned long adr, void *thunk);
! static int cfi_intelext_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
! loff_t ofs, size_t len, void *thunk)
{
! struct map_info *map = mtd->priv;
! struct cfi_private *cfi = map->fldrv_priv;
! unsigned long adr;
! int chipnum, ret = 0;
! int i, first;
struct mtd_erase_region_info *regions = mtd->eraseregions;
if (ofs > mtd->size)
--- 1068,1077 ----
return 0;
}
! static int get_region_index(struct mtd_info *mtd, loff_t ofs, size_t len, int *first)
{
! int i;
struct mtd_erase_region_info *regions = mtd->eraseregions;
if (ofs > mtd->size)
***************
*** 1087,1101 ****
if ((len + ofs) > mtd->size)
return -EINVAL;
! /* Check that both start and end of the requested erase are
* aligned with the erasesize at the appropriate addresses.
*/
i = 0;
! /* Skip all erase regions which are ended before the start of
! the requested erase. Actually, to save on the calculations,
! we skip to the first erase region which starts after the
start of the requested erase, and then go back one.
*/
--- 1079,1093 ----
if ((len + ofs) > mtd->size)
return -EINVAL;
! /* Check that both start and end of the requested region are
* aligned with the erasesize at the appropriate addresses.
*/
i = 0;
! /* Skip all regions which are ended before the start of
! the requested region. Actually, to save on the calculations,
! we skip to the first region which starts after the
start of the requested erase, and then go back one.
*/
***************
*** 1104,1111 ****
i--;
/* OK, now i is pointing at the erase region in which this
! erase request starts. Check the start of the requested
! erase range is aligned with the erase size which is in
effect here.
*/
--- 1096,1103 ----
i--;
/* OK, now i is pointing at the erase region in which this
! request starts. Check the start of the requested
! range is aligned with the erase size which is in
effect here.
*/
***************
*** 1113,1121 ****
return -EINVAL;
/* Remember the erase region we start on */
! first = i;
! /* Next, check that the end of the requested erase is aligned
* with the erase region at that address.
*/
--- 1105,1115 ----
return -EINVAL;
/* Remember the erase region we start on */
!
! if (first)
! *first = i;
! /* Next, check that the end of the request is aligned
* with the erase region at that address.
*/
***************
*** 1129,1135 ****
--- 1123,1147 ----
if ((ofs + len) & (regions[i].erasesize-1))
return -EINVAL;
+ return i;
+ }
+
+ typedef int (*varsize_frob_t)(struct map_info *map, struct flchip *chip,
+ unsigned long adr, void *thunk);
+
+ static int cfi_intelext_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
+ loff_t ofs, size_t len, void *thunk)
+ {
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+ unsigned long adr;
+ int chipnum, ret = 0;
+ int i, first;
+ struct mtd_erase_region_info *regions = mtd->eraseregions;
+ if (0 > (i = get_region_index(mtd,ofs,len,&first)))
+ return i;
+
chipnum = ofs >> cfi->chipshift;
adr = ofs - (chipnum << cfi->chipshift);
***************
*** 1401,1406 ****
--- 1413,1441 ----
}
}
+ static int cfi_is_it_locked(struct mtd_info *mtd, loff_t ofs, size_t len)
+ {
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+ int ofs_factor = cfi->interleave *
+ cfi->device_type;
+ unsigned long adr;
+ int chipnum;
+ int i;
+ int flags = 0;
+
+ if (0 > (i = get_region_index(mtd,ofs,len,0)))
+ return i;
+
+ chipnum = ofs >> cfi->chipshift;
+ adr = ofs - (chipnum << cfi->chipshift);
+
+ cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+ flags = cfi_read_query(map, adr+(2*ofs_factor));
+ cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+ return flags;
+ }
+
#ifdef DEBUG_LOCK_BITS
static int do_printlockstatus_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
{
***************
*** 1451,1457 ****
/* Urgh. Chip not yet ready to talk to us. */
if (time_after(jiffies, timeo)) {
spin_unlock_bh(chip->mutex);
! printk(KERN_ERR __FUNCTION__ ": waiting for chip to be ready timed out\n");
return -EIO;
}
--- 1486,1494 ----
/* Urgh. Chip not yet ready to talk to us. */
if (time_after(jiffies, timeo)) {
spin_unlock_bh(chip->mutex);
! printk(KERN_ERR
! "%s: waiting for chip to be ready timed out\n",
! __FUNCTION__);
return -EIO;
}
Index: include/linux/mtd/mtd.h
===================================================================
RCS file: /cvs/public/linux/include/linux/mtd/mtd.h,v
retrieving revision 1.4
diff -c -b -B -r1.4 mtd.h
*** include/linux/mtd/mtd.h 2002/04/16 20:00:29 1.4
--- include/linux/mtd/mtd.h 2002/08/01 21:08:33
***************
*** 85,90 ****
--- 85,95 ----
u_int32_t regionindex;
};
+ struct region_info_lock {
+ u_int32_t regionindex;
+ u_char *block_stati;
+ };
+
#define MEMGETINFO _IOR('M', 1, struct mtd_info_user)
#define MEMERASE _IOW('M', 2, struct erase_info_user)
#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf)
***************
*** 93,98 ****
--- 98,104 ----
#define MEMUNLOCK _IOW('M', 6, struct erase_info_user)
#define MEMGETREGIONCOUNT _IOR('M', 7, int)
#define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user)
+ #define MEMGETREGIONLOCKS _IOWR('M', 9, struct region_info_lock)
#ifndef __KERNEL__
***************
*** 207,212 ****
--- 213,219 ----
/* Chip-supported device locking */
int (*lock) (struct mtd_info *mtd, loff_t ofs, size_t len);
int (*unlock) (struct mtd_info *mtd, loff_t ofs, size_t len);
+ int (*is_it_locked) (struct mtd_info *mtd, loff_t ofs, size_t len);
/* Power Management functions */
int (*suspend) (struct mtd_info *mtd);
More information about the linux-mtd
mailing list