linux/drivers/mtd/chips/fwh_lock.h
Adrian Hunter 69423d99fc [MTD] update internal API to support 64-bit device size
MTD internal API presently uses 32-bit values to represent
device size.  This patch updates them to 64-bits but leaves
the external API unchanged.  Extending the external API
is a separate issue for several reasons.  First, no one
needs it at the moment.  Secondly, whether the implementation
is done with IOCTLs, sysfs or both is still debated.  Thirdly
external API changes require the internal API to be accepted
first.

Note that although the MTD API will be able to support 64-bit
device sizes, existing drivers do not and are not required
to do so, although NAND base has been updated.

In general, changing from 32-bit to 64-bit values cause little
or no changes to the majority of the code with the following
exceptions:
    	- printk message formats
    	- division and modulus of 64-bit values
    	- NAND base support
	- 32-bit local variables used by mtdpart and mtdconcat
	- naughtily assuming one structure maps to another
	in MEMERASE ioctl

Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
2008-12-10 13:37:21 +00:00

109 lines
2.8 KiB
C

#ifndef FWH_LOCK_H
#define FWH_LOCK_H
enum fwh_lock_state {
FWH_UNLOCKED = 0,
FWH_DENY_WRITE = 1,
FWH_IMMUTABLE = 2,
FWH_DENY_READ = 4,
};
struct fwh_xxlock_thunk {
enum fwh_lock_state val;
flstate_t state;
};
#define FWH_XXLOCK_ONEBLOCK_LOCK ((struct fwh_xxlock_thunk){ FWH_DENY_WRITE, FL_LOCKING})
#define FWH_XXLOCK_ONEBLOCK_UNLOCK ((struct fwh_xxlock_thunk){ FWH_UNLOCKED, FL_UNLOCKING})
/*
* This locking/unlock is specific to firmware hub parts. Only one
* is known that supports the Intel command set. Firmware
* hub parts cannot be interleaved as they are on the LPC bus
* so this code has not been tested with interleaved chips,
* and will likely fail in that context.
*/
static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip,
unsigned long adr, int len, void *thunk)
{
struct cfi_private *cfi = map->fldrv_priv;
struct fwh_xxlock_thunk *xxlt = (struct fwh_xxlock_thunk *)thunk;
int ret;
/* Refuse the operation if the we cannot look behind the chip */
if (chip->start < 0x400000) {
DEBUG( MTD_DEBUG_LEVEL3,
"MTD %s(): chip->start: %lx wanted >= 0x400000\n",
__func__, chip->start );
return -EIO;
}
/*
* lock block registers:
* - on 64k boundariesand
* - bit 1 set high
* - block lock registers are 4MiB lower - overflow subtract (danger)
*
* The address manipulation is first done on the logical address
* which is 0 at the start of the chip, and then the offset of
* the individual chip is addted to it. Any other order a weird
* map offset could cause problems.
*/
adr = (adr & ~0xffffUL) | 0x2;
adr += chip->start - 0x400000;
/*
* This is easy because these are writes to registers and not writes
* to flash memory - that means that we don't have to check status
* and timeout.
*/
spin_lock(chip->mutex);
ret = get_chip(map, chip, adr, FL_LOCKING);
if (ret) {
spin_unlock(chip->mutex);
return ret;
}
chip->oldstate = chip->state;
chip->state = xxlt->state;
map_write(map, CMD(xxlt->val), adr);
/* Done and happy. */
chip->state = chip->oldstate;
put_chip(map, chip, adr);
spin_unlock(chip->mutex);
return 0;
}
static int fwh_lock_varsize(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
int ret;
ret = cfi_varsize_frob(mtd, fwh_xxlock_oneblock, ofs, len,
(void *)&FWH_XXLOCK_ONEBLOCK_LOCK);
return ret;
}
static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
int ret;
ret = cfi_varsize_frob(mtd, fwh_xxlock_oneblock, ofs, len,
(void *)&FWH_XXLOCK_ONEBLOCK_UNLOCK);
return ret;
}
static void fixup_use_fwh_lock(struct mtd_info *mtd, void *param)
{
printk(KERN_NOTICE "using fwh lock/unlock method\n");
/* Setup for the chips with the fwh lock method */
mtd->lock = fwh_lock_varsize;
mtd->unlock = fwh_unlock_varsize;
}
#endif /* FWH_LOCK_H */