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. Regards, Peter >> + DEFINE_PROP_END_OF_LIST(), >> +};