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