On Thu, Sep 20, 2012 at 1:37 AM, Peter Crosthwaite <peter.crosthwa...@petalogix.com> wrote: > On Thu, Sep 20, 2012 at 4:25 AM, Blue Swirl <blauwir...@gmail.com> wrote: >> On Tue, Sep 18, 2012 at 2:11 AM, Peter A. G. Crosthwaite >>> + int64_t dirty_page; >>> + >>> + uint64_t waddr; >>> + int write_enable; >>> + >>> + char *part_name; >> >> With 'const char *' here.. >> >>> + const FlashPartInfo *pi; >>> + >>> +} Flash; >>> + >>> +static void bdrv_sync_complete(void *opaque, int ret) >>> +{ >>> + /* do nothing. Masters do not directly interact with the backing store, >>> + * only the working copy so no mutexing required. >>> + */ >>> +} >>> + >>> +static void flash_sync_page(Flash *s, int page) >>> +{ >>> + if (s->bdrv) { >>> + int bdrv_sector, nb_sectors; >>> + QEMUIOVector iov; >>> + >>> + bdrv_sector = (page * s->pi->page_size) / BDRV_SECTOR_SIZE; >>> + nb_sectors = DIV_ROUND_UP(s->pi->page_size, BDRV_SECTOR_SIZE); >>> + qemu_iovec_init(&iov, 1); >>> + qemu_iovec_add(&iov, s->storage + bdrv_sector * BDRV_SECTOR_SIZE, >>> + nb_sectors * >>> BDRV_SECTOR_SIZE); >>> + bdrv_aio_writev(s->bdrv, bdrv_sector, &iov, nb_sectors, >>> + bdrv_sync_complete, NULL); >>> + } >>> +} >>> + >>> +static inline void flash_sync_area(Flash *s, int64_t off, int64_t len) >>> +{ >>> + int64_t start, end; >>> + int nb_sectors; >>> + QEMUIOVector iov; >>> + >>> + if (!s->bdrv) { >>> + return; >>> + } >>> + >>> + assert(!(len % BDRV_SECTOR_SIZE)); >>> + start = off / BDRV_SECTOR_SIZE; >>> + end = (off + len) / BDRV_SECTOR_SIZE; >>> + nb_sectors = end - start; >>> + qemu_iovec_init(&iov, 1); >>> + qemu_iovec_add(&iov, s->storage + (start * BDRV_SECTOR_SIZE), >>> + nb_sectors * BDRV_SECTOR_SIZE); >>> + bdrv_aio_writev(s->bdrv, start, &iov, nb_sectors, bdrv_sync_complete, >>> NULL); >>> +} >>> + >>> +static void flash_erase(Flash *s, int offset, FlashCMD cmd) >>> +{ >>> + uint32_t len; >>> + uint8_t capa_to_assert = 0; >>> + >>> + switch (cmd) { >>> + case ERASE_4K: >>> + len = 4 << 10; >>> + capa_to_assert = ER_4K; >>> + break; >>> + case ERASE_32K: >>> + len = 32 << 10; >>> + capa_to_assert = ER_32K; >>> + break; >>> + case ERASE_SECTOR: >>> + len = s->pi->sector_size; >>> + break; >>> + case BULK_ERASE: >>> + len = s->size; >>> + default: >>> + assert(false); >>> + } >>> + >>> + DB_PRINT("offset = %#x, len = %d\n", offset, len); >>> + if ((s->pi->flags & capa_to_assert) != capa_to_assert) { >>> + hw_error("m25p80: %dk erase size not supported by device\n", len); >>> + } >>> + >>> + if (!s->write_enable) { >>> + DB_PRINT("erase with write protect!\n"); >>> + return; >>> + } >>> + memset(s->storage + offset, 0xff, len); >>> + flash_sync_area(s, offset, len); >>> +} >>> + >>> +static inline void flash_sync_dirty(Flash *s, int64_t newpage) >>> +{ >>> + if (s->dirty_page >= 0 && s->dirty_page != newpage) { >>> + flash_sync_page(s, s->dirty_page); >>> + s->dirty_page = newpage; >>> + } >>> +} >>> + >>> +static inline >>> +void flash_write8(Flash *s, uint64_t addr, uint8_t data) >>> +{ >>> + int64_t page = addr / s->pi->page_size; >>> + uint8_t prev = s->storage[s->waddr]; >>> + >>> + if (!s->write_enable) { >>> + DB_PRINT("write with write protect!\n"); >>> + } >>> + >>> + if ((prev ^ data) & data) { >>> + DB_PRINT("programming zero to one! addr=%lx %x -> %x\n", >>> + addr, prev, data); >>> + } >>> + >>> + if (s->pi->flags & WR_1) { >>> + s->storage[s->waddr] = data; >>> + } else { >>> + s->storage[s->waddr] &= ~data; >>> + } >>> + >>> + flash_sync_dirty(s, page); >>> + s->dirty_page = page; >>> +} >>> + >>> +static void complete_collecting_data(Flash *s) >>> +{ >>> + s->waddr = s->data[0] << 16; >>> + s->waddr |= s->data[1] << 8; >>> + s->waddr |= s->data[2]; >>> + >>> + switch (s->cmd_in_progress) { >>> + case PP: >>> + s->state = STATE_PAGE_PROGRAM; >>> + break; >>> + case READ: >>> + case FAST_READ: >>> + s->state = STATE_READ; >>> + break; >>> + case ERASE_4K: >>> + case ERASE_32K: >>> + case ERASE_SECTOR: >>> + flash_erase(s, s->waddr, s->cmd_in_progress); >>> + break; >>> + default: >>> + break; >>> + } >>> +} >>> + >>> +static void decode_new_cmd(Flash *s, uint32_t value) >>> +{ >>> + s->cmd_in_progress = value; >>> + DB_PRINT("decoded new command:%x\n", value); >>> + >>> + switch (value) { >>> + >>> + case ERASE_4K: >>> + case ERASE_32K: >>> + case ERASE_SECTOR: >>> + case READ: >>> + case PP: >>> + s->needed_bytes = 3; >>> + s->pos = 0; >>> + s->len = 0; >>> + s->state = STATE_COLLECTING_DATA; >>> + break; >>> + >>> + case FAST_READ: >>> + s->needed_bytes = 4; >>> + s->pos = 0; >>> + s->len = 0; >>> + s->state = STATE_COLLECTING_DATA; >>> + break; >>> + >>> + case WRDI: >>> + s->write_enable = 0; >>> + break; >>> + case WREN: >>> + s->write_enable = 1; >>> + break; >>> + >>> + case RDSR: >>> + s->data[0] = (!!s->write_enable) << 1; >>> + s->pos = 0; >>> + s->len = 1;; >>> + s->state = STATE_READING_DATA; >>> + break; >>> + >>> + case JEDEC_READ: >>> + DB_PRINT("populated jedec code\n"); >>> + s->data[0] = (s->pi->jedec >> 16) & 0xff; >>> + s->data[1] = (s->pi->jedec >> 8) & 0xff; >>> + s->data[2] = s->pi->jedec & 0xff; >>> + if (s->pi->ext_jedec) { >>> + s->data[3] = (s->pi->ext_jedec >> 8) & 0xff; >>> + s->data[4] = s->pi->ext_jedec & 0xff; >>> + s->len = 5; >>> + } else { >>> + s->len = 3; >>> + } >>> + s->pos = 0; >>> + s->state = STATE_READING_DATA; >>> + break; >>> + >>> + case BULK_ERASE: >>> + if (s->write_enable) { >>> + DB_PRINT("chip erase\n"); >>> + flash_erase(s, 0, BULK_ERASE); >>> + } else { >>> + DB_PRINT("chip erase with write protect!\n"); >>> + } >>> + break; >>> + case NOP: >>> + break; >>> + default: >>> + DB_PRINT("Unknown cmd %x\n", value); >>> + break; >>> + } >>> +} >>> + >>> +static int m25p80_cs(SSISlave *ss, bool select) >>> +{ >>> + Flash *s = FROM_SSI_SLAVE(Flash, ss); >>> + >>> + if (select) { >>> + s->len = 0; >>> + s->pos = 0; >>> + s->state = STATE_IDLE; >>> + flash_sync_dirty(s, -1); >>> + DB_PRINT("deselect\n"); >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx) >>> +{ >>> + Flash *s = FROM_SSI_SLAVE(Flash, ss); >>> + uint32_t r = 0; >>> + >>> + switch (s->state) { >>> + >>> + case STATE_PAGE_PROGRAM: >>> + DB_PRINT("page program waddr=%lx data=%x\n", s->waddr, >>> (uint8_t)tx); >>> + flash_write8(s, s->waddr, (uint8_t)tx); >>> + s->waddr++; >>> + break; >>> + >>> + case STATE_READ: >>> + r = s->storage[s->waddr]; >>> + DB_PRINT("READ 0x%lx=%x\n", s->waddr, r); >>> + s->waddr = (s->waddr + 1) % s->size; >>> + break; >>> + >>> + case STATE_COLLECTING_DATA: >>> + s->data[s->len] = (uint8_t)tx; >>> + s->len++; >>> + >>> + if (s->len == s->needed_bytes) { >>> + complete_collecting_data(s); >>> + } >>> + break; >>> + >>> + case STATE_READING_DATA: >>> + r = s->data[s->pos]; >>> + s->pos++; >>> + if (s->pos == s->len) { >>> + s->pos = 0; >>> + s->state = STATE_IDLE; >>> + } >>> + break; >>> + >>> + default: >>> + case STATE_IDLE: >>> + decode_new_cmd(s, (uint8_t)tx); >>> + break; >>> + } >>> + >>> + return r; >>> +} >>> + >>> +static int m25p80_init(SSISlave *ss) >>> +{ >>> + DriveInfo *dinfo; >>> + Flash *s = FROM_SSI_SLAVE(Flash, ss); >>> + const FlashPartInfo *i; >>> + >>> + if (!s->part_name) { /* default to actual m25p80 if no partname given >>> */ >>> + s->part_name = (char *)"m25p80"; >> >> ... fishy casts to remove 'const' like this could be avoided. >> > > Doesn't work see comment below, > >>> + } >>> + >>> + i = known_devices; >>> + for (i = known_devices;; i++) { >>> + assert(i); >>> + if (!i->part_name) { >>> + fprintf(stderr, "Unknown SPI flash part: \"%s\"\n", >>> s->part_name); >>> + return 1; >>> + } else if (!strcmp(i->part_name, s->part_name)) { >>> + s->pi = i; >>> + break; >>> + } >>> + } >>> + >>> + s->size = s->pi->sector_size * s->pi->n_sectors; >>> + s->dirty_page = -1; >>> + s->storage = qemu_blockalign(s->bdrv, s->size); >>> + >>> + dinfo = drive_get_next(IF_MTD); >>> + >>> + if (dinfo && dinfo->bdrv) { >>> + int rsize; >>> + >>> + DB_PRINT("Binding to IF_MTD drive\n"); >>> + s->bdrv = dinfo->bdrv; >>> + rsize = MIN(bdrv_getlength(s->bdrv), s->size); >>> + /* FIXME: Move to late init */ >>> + if (bdrv_read(s->bdrv, 0, s->storage, DIV_ROUND_UP(s->size, >>> + BDRV_SECTOR_SIZE))) { >>> + fprintf(stderr, "Failed to initialize SPI flash!\n"); >>> + return 1; >>> + } >>> + } else { >>> + memset(s->storage, 0xFF, s->size); >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +static Property m25p80_properties[] = { >>> + DEFINE_PROP_STRING("partname", Flash, part_name), > > the ->part_name prop is defined here an string object property which > is of type char* and not const char* so if you covert part_name to > const you get this warning: > > hw/m25p80.c:545: error: invalid operands to binary - (have ‘char **’ > and ‘const char **’) > > Its coming from whatever the macro expansion of DEFINE_PROP_STRING is.
OK. Probably DEFINE_PROP_CONST_STRING could be added later for completeness and preserving const purity. > > Regards, > Peter > >>> + DEFINE_PROP_END_OF_LIST(), >>> +};