ONFI parameters are little-endian, hence we must take care to convert them

to native endianness.  We must also pay attention to unaligned accesses.

Copy the interesting parameters to a new struct so the rest of the code can
forget about these problems.

Submitted by:	Kristof Provost <kristof@sigsegv.be> (cleanup) and me (orig).
This commit is contained in:
Ian Lepore 2013-11-15 23:41:32 +00:00
parent 1b45c6cd53
commit c3c04faa3a
3 changed files with 48 additions and 21 deletions

View File

@ -115,7 +115,7 @@ nand_init(struct nand_softc *nand, device_t dev, int ecc_mode,
}
void
nand_onfi_set_params(struct nand_chip *chip, struct onfi_params *params)
nand_onfi_set_params(struct nand_chip *chip, struct onfi_chip_params *params)
{
struct chip_geom *cg;

View File

@ -235,6 +235,20 @@ struct onfi_params {
}__attribute__((packed));
CTASSERT(sizeof(struct onfi_params) == 256);
struct onfi_chip_params {
uint8_t luns;
uint32_t blocks_per_lun;
uint32_t pages_per_block;
uint32_t bytes_per_page;
uint32_t spare_bytes_per_page;
uint16_t t_bers;
uint16_t t_prog;
uint16_t t_r;
uint16_t t_ccs;
uint16_t features;
uint8_t address_cycles;
};
struct nand_ecc_data {
int eccsize; /* Number of data bytes per ECC step */
int eccmode;
@ -367,7 +381,7 @@ void nand_init(struct nand_softc *nand, device_t dev, int ecc_mode,
void nand_detach(struct nand_softc *nand);
struct nand_params *nand_get_params(struct nand_id *id);
void nand_onfi_set_params(struct nand_chip *chip, struct onfi_params *params);
void nand_onfi_set_params(struct nand_chip *chip, struct onfi_chip_params *params);
void nand_set_params(struct nand_chip *chip, struct nand_params *params);
int nand_init_stat(struct nand_chip *chip);
void nand_destroy_stat(struct nand_chip *chip);

View File

@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/endian.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/rman.h>
@ -73,7 +74,7 @@ static int small_program_page(device_t, uint32_t, void *, uint32_t, uint32_t);
static int small_program_oob(device_t, uint32_t, void *, uint32_t, uint32_t);
static int onfi_is_blk_bad(device_t, uint32_t, uint8_t *);
static int onfi_read_parameter(struct nand_chip *, struct onfi_params *);
static int onfi_read_parameter(struct nand_chip *, struct onfi_chip_params *);
static int nand_send_address(device_t, int32_t, int32_t, int8_t);
@ -206,7 +207,7 @@ generic_nand_attach(device_t dev)
{
struct nand_chip *chip;
struct nandbus_ivar *ivar;
struct onfi_params *onfi_params;
struct onfi_chip_params *onfi_chip_params;
device_t nandbus, nfc;
int err;
@ -225,25 +226,24 @@ generic_nand_attach(device_t dev)
chip->nand = device_get_softc(nfc);
if (ivar->is_onfi) {
onfi_params = malloc(sizeof(struct onfi_params),
onfi_chip_params = malloc(sizeof(struct onfi_chip_params),
M_NAND, M_WAITOK | M_ZERO);
if (onfi_params == NULL)
return (ENXIO);
if (onfi_chip_params == NULL)
return (ENOMEM);
if (onfi_read_parameter(chip, onfi_params)) {
if (onfi_read_parameter(chip, onfi_chip_params)) {
nand_debug(NDBG_GEN,"Could not read parameter page!\n");
free(onfi_params, M_NAND);
free(onfi_chip_params, M_NAND);
return (ENXIO);
}
nand_onfi_set_params(chip, onfi_params);
nand_onfi_set_params(chip, onfi_chip_params);
/* Set proper column and row cycles */
ivar->cols = (onfi_params->address_cycles >> 4) & 0xf;
ivar->rows = onfi_params->address_cycles & 0xf;
free(onfi_params, M_NAND);
ivar->cols = (onfi_chip_params->address_cycles >> 4) & 0xf;
ivar->rows = onfi_chip_params->address_cycles & 0xf;
free(onfi_chip_params, M_NAND);
} else {
nand_set_params(chip, ivar->params);
}
@ -340,9 +340,10 @@ onfi_crc(const void *buf, size_t buflen)
}
static int
onfi_read_parameter(struct nand_chip *chip, struct onfi_params *params)
onfi_read_parameter(struct nand_chip *chip, struct onfi_chip_params *chip_params)
{
device_t nandbus;
struct onfi_params params;
int found, sigcount, trycopy;
nand_debug(NDBG_GEN,"read parameter");
@ -373,20 +374,32 @@ onfi_read_parameter(struct nand_chip *chip, struct onfi_params *params)
* rule that the signature is valid if any 2 of the 4 bytes are correct.
*/
for (found= 0, trycopy = 0; !found && trycopy < 3; trycopy++) {
NANDBUS_READ_BUFFER(nandbus, params, sizeof(struct onfi_params));
sigcount = params->signature[0] == 'O';
sigcount += params->signature[1] == 'N';
sigcount += params->signature[2] == 'F';
sigcount += params->signature[3] == 'I';
NANDBUS_READ_BUFFER(nandbus, &params, sizeof(struct onfi_params));
sigcount = params.signature[0] == 'O';
sigcount += params.signature[1] == 'N';
sigcount += params.signature[2] == 'F';
sigcount += params.signature[3] == 'I';
if (sigcount < 2)
continue;
if (onfi_crc(params, 254) != params->crc)
if (onfi_crc(&params, 254) != params.crc)
continue;
found = 1;
}
if (!found)
return (ENXIO);
chip_params->luns = params.luns;
chip_params->blocks_per_lun = le32dec(&params.blocks_per_lun);
chip_params->pages_per_block = le32dec(&params.pages_per_block);
chip_params->bytes_per_page = le32dec(&params.bytes_per_page);
chip_params->spare_bytes_per_page = le32dec(&params.spare_bytes_per_page);
chip_params->t_bers = le16dec(&params.t_bers);
chip_params->t_prog = le16dec(&params.t_prog);
chip_params->t_r = le16dec(&params.t_r);
chip_params->t_ccs = le16dec(&params.t_ccs);
chip_params->features = le16dec(&params.features);
chip_params->address_cycles = params.address_cycles;
return (0);
}