diff options
74 files changed, 4247 insertions, 2444 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 894dc43105..310a9512ea 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1623,6 +1623,7 @@ F: cpu.c F: hw/core/cpu.c F: hw/core/machine-qmp-cmds.c F: hw/core/machine.c +F: hw/core/machine-smp.c F: hw/core/null-machine.c F: hw/core/numa.c F: hw/cpu/cluster.c @@ -1632,6 +1633,7 @@ F: include/hw/boards.h F: include/hw/core/cpu.h F: include/hw/cpu/cluster.h F: include/sysemu/numa.h +F: tests/unit/test-smp-parse.c T: git https://gitlab.com/ehabkost/qemu.git machine-next Xtensa Machines diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index db8d83b137..eecd8031cf 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -469,6 +469,7 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp) cpu->kvm_fd = ret; cpu->kvm_state = s; cpu->vcpu_dirty = true; + cpu->dirty_pages = 0; mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0); if (mmap_size < 0) { @@ -743,6 +744,7 @@ static uint32_t kvm_dirty_ring_reap_one(KVMState *s, CPUState *cpu) count++; } cpu->kvm_fetch_index = fetch; + cpu->dirty_pages += count; return count; } @@ -2296,6 +2298,11 @@ bool kvm_vcpu_id_is_valid(int vcpu_id) return vcpu_id >= 0 && vcpu_id < kvm_max_vcpu_id(s); } +bool kvm_dirty_ring_enabled(void) +{ + return kvm_state->kvm_dirty_ring_size ? true : false; +} + static int kvm_init(MachineState *ms) { MachineClass *mc = MACHINE_GET_CLASS(ms); diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c index 5b1d00a222..5319573e00 100644 --- a/accel/stubs/kvm-stub.c +++ b/accel/stubs/kvm-stub.c @@ -147,4 +147,9 @@ bool kvm_arm_supports_user_irq(void) { return false; } + +bool kvm_dirty_ring_enabled(void) +{ + return false; +} #endif diff --git a/dump/dump.c b/dump/dump.c index ab625909f3..662d0a62cd 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -29,6 +29,7 @@ #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "hw/misc/vmcoreinfo.h" +#include "migration/blocker.h" #ifdef TARGET_X86_64 #include "win_dump.h" @@ -47,6 +48,8 @@ #define MAX_GUEST_NOTE_SIZE (1 << 20) /* 1MB should be enough */ +static Error *dump_migration_blocker; + #define ELF_NOTE_SIZE(hdr_size, name_size, desc_size) \ ((DIV_ROUND_UP((hdr_size), 4) + \ DIV_ROUND_UP((name_size), 4) + \ @@ -101,6 +104,7 @@ static int dump_cleanup(DumpState *s) qemu_mutex_unlock_iothread(); } } + migrate_del_blocker(dump_migration_blocker); return 0; } @@ -2005,6 +2009,21 @@ void qmp_dump_guest_memory(bool paging, const char *file, return; } + if (!dump_migration_blocker) { + error_setg(&dump_migration_blocker, + "Live migration disabled: dump-guest-memory in progress"); + } + + /* + * Allows even for -only-migratable, but forbid migration during the + * process of dump guest memory. + */ + if (migrate_add_blocker_internal(dump_migration_blocker, errp)) { + /* Remember to release the fd before passing it over to dump state */ + close(fd); + return; + } + s = &dump_state_global; dump_state_prepare(s); diff --git a/hmp-commands.hx b/hmp-commands.hx index cf723c69ac..3a5aeba3fe 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1737,8 +1737,10 @@ ERST { .name = "calc_dirty_rate", - .args_type = "second:l,sample_pages_per_GB:l?", - .params = "second [sample_pages_per_GB]", - .help = "start a round of guest dirty rate measurement", + .args_type = "dirty_ring:-r,dirty_bitmap:-b,second:l,sample_pages_per_GB:l?", + .params = "[-r] [-b] second [sample_pages_per_GB]", + .help = "start a round of guest dirty rate measurement (using -r to" + "\n\t\t\t specify dirty ring as the method of calculation and" + "\n\t\t\t -b to specify dirty bitmap as method of calculation)", .cmd = hmp_calc_dirty_rate, }, diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c index 167f4d8cb9..355886ee3a 100644 --- a/hw/char/sh_serial.c +++ b/hw/char/sh_serial.c @@ -26,13 +26,17 @@ */ #include "qemu/osdep.h" +#include "hw/sysbus.h" #include "hw/irq.h" +#include "hw/qdev-core.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" #include "hw/sh4/sh.h" #include "chardev/char-fe.h" #include "qapi/error.h" #include "qemu/timer.h" - -//#define DEBUG_SERIAL +#include "qemu/log.h" +#include "trace.h" #define SH_SERIAL_FLAG_TEND (1 << 0) #define SH_SERIAL_FLAG_TDE (1 << 1) @@ -42,10 +46,10 @@ #define SH_RX_FIFO_LENGTH (16) -typedef struct { - MemoryRegion iomem; - MemoryRegion iomem_p4; - MemoryRegion iomem_a7; +OBJECT_DECLARE_SIMPLE_TYPE(SHSerialState, SH_SERIAL) + +struct SHSerialState { + SysBusDevice parent; uint8_t smr; uint8_t brr; uint8_t scr; @@ -59,13 +63,12 @@ typedef struct { uint8_t rx_tail; uint8_t rx_head; - int freq; - int feat; + uint8_t feat; int flags; int rtrg; CharBackend chr; - QEMUTimer *fifo_timeout_timer; + QEMUTimer fifo_timeout_timer; uint64_t etu; /* Elementary Time Unit (ns) */ qemu_irq eri; @@ -73,9 +76,13 @@ typedef struct { qemu_irq txi; qemu_irq tei; qemu_irq bri; -} sh_serial_state; +}; + +typedef struct {} SHSerialStateClass; -static void sh_serial_clear_fifo(sh_serial_state * s) +OBJECT_DEFINE_TYPE(SHSerialState, sh_serial, SH_SERIAL, SYS_BUS_DEVICE) + +static void sh_serial_clear_fifo(SHSerialState *s) { memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH); s->rx_cnt = 0; @@ -86,14 +93,12 @@ static void sh_serial_clear_fifo(sh_serial_state * s) static void sh_serial_write(void *opaque, hwaddr offs, uint64_t val, unsigned size) { - sh_serial_state *s = opaque; + SHSerialState *s = opaque; + DeviceState *d = DEVICE(s); unsigned char ch; -#ifdef DEBUG_SERIAL - printf("sh_serial: write offs=0x%02x val=0x%02x\n", - offs, val); -#endif - switch(offs) { + trace_sh_serial_write(d->id, size, offs, val); + switch (offs) { case 0x00: /* SMR */ s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff); return; @@ -103,8 +108,9 @@ static void sh_serial_write(void *opaque, hwaddr offs, case 0x08: /* SCR */ /* TODO : For SH7751, SCIF mask should be 0xfb. */ s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff); - if (!(val & (1 << 5))) + if (!(val & (1 << 5))) { s->flags |= SH_SERIAL_FLAG_TEND; + } if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) { qemu_set_irq(s->txi, val & (1 << 7)); } @@ -115,8 +121,10 @@ static void sh_serial_write(void *opaque, hwaddr offs, case 0x0c: /* FTDR / TDR */ if (qemu_chr_fe_backend_connected(&s->chr)) { ch = val; - /* XXX this blocks entire thread. Rewrite to use - * qemu_chr_fe_write and background I/O callbacks */ + /* + * XXX this blocks entire thread. Rewrite to use + * qemu_chr_fe_write and background I/O callbacks + */ qemu_chr_fe_write_all(&s->chr, &ch, 1); } s->dr = val; @@ -129,18 +137,23 @@ static void sh_serial_write(void *opaque, hwaddr offs, #endif } if (s->feat & SH_SERIAL_FEAT_SCIF) { - switch(offs) { + switch (offs) { case 0x10: /* FSR */ - if (!(val & (1 << 6))) + if (!(val & (1 << 6))) { s->flags &= ~SH_SERIAL_FLAG_TEND; - if (!(val & (1 << 5))) + } + if (!(val & (1 << 5))) { s->flags &= ~SH_SERIAL_FLAG_TDE; - if (!(val & (1 << 4))) + } + if (!(val & (1 << 4))) { s->flags &= ~SH_SERIAL_FLAG_BRK; - if (!(val & (1 << 1))) + } + if (!(val & (1 << 1))) { s->flags &= ~SH_SERIAL_FLAG_RDF; - if (!(val & (1 << 0))) + } + if (!(val & (1 << 0))) { s->flags &= ~SH_SERIAL_FLAG_DR; + } if (!(val & (1 << 1)) || !(val & (1 << 0))) { if (s->rxi) { @@ -176,9 +189,8 @@ static void sh_serial_write(void *opaque, hwaddr offs, case 0x24: /* LSR */ return; } - } - else { - switch(offs) { + } else { + switch (offs) { #if 0 case 0x0c: ret = s->dr; @@ -192,20 +204,20 @@ static void sh_serial_write(void *opaque, hwaddr offs, return; } } - - fprintf(stderr, "sh_serial: unsupported write to 0x%02" - HWADDR_PRIx "\n", offs); - abort(); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: unsupported write to 0x%02" HWADDR_PRIx "\n", + __func__, offs); } static uint64_t sh_serial_read(void *opaque, hwaddr offs, unsigned size) { - sh_serial_state *s = opaque; - uint32_t ret = ~0; + SHSerialState *s = opaque; + DeviceState *d = DEVICE(s); + uint32_t ret = UINT32_MAX; #if 0 - switch(offs) { + switch (offs) { case 0x00: ret = s->smr; break; @@ -221,7 +233,7 @@ static uint64_t sh_serial_read(void *opaque, hwaddr offs, } #endif if (s->feat & SH_SERIAL_FEAT_SCIF) { - switch(offs) { + switch (offs) { case 0x00: /* SMR */ ret = s->smr; break; @@ -230,29 +242,37 @@ static uint64_t sh_serial_read(void *opaque, hwaddr offs, break; case 0x10: /* FSR */ ret = 0; - if (s->flags & SH_SERIAL_FLAG_TEND) + if (s->flags & SH_SERIAL_FLAG_TEND) { ret |= (1 << 6); - if (s->flags & SH_SERIAL_FLAG_TDE) + } + if (s->flags & SH_SERIAL_FLAG_TDE) { ret |= (1 << 5); - if (s->flags & SH_SERIAL_FLAG_BRK) + } + if (s->flags & SH_SERIAL_FLAG_BRK) { ret |= (1 << 4); - if (s->flags & SH_SERIAL_FLAG_RDF) + } + if (s->flags & SH_SERIAL_FLAG_RDF) { ret |= (1 << 1); - if (s->flags & SH_SERIAL_FLAG_DR) + } + if (s->flags & SH_SERIAL_FLAG_DR) { ret |= (1 << 0); + } - if (s->scr & (1 << 5)) + if (s->scr & (1 << 5)) { s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND; + } break; case 0x14: if (s->rx_cnt > 0) { ret = s->rx_fifo[s->rx_tail++]; s->rx_cnt--; - if (s->rx_tail == SH_RX_FIFO_LENGTH) + if (s->rx_tail == SH_RX_FIFO_LENGTH) { s->rx_tail = 0; - if (s->rx_cnt < s->rtrg) + } + if (s->rx_cnt < s->rtrg) { s->flags &= ~SH_SERIAL_FLAG_RDF; + } } break; case 0x18: @@ -268,9 +288,8 @@ static uint64_t sh_serial_read(void *opaque, hwaddr offs, ret = 0; break; } - } - else { - switch(offs) { + } else { + switch (offs) { #if 0 case 0x0c: ret = s->dr; @@ -287,40 +306,39 @@ static uint64_t sh_serial_read(void *opaque, hwaddr offs, break; } } -#ifdef DEBUG_SERIAL - printf("sh_serial: read offs=0x%02x val=0x%x\n", - offs, ret); -#endif + trace_sh_serial_read(d->id, size, offs, ret); - if (ret & ~((1 << 16) - 1)) { - fprintf(stderr, "sh_serial: unsupported read from 0x%02" - HWADDR_PRIx "\n", offs); - abort(); + if (ret > UINT16_MAX) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: unsupported read from 0x%02" HWADDR_PRIx "\n", + __func__, offs); + ret = 0; } return ret; } -static int sh_serial_can_receive(sh_serial_state *s) +static int sh_serial_can_receive(SHSerialState *s) { return s->scr & (1 << 4); } -static void sh_serial_receive_break(sh_serial_state *s) +static void sh_serial_receive_break(SHSerialState *s) { - if (s->feat & SH_SERIAL_FEAT_SCIF) + if (s->feat & SH_SERIAL_FEAT_SCIF) { s->sr |= (1 << 4); + } } static int sh_serial_can_receive1(void *opaque) { - sh_serial_state *s = opaque; + SHSerialState *s = opaque; return sh_serial_can_receive(s); } static void sh_serial_timeout_int(void *opaque) { - sh_serial_state *s = opaque; + SHSerialState *s = opaque; s->flags |= SH_SERIAL_FLAG_RDF; if (s->scr & (1 << 6) && s->rxi) { @@ -330,7 +348,7 @@ static void sh_serial_timeout_int(void *opaque) static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size) { - sh_serial_state *s = opaque; + SHSerialState *s = opaque; if (s->feat & SH_SERIAL_FEAT_SCIF) { int i; @@ -344,11 +362,11 @@ static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size) if (s->rx_cnt >= s->rtrg) { s->flags |= SH_SERIAL_FLAG_RDF; if (s->scr & (1 << 6) && s->rxi) { - timer_del(s->fifo_timeout_timer); + timer_del(&s->fifo_timeout_timer); qemu_set_irq(s->rxi, 1); } } else { - timer_mod(s->fifo_timeout_timer, + timer_mod(&s->fifo_timeout_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 15 * s->etu); } } @@ -360,9 +378,10 @@ static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size) static void sh_serial_event(void *opaque, QEMUChrEvent event) { - sh_serial_state *s = opaque; - if (event == CHR_EVENT_BREAK) + SHSerialState *s = opaque; + if (event == CHR_EVENT_BREAK) { sh_serial_receive_break(s); + } } static const MemoryRegionOps sh_serial_ops = { @@ -371,20 +390,10 @@ static const MemoryRegionOps sh_serial_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -void sh_serial_init(MemoryRegion *sysmem, - hwaddr base, int feat, - uint32_t freq, Chardev *chr, - qemu_irq eri_source, - qemu_irq rxi_source, - qemu_irq txi_source, - qemu_irq tei_source, - qemu_irq bri_source) +static void sh_serial_reset(DeviceState *dev) { - sh_serial_state *s; + SHSerialState *s = SH_SERIAL(dev); - s = g_malloc0(sizeof(sh_serial_state)); - - s->feat = feat; s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE; s->rtrg = 1; @@ -393,39 +402,64 @@ void sh_serial_init(MemoryRegion *sysmem, s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */ s->sptr = 0; - if (feat & SH_SERIAL_FEAT_SCIF) { + if (s->feat & SH_SERIAL_FEAT_SCIF) { s->fcr = 0; - } - else { + } else { s->dr = 0xff; } sh_serial_clear_fifo(s); +} - memory_region_init_io(&s->iomem, NULL, &sh_serial_ops, s, - "serial", 0x100000000ULL); - - memory_region_init_alias(&s->iomem_p4, NULL, "serial-p4", &s->iomem, - 0, 0x28); - memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4); - - memory_region_init_alias(&s->iomem_a7, NULL, "serial-a7", &s->iomem, - 0, 0x28); - memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7); - - if (chr) { - qemu_chr_fe_init(&s->chr, chr, &error_abort); +static void sh_serial_realize(DeviceState *d, Error **errp) +{ + SHSerialState *s = SH_SERIAL(d); + MemoryRegion *iomem = g_malloc(sizeof(*iomem)); + + assert(d->id); + memory_region_init_io(iomem, OBJECT(d), &sh_serial_ops, s, d->id, 0x28); + sysbus_init_mmio(SYS_BUS_DEVICE(d), iomem); + qdev_init_gpio_out_named(d, &s->eri, "eri", 1); + qdev_init_gpio_out_named(d, &s->rxi, "rxi", 1); + qdev_init_gpio_out_named(d, &s->txi, "txi", 1); + qdev_init_gpio_out_named(d, &s->tei, "tei", 1); + qdev_init_gpio_out_named(d, &s->bri, "bri", 1); + + if (qemu_chr_fe_backend_connected(&s->chr)) { qemu_chr_fe_set_handlers(&s->chr, sh_serial_can_receive1, sh_serial_receive1, sh_serial_event, NULL, s, NULL, true); } - s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, - sh_serial_timeout_int, s); + timer_init_ns(&s->fifo_timeout_timer, QEMU_CLOCK_VIRTUAL, + sh_serial_timeout_int, s); s->etu = NANOSECONDS_PER_SECOND / 9600; - s->eri = eri_source; - s->rxi = rxi_source; - s->txi = txi_source; - s->tei = tei_source; - s->bri = bri_source; +} + +static void sh_serial_finalize(Object *obj) +{ + SHSerialState *s = SH_SERIAL(obj); + + timer_del(&s->fifo_timeout_timer); +} + +static void sh_serial_init(Object *obj) +{ +} + +static Property sh_serial_properties[] = { + DEFINE_PROP_CHR("chardev", SHSerialState, chr), + DEFINE_PROP_UINT8("features", SHSerialState, feat, 0), + DEFINE_PROP_END_OF_LIST() +}; + +static void sh_serial_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + device_class_set_props(dc, sh_serial_properties); + dc->realize = sh_serial_realize; + dc->reset = sh_serial_reset; + /* Reason: part of SuperH CPU/SoC, needs to be wired up */ + dc->user_creatable = false; } diff --git a/hw/char/trace-events b/hw/char/trace-events index b774832af4..2ecb36232e 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -101,3 +101,7 @@ exynos_uart_rx_timeout(uint32_t channel, uint32_t stat, uint32_t intsp) "UART%d: # cadence_uart.c cadence_uart_baudrate(unsigned baudrate) "baudrate %u" + +# sh_serial.c +sh_serial_read(char *id, unsigned size, uint64_t offs, uint64_t val) " %s size %d offs 0x%02" PRIx64 " -> 0x%02" PRIx64 +sh_serial_write(char *id, unsigned size, uint64_t offs, uint64_t val) "%s size %d offs 0x%02" PRIx64 " <- 0x%02" PRIx64 diff --git a/hw/core/gpio.c b/hw/core/gpio.c new file mode 100644 index 0000000000..8e6b4f5edf --- /dev/null +++ b/hw/core/gpio.c @@ -0,0 +1,197 @@ +/* + * qdev GPIO helpers + * + * Copyright (c) 2009 CodeSourcery + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "hw/qdev-core.h" +#include "hw/irq.h" +#include "qapi/error.h" + +static NamedGPIOList *qdev_get_named_gpio_list(DeviceState *dev, + const char *name) +{ + NamedGPIOList *ngl; + + QLIST_FOREACH(ngl, &dev->gpios, node) { + /* NULL is a valid and matchable name. */ + if (g_strcmp0(name, ngl->name) == 0) { + return ngl; + } + } + + ngl = g_malloc0(sizeof(*ngl)); + ngl->name = g_strdup(name); + QLIST_INSERT_HEAD(&dev->gpios, ngl, node); + return ngl; +} + +void qdev_init_gpio_in_named_with_opaque(DeviceState *dev, + qemu_irq_handler handler, + void *opaque, + const char *name, int n) +{ + int i; + NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name); + + assert(gpio_list->num_out == 0 || !name); + gpio_list->in = qemu_extend_irqs(gpio_list->in, gpio_list->num_in, handler, + opaque, n); + + if (!name) { + name = "unnamed-gpio-in"; + } + for (i = gpio_list->num_in; i < gpio_list->num_in + n; i++) { + gchar *propname = g_strdup_printf("%s[%u]", name, i); + + object_property_add_child(OBJECT(dev), propname, + OBJECT(gpio_list->in[i])); + g_free(propname); + } + + gpio_list->num_in += n; +} + +void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n) +{ + qdev_init_gpio_in_named(dev, handler, NULL, n); +} + +void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins, + const char *name, int n) +{ + int i; + NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name); + + assert(gpio_list->num_in == 0 || !name); + + if (!name) { + name = "unnamed-gpio-out"; + } + memset(pins, 0, sizeof(*pins) * n); + for (i = 0; i < n; ++i) { + gchar *propname = g_strdup_printf("%s[%u]", name, + gpio_list->num_out + i); + + object_property_add_link(OBJECT(dev), propname, TYPE_IRQ, + (Object **)&pins[i], + object_property_allow_set_link, + OBJ_PROP_LINK_STRONG); + g_free(propname); + } + gpio_list->num_out += n; +} + +void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n) +{ + qdev_init_gpio_out_named(dev, pins, NULL, n); +} + +qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n) +{ + NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name); + + assert(n >= 0 && n < gpio_list->num_in); + return gpio_list->in[n]; +} + +qemu_irq qdev_get_gpio_in(DeviceState *dev, int n) +{ + return qdev_get_gpio_in_named(dev, NULL, n); +} + +void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n, + qemu_irq pin) +{ + char *propname = g_strdup_printf("%s[%d]", + name ? name : "unnamed-gpio-out", n); + if (pin && !OBJECT(pin)->parent) { + /* We need a name for object_property_set_link to work */ + object_property_add_child(container_get(qdev_get_machine(), + "/unattached"), + "non-qdev-gpio[*]", OBJECT(pin)); + } + object_property_set_link(OBJECT(dev), propname, OBJECT(pin), &error_abort); + g_free(propname); +} + +qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n) +{ + g_autofree char *propname = g_strdup_printf("%s[%d]", + name ? name : "unnamed-gpio-out", n); + + qemu_irq ret = (qemu_irq)object_property_get_link(OBJECT(dev), propname, + NULL); + + return ret; +} + +/* disconnect a GPIO output, returning the disconnected input (if any) */ + +static qemu_irq qdev_disconnect_gpio_out_named(DeviceState *dev, + const char *name, int n) +{ + char *propname = g_strdup_printf("%s[%d]", + name ? name : "unnamed-gpio-out", n); + + qemu_irq ret = (qemu_irq)object_property_get_link(OBJECT(dev), propname, + NULL); + if (ret) { + object_property_set_link(OBJECT(dev), propname, NULL, NULL); + } + g_free(propname); + return ret; +} + +qemu_irq qdev_intercept_gpio_out(DeviceState *dev, qemu_irq icpt, + const char *name, int n) +{ + qemu_irq disconnected = qdev_disconnect_gpio_out_named(dev, name, n); + qdev_connect_gpio_out_named(dev, name, n, icpt); + return disconnected; +} + +void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin) +{ + qdev_connect_gpio_out_named(dev, NULL, n, pin); +} + +void qdev_pass_gpios(DeviceState *dev, DeviceState *container, + const char *name) +{ + int i; + NamedGPIOList *ngl = qdev_get_named_gpio_list(dev, name); + + for (i = 0; i < ngl->num_in; i++) { + const char *nm = ngl->name ? ngl->name : "unnamed-gpio-in"; + char *propname = g_strdup_printf("%s[%d]", nm, i); + + object_property_add_alias(OBJECT(container), propname, + OBJECT(dev), propname); + g_free(propname); + } + for (i = 0; i < ngl->num_out; i++) { + const char *nm = ngl->name ? ngl->name : "unnamed-gpio-out"; + char *propname = g_strdup_printf("%s[%d]", nm, i); + + object_property_add_alias(OBJECT(container), propname, + OBJECT(dev), propname); + g_free(propname); + } + QLIST_REMOVE(ngl, node); + QLIST_INSERT_HEAD(&container->gpios, ngl, node); +} diff --git a/hw/core/hotplug-stubs.c b/hw/core/hotplug-stubs.c new file mode 100644 index 0000000000..7aadaa29bd --- /dev/null +++ b/hw/core/hotplug-stubs.c @@ -0,0 +1,34 @@ +/* + * Hotplug handler stubs + * + * Copyright (c) Red Hat + * + * Authors: + * Philippe Mathieu-Daudé <philmd@redhat.com>, + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#include "qemu/osdep.h" +#include "hw/qdev-core.h" + +HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev) +{ + return NULL; +} + +void hotplug_handler_pre_plug(HotplugHandler *plug_handler, + DeviceState *plugged_dev, + Error **errp) +{ + g_assert_not_reached(); +} + +void hotplug_handler_plug(HotplugHandler *plug_handler, + DeviceState *plugged_dev, + Error **errp) +{ + g_assert_not_reached(); +} diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c new file mode 100644 index 0000000000..116a0cbbfa --- /dev/null +++ b/hw/core/machine-smp.c @@ -0,0 +1,181 @@ +/* + * QEMU Machine core (related to -smp parsing) + * + * Copyright (c) 2021 Huawei Technologies Co., Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "hw/boards.h" +#include "qapi/error.h" + +/* + * Report information of a machine's supported CPU topology hierarchy. + * Topology members will be ordered from the largest to the smallest + * in the string. + */ +static char *cpu_hierarchy_to_string(MachineState *ms) +{ + MachineClass *mc = MACHINE_GET_CLASS(ms); + GString *s = g_string_new(NULL); + + g_string_append_printf(s, "sockets (%u)", ms->smp.sockets); + + if (mc->smp_props.dies_supported) { + g_string_append_printf(s, " * dies (%u)", ms->smp.dies); + } + + g_string_append_printf(s, " * cores (%u)", ms->smp.cores); + g_string_append_printf(s, " * threads (%u)", ms->smp.threads); + + return g_string_free(s, false); +} + +/* + * smp_parse - Generic function used to parse the given SMP configuration + * + * Any missing parameter in "cpus/maxcpus/sockets/cores/threads" will be + * automatically computed based on the provided ones. + * + * In the calculation of omitted sockets/cores/threads: we prefer sockets + * over cores over threads before 6.2, while preferring cores over sockets + * over threads since 6.2. + * + * In the calculation of cpus/maxcpus: When both maxcpus and cpus are omitted, + * maxcpus will be computed from the given parameters and cpus will be set + * equal to maxcpus. When only one of maxcpus and cpus is given then the + * omitted one will be set to its given counterpart's value. Both maxcpus and + * cpus may be specified, but maxcpus must be equal to or greater than cpus. + * + * For compatibility, apart from the parameters that will be computed, newly + * introduced topology members which are likely to be target specific should + * be directly set as 1 if they are omitted (e.g. dies for PC since 4.1). + */ +void smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp) +{ + MachineClass *mc = MACHINE_GET_CLASS(ms); + unsigned cpus = config->has_cpus ? config->cpus : 0; + unsigned sockets = config->has_sockets ? config->sockets : 0; + unsigned dies = config->has_dies ? config->dies : 0; + unsigned cores = config->has_cores ? config->cores : 0; + unsigned threads = config->has_threads ? config->threads : 0; + unsigned maxcpus = config->has_maxcpus ? config->maxcpus : 0; + + /* + * Specified CPU topology parameters must be greater than zero, + * explicit configuration like "cpus=0" is not allowed. + */ + if ((config->has_cpus && config->cpus == 0) || + (config->has_sockets && config->sockets == 0) || + (config->has_dies && config->dies == 0) || + (config->has_cores && config->cores == 0) || + (config->has_threads && config->threads == 0) || + (config->has_maxcpus && config->maxcpus == 0)) { + warn_report("Deprecated CPU topology (considered invalid): " + "CPU topology parameters must be greater than zero"); + } + + /* + * If not supported by the machine, a topology parameter must be + * omitted or specified equal to 1. + */ + if (!mc->smp_props.dies_supported && dies > 1) { + error_setg(errp, "dies not supported by this machine's CPU topology"); + return; + } + + dies = dies > 0 ? dies : 1; + + /* compute missing values based on the provided ones */ + if (cpus == 0 && maxcpus == 0) { + sockets = sockets > 0 ? sockets : 1; + cores = cores > 0 ? cores : 1; + threads = threads > 0 ? threads : 1; + } else { + maxcpus = maxcpus > 0 ? maxcpus : cpus; + + if (mc->smp_props.prefer_sockets) { + /* prefer sockets over cores before 6.2 */ + if (sockets == 0) { + cores = cores > 0 ? cores : 1; + threads = threads > 0 ? threads : 1; + sockets = maxcpus / (dies * cores * threads); + } else if (cores == 0) { + threads = threads > 0 ? threads : 1; + cores = maxcpus / (sockets * dies * threads); + } + } else { + /* prefer cores over sockets since 6.2 */ + if (cores == 0) { + sockets = sockets > 0 ? sockets : 1; + threads = threads > 0 ? threads : 1; + cores = maxcpus / (sockets * dies * threads); + } else if (sockets == 0) { + threads = threads > 0 ? threads : 1; + sockets = maxcpus / (dies * cores * threads); + } + } + + /* try to calculate omitted threads at last */ + if (threads == 0) { + threads = maxcpus / (sockets * dies * cores); + } + } + + maxcpus = maxcpus > 0 ? maxcpus : sockets * dies * cores * threads; + cpus = cpus > 0 ? cpus : maxcpus; + + ms->smp.cpus = cpus; + ms->smp.sockets = sockets; + ms->smp.dies = dies; + ms->smp.cores = cores; + ms->smp.threads = threads; + ms->smp.max_cpus = maxcpus; + + /* sanity-check of the computed topology */ + if (sockets * dies * cores * threads != maxcpus) { + g_autofree char *topo_msg = cpu_hierarchy_to_string(ms); + error_setg(errp, "Invalid CPU topology: " + "product of the hierarchy must match maxcpus: " + "%s != maxcpus (%u)", + topo_msg, maxcpus); + return; + } + + if (maxcpus < cpus) { + g_autofree char *topo_msg = cpu_hierarchy_to_string(ms); + error_setg(errp, "Invalid CPU topology: " + "maxcpus must be equal to or greater than smp: " + "%s == maxcpus (%u) < smp_cpus (%u)", + topo_msg, maxcpus, cpus); + return; + } + + if (ms->smp.cpus < mc->min_cpus) { + error_setg(errp, "Invalid SMP CPUs %d. The min CPUs " + "supported by machine '%s' is %d", + ms->smp.cpus, + mc->name, mc->min_cpus); + return; + } + + if (ms->smp.max_cpus > mc->max_cpus) { + error_setg(errp, "Invalid SMP CPUs %d. The max CPUs " + "supported by machine '%s' is %d", + ms->smp.max_cpus, + mc->name, mc->max_cpus); + return; + } +} diff --git a/hw/core/machine.c b/hw/core/machine.c index b8d95eec32..e24e3e27db 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -548,35 +548,30 @@ void machine_class_allow_dynamic_sysbus_dev(MachineClass *mc, const char *type) bool device_is_dynamic_sysbus(MachineClass *mc, DeviceState *dev) { - bool allowed = false; - strList *wl; Object *obj = OBJECT(dev); if (!object_dynamic_cast(obj, TYPE_SYS_BUS_DEVICE)) { return false; } + return device_type_is_dynamic_sysbus(mc, object_get_typename(obj)); +} + +bool device_type_is_dynamic_sysbus(MachineClass *mc, const char *type) +{ + bool allowed = false; + strList *wl; + ObjectClass *klass = object_class_by_name(type); + for (wl = mc->allowed_dynamic_sysbus_devices; !allowed && wl; wl = wl->next) { - allowed |= !!object_dynamic_cast(obj, wl->value); + allowed |= !!object_class_dynamic_cast(klass, wl->value); } return allowed; } -static void validate_sysbus_device(SysBusDevice *sbdev, void *opaque) -{ - MachineState *machine = opaque; - MachineClass *mc = MACHINE_GET_CLASS(machine); - - if (!device_is_dynamic_sysbus(mc, DEVICE(sbdev))) { - error_report("Option '-device %s' cannot be handled by this machine", - object_class_get_name(object_get_class(OBJECT(sbdev)))); - exit(1); - } -} - static char *machine_get_memdev(Object *obj, Error **errp) { MachineState *ms = MACHINE(obj); @@ -592,17 +587,6 @@ static void machine_set_memdev(Object *obj, const char *value, Error **errp) ms->ram_memdev_id = g_strdup(value); } -static void machine_init_notify(Notifier *notifier, void *data) -{ - MachineState *machine = MACHINE(qdev_get_machine()); - - /* - * Loop through all dynamically created sysbus devices and check if they are - * all allowed. If a device is not allowed, error out. - */ - foreach_dynamic_sysbus_device(validate_sysbus_device, machine); -} - HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine) { int i; @@ -749,165 +733,6 @@ void machine_set_cpu_numa_node(MachineState *machine, } } -/* - * Report information of a machine's supported CPU topology hierarchy. - * Topology members will be ordered from the largest to the smallest - * in the string. - */ -static char *cpu_hierarchy_to_string(MachineState *ms) -{ - MachineClass *mc = MACHINE_GET_CLASS(ms); - GString *s = g_string_new(NULL); - - g_string_append_printf(s, "sockets (%u)", ms->smp.sockets); - - if (mc->smp_props.dies_supported) { - g_string_append_printf(s, " * dies (%u)", ms->smp.dies); - } - - g_string_append_printf(s, " * cores (%u)", ms->smp.cores); - g_string_append_printf(s, " * threads (%u)", ms->smp.threads); - - return g_string_free(s, false); -} - -/* - * smp_parse - Generic function used to parse the given SMP configuration - * - * Any missing parameter in "cpus/maxcpus/sockets/cores/threads" will be - * automatically computed based on the provided ones. - * - * In the calculation of omitted sockets/cores/threads: we prefer sockets - * over cores over threads before 6.2, while preferring cores over sockets - * over threads since 6.2. - * - * In the calculation of cpus/maxcpus: When both maxcpus and cpus are omitted, - * maxcpus will be computed from the given parameters and cpus will be set - * equal to maxcpus. When only one of maxcpus and cpus is given then the - * omitted one will be set to its given counterpart's value. Both maxcpus and - * cpus may be specified, but maxcpus must be equal to or greater than cpus. - * - * For compatibility, apart from the parameters that will be computed, newly - * introduced topology members which are likely to be target specific should - * be directly set as 1 if they are omitted (e.g. dies for PC since 4.1). - */ -static void smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp) -{ - MachineClass *mc = MACHINE_GET_CLASS(ms); - unsigned cpus = config->has_cpus ? config->cpus : 0; - unsigned sockets = config->has_sockets ? config->sockets : 0; - unsigned dies = config->has_dies ? config->dies : 0; - unsigned cores = config->has_cores ? config->cores : 0; - unsigned threads = config->has_threads ? config->threads : 0; - unsigned maxcpus = config->has_maxcpus ? config->maxcpus : 0; - - /* - * Specified CPU topology parameters must be greater than zero, - * explicit configuration like "cpus=0" is not allowed. - */ - if ((config->has_cpus && config->cpus == 0) || - (config->has_sockets && config->sockets == 0) || - (config->has_dies && config->dies == 0) || - (config->has_cores && config->cores == 0) || - (config->has_threads && config->threads == 0) || - (config->has_maxcpus && config->maxcpus == 0)) { - warn_report("Deprecated CPU topology (considered invalid): " - "CPU topology parameters must be greater than zero"); - } - - /* - * If not supported by the machine, a topology parameter must be - * omitted or specified equal to 1. - */ - if (!mc->smp_props.dies_supported && dies > 1) { - error_setg(errp, "dies not supported by this machine's CPU topology"); - return; - } - - dies = dies > 0 ? dies : 1; - - /* compute missing values based on the provided ones */ - if (cpus == 0 && maxcpus == 0) { - sockets = sockets > 0 ? sockets : 1; - cores = cores > 0 ? cores : 1; - threads = threads > 0 ? threads : 1; - } else { - maxcpus = maxcpus > 0 ? maxcpus : cpus; - - if (mc->smp_props.prefer_sockets) { - /* prefer sockets over cores before 6.2 */ - if (sockets == 0) { - cores = cores > 0 ? cores : 1; - threads = threads > 0 ? threads : 1; - sockets = maxcpus / (dies * cores * threads); - } else if (cores == 0) { - threads = threads > 0 ? threads : 1; - cores = maxcpus / (sockets * dies * threads); - } - } else { - /* prefer cores over sockets since 6.2 */ - if (cores == 0) { - sockets = sockets > 0 ? sockets : 1; - threads = threads > 0 ? threads : 1; - cores = maxcpus / (sockets * dies * threads); - } else if (sockets == 0) { - threads = threads > 0 ? threads : 1; - sockets = maxcpus / (dies * cores * threads); - } - } - - /* try to calculate omitted threads at last */ - if (threads == 0) { - threads = maxcpus / (sockets * dies * cores); - } - } - - maxcpus = maxcpus > 0 ? maxcpus : sockets * dies * cores * threads; - cpus = cpus > 0 ? cpus : maxcpus; - - ms->smp.cpus = cpus; - ms->smp.sockets = sockets; - ms->smp.dies = dies; - ms->smp.cores = cores; - ms->smp.threads = threads; - ms->smp.max_cpus = maxcpus; - - /* sanity-check of the computed topology */ - if (sockets * dies * cores * threads != maxcpus) { - g_autofree char *topo_msg = cpu_hierarchy_to_string(ms); - error_setg(errp, "Invalid CPU topology: " - "product of the hierarchy must match maxcpus: " - "%s != maxcpus (%u)", - topo_msg, maxcpus); - return; - } - - if (maxcpus < cpus) { - g_autofree char *topo_msg = cpu_hierarchy_to_string(ms); - error_setg(errp, "Invalid CPU topology: " - "maxcpus must be equal to or greater than smp: " - "%s == maxcpus (%u) < smp_cpus (%u)", - topo_msg, maxcpus, cpus); - return; - } - - if (ms->smp.cpus < mc->min_cpus) { - error_setg(errp, "Invalid SMP CPUs %d. The min CPUs " - "supported by machine '%s' is %d", - ms->smp.cpus, - mc->name, mc->min_cpus); - return; - } - - if (ms->smp.max_cpus > mc->max_cpus) { - error_setg(errp, "Invalid SMP CPUs %d. The max CPUs " - "supported by machine '%s' is %d", - ms->smp.max_cpus, - mc->name, mc->max_cpus); - return; - } -} - static void machine_get_smp(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -1101,10 +926,6 @@ static void machine_initfn(Object *obj) "Table (HMAT)"); } - /* Register notifier when init is done for sysbus sanity checks */ - ms->sysbus_notifier.notify = machine_init_notify; - qemu_add_machine_init_done_notifier(&ms->sysbus_notifier); - /* default to mc->default_cpus */ ms->smp.cpus = mc->default_cpus; ms->smp.max_cpus = mc->default_cpus; diff --git a/hw/core/meson.build b/hw/core/meson.build index 18f44fb7c2..0f884d6fd4 100644 --- a/hw/core/meson.build +++ b/hw/core/meson.build @@ -1,7 +1,6 @@ # core qdev-related obj files, also used by *-user and unit tests -hwcore_files = files( +hwcore_ss.add(files( 'bus.c', - 'hotplug.c', 'qdev-properties.c', 'qdev.c', 'reset.c', @@ -11,22 +10,34 @@ hwcore_files = files( 'irq.c', 'clock.c', 'qdev-clock.c', -) +)) +if have_system + hwcore_ss.add(files( + 'hotplug.c', + 'qdev-hotplug.c', + )) +else + hwcore_ss.add(files( + 'hotplug-stubs.c', + )) +endif common_ss.add(files('cpu-common.c')) -common_ss.add(when: 'CONFIG_FITLOADER', if_true: files('loader-fit.c')) -common_ss.add(when: 'CONFIG_GENERIC_LOADER', if_true: files('generic-loader.c')) -common_ss.add(when: ['CONFIG_GUEST_LOADER', fdt], if_true: files('guest-loader.c')) -common_ss.add(when: 'CONFIG_OR_IRQ', if_true: files('or-irq.c')) -common_ss.add(when: 'CONFIG_PLATFORM_BUS', if_true: files('platform-bus.c')) -common_ss.add(when: 'CONFIG_PTIMER', if_true: files('ptimer.c')) -common_ss.add(when: 'CONFIG_REGISTER', if_true: files('register.c')) -common_ss.add(when: 'CONFIG_SPLIT_IRQ', if_true: files('split-irq.c')) -common_ss.add(when: 'CONFIG_XILINX_AXI', if_true: files('stream.c')) +common_ss.add(files('machine-smp.c')) +softmmu_ss.add(when: 'CONFIG_FITLOADER', if_true: files('loader-fit.c')) +softmmu_ss.add(when: 'CONFIG_GENERIC_LOADER', if_true: files('generic-loader.c')) +softmmu_ss.add(when: ['CONFIG_GUEST_LOADER', fdt], if_true: files('guest-loader.c')) +softmmu_ss.add(when: 'CONFIG_OR_IRQ', if_true: files('or-irq.c')) +softmmu_ss.add(when: 'CONFIG_PLATFORM_BUS', if_true: files('platform-bus.c')) +softmmu_ss.add(when: 'CONFIG_PTIMER', if_true: files('ptimer.c')) +softmmu_ss.add(when: 'CONFIG_REGISTER', if_true: files('register.c')) +softmmu_ss.add(when: 'CONFIG_SPLIT_IRQ', if_true: files('split-irq.c')) +softmmu_ss.add(when: 'CONFIG_XILINX_AXI', if_true: files('stream.c')) softmmu_ss.add(files( 'cpu-sysemu.c', 'fw-path-provider.c', + 'gpio.c', 'loader.c', 'machine-hmp-cmds.c', 'machine.c', diff --git a/hw/core/qdev-hotplug.c b/hw/core/qdev-hotplug.c new file mode 100644 index 0000000000..d495d0e9c7 --- /dev/null +++ b/hw/core/qdev-hotplug.c @@ -0,0 +1,73 @@ +/* + * QDev Hotplug handlers + * + * Copyright (c) Red Hat + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/qdev-core.h" +#include "hw/boards.h" + +HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev) +{ + MachineState *machine; + MachineClass *mc; + Object *m_obj = qdev_get_machine(); + + if (object_dynamic_cast(m_obj, TYPE_MACHINE)) { + machine = MACHINE(m_obj); + mc = MACHINE_GET_CLASS(machine); + if (mc->get_hotplug_handler) { + return mc->get_hotplug_handler(machine, dev); + } + } + + return NULL; +} + +bool qdev_hotplug_allowed(DeviceState *dev, Error **errp) +{ + MachineState *machine; + MachineClass *mc; + Object *m_obj = qdev_get_machine(); + + if (object_dynamic_cast(m_obj, TYPE_MACHINE)) { + machine = MACHINE(m_obj); + mc = MACHINE_GET_CLASS(machine); + if (mc->hotplug_allowed) { + return mc->hotplug_allowed(machine, dev, errp); + } + } + + return true; +} + +HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev) +{ + if (dev->parent_bus) { + return dev->parent_bus->hotplug_handler; + } + return NULL; +} + +HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev) +{ + HotplugHandler *hotplug_ctrl = qdev_get_machine_hotplug_handler(dev); + + if (hotplug_ctrl == NULL && dev->parent_bus) { + hotplug_ctrl = qdev_get_bus_hotplug_handler(dev); + } + return hotplug_ctrl; +} + +/* can be used as ->unplug() callback for the simple cases */ +void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + qdev_unrealize(dev); +} diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 7f06403752..84f3019440 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -33,7 +33,6 @@ #include "qapi/visitor.h" #include "qemu/error-report.h" #include "qemu/option.h" -#include "hw/hotplug.h" #include "hw/irq.h" #include "hw/qdev-properties.h" #include "hw/boards.h" @@ -238,58 +237,6 @@ void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, dev->alias_required_for_version = required_for_version; } -HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev) -{ - MachineState *machine; - MachineClass *mc; - Object *m_obj = qdev_get_machine(); - - if (object_dynamic_cast(m_obj, TYPE_MACHINE)) { - machine = MACHINE(m_obj); - mc = MACHINE_GET_CLASS(machine); - if (mc->get_hotplug_handler) { - return mc->get_hotplug_handler(machine, dev); - } - } - - return NULL; -} - -bool qdev_hotplug_allowed(DeviceState *dev, Error **errp) -{ - MachineState *machine; - MachineClass *mc; - Object *m_obj = qdev_get_machine(); - - if (object_dynamic_cast(m_obj, TYPE_MACHINE)) { - machine = MACHINE(m_obj); - mc = MACHINE_GET_CLASS(machine); - if (mc->hotplug_allowed) { - return mc->hotplug_allowed(machine, dev, errp); - } - } - - return true; -} - -HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev) -{ - if (dev->parent_bus) { - return dev->parent_bus->hotplug_handler; - } - return NULL; -} - -HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev) -{ - HotplugHandler *hotplug_ctrl = qdev_get_machine_hotplug_handler(dev); - - if (hotplug_ctrl == NULL && dev->parent_bus) { - hotplug_ctrl = qdev_get_bus_hotplug_handler(dev); - } - return hotplug_ctrl; -} - static int qdev_prereset(DeviceState *dev, void *opaque) { trace_qdev_reset_tree(dev, object_get_typename(OBJECT(dev))); @@ -371,13 +318,6 @@ static void device_reset_child_foreach(Object *obj, ResettableChildCallback cb, } } -/* can be used as ->unplug() callback for the simple cases */ -void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - qdev_unrealize(dev); -} - bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp) { assert(!dev->realized && !dev->parent_bus); @@ -436,180 +376,6 @@ BusState *qdev_get_parent_bus(DeviceState *dev) return dev->parent_bus; } -static NamedGPIOList *qdev_get_named_gpio_list(DeviceState *dev, - const char *name) -{ - NamedGPIOList *ngl; - - QLIST_FOREACH(ngl, &dev->gpios, node) { - /* NULL is a valid and matchable name. */ - if (g_strcmp0(name, ngl->name) == 0) { - return ngl; - } - } - - ngl = g_malloc0(sizeof(*ngl)); - ngl->name = g_strdup(name); - QLIST_INSERT_HEAD(&dev->gpios, ngl, node); - return ngl; -} - -void qdev_init_gpio_in_named_with_opaque(DeviceState *dev, - qemu_irq_handler handler, - void *opaque, - const char *name, int n) -{ - int i; - NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name); - - assert(gpio_list->num_out == 0 || !name); - gpio_list->in = qemu_extend_irqs(gpio_list->in, gpio_list->num_in, handler, - opaque, n); - - if (!name) { - name = "unnamed-gpio-in"; - } - for (i = gpio_list->num_in; i < gpio_list->num_in + n; i++) { - gchar *propname = g_strdup_printf("%s[%u]", name, i); - - object_property_add_child(OBJECT(dev), propname, - OBJECT(gpio_list->in[i])); - g_free(propname); - } - - gpio_list->num_in += n; -} - -void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n) -{ - qdev_init_gpio_in_named(dev, handler, NULL, n); -} - -void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins, - const char *name, int n) -{ - int i; - NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name); - - assert(gpio_list->num_in == 0 || !name); - - if (!name) { - name = "unnamed-gpio-out"; - } - memset(pins, 0, sizeof(*pins) * n); - for (i = 0; i < n; ++i) { - gchar *propname = g_strdup_printf("%s[%u]", name, - gpio_list->num_out + i); - - object_property_add_link(OBJECT(dev), propname, TYPE_IRQ, - (Object **)&pins[i], - object_property_allow_set_link, - OBJ_PROP_LINK_STRONG); - g_free(propname); - } - gpio_list->num_out += n; -} - -void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n) -{ - qdev_init_gpio_out_named(dev, pins, NULL, n); -} - -qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n) -{ - NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name); - - assert(n >= 0 && n < gpio_list->num_in); - return gpio_list->in[n]; -} - -qemu_irq qdev_get_gpio_in(DeviceState *dev, int n) -{ - return qdev_get_gpio_in_named(dev, NULL, n); -} - -void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n, - qemu_irq pin) -{ - char *propname = g_strdup_printf("%s[%d]", - name ? name : "unnamed-gpio-out", n); - if (pin && !OBJECT(pin)->parent) { - /* We need a name for object_property_set_link to work */ - object_property_add_child(container_get(qdev_get_machine(), - "/unattached"), - "non-qdev-gpio[*]", OBJECT(pin)); - } - object_property_set_link(OBJECT(dev), propname, OBJECT(pin), &error_abort); - g_free(propname); -} - -qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n) -{ - g_autofree char *propname = g_strdup_printf("%s[%d]", - name ? name : "unnamed-gpio-out", n); - - qemu_irq ret = (qemu_irq)object_property_get_link(OBJECT(dev), propname, - NULL); - - return ret; -} - -/* disconnect a GPIO output, returning the disconnected input (if any) */ - -static qemu_irq qdev_disconnect_gpio_out_named(DeviceState *dev, - const char *name, int n) -{ - char *propname = g_strdup_printf("%s[%d]", - name ? name : "unnamed-gpio-out", n); - - qemu_irq ret = (qemu_irq)object_property_get_link(OBJECT(dev), propname, - NULL); - if (ret) { - object_property_set_link(OBJECT(dev), propname, NULL, NULL); - } - g_free(propname); - return ret; -} - -qemu_irq qdev_intercept_gpio_out(DeviceState *dev, qemu_irq icpt, - const char *name, int n) -{ - qemu_irq disconnected = qdev_disconnect_gpio_out_named(dev, name, n); - qdev_connect_gpio_out_named(dev, name, n, icpt); - return disconnected; -} - -void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin) -{ - qdev_connect_gpio_out_named(dev, NULL, n, pin); -} - -void qdev_pass_gpios(DeviceState *dev, DeviceState *container, - const char *name) -{ - int i; - NamedGPIOList *ngl = qdev_get_named_gpio_list(dev, name); - - for (i = 0; i < ngl->num_in; i++) { - const char *nm = ngl->name ? ngl->name : "unnamed-gpio-in"; - char *propname = g_strdup_printf("%s[%d]", nm, i); - - object_property_add_alias(OBJECT(container), propname, - OBJECT(dev), propname); - g_free(propname); - } - for (i = 0; i < ngl->num_out; i++) { - const char *nm = ngl->name ? ngl->name : "unnamed-gpio-out"; - char *propname = g_strdup_printf("%s[%d]", nm, i); - - object_property_add_alias(OBJECT(container), propname, - OBJECT(dev), propname); - g_free(propname); - } - QLIST_REMOVE(ngl, node); - QLIST_INSERT_HEAD(&container->gpios, ngl, node); -} - BusState *qdev_get_child_bus(DeviceState *dev, const char *name) { BusState *bus; diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c index e3d3d5cf89..482be95415 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -1613,8 +1613,8 @@ void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t length) void qmp_xen_set_global_dirty_log(bool enable, Error **errp) { if (enable) { - memory_global_dirty_log_start(); + memory_global_dirty_log_start(GLOBAL_DIRTY_MIGRATION); } else { - memory_global_dirty_log_stop(); + memory_global_dirty_log_stop(GLOBAL_DIRTY_MIGRATION); } } diff --git a/hw/intc/sh_intc.c b/hw/intc/sh_intc.c index 72a55e32dd..c9b0b0c1ec 100644 --- a/hw/intc/sh_intc.c +++ b/hw/intc/sh_intc.c @@ -9,40 +9,37 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "hw/sh4/sh_intc.h" #include "hw/irq.h" #include "hw/sh4/sh.h" - -//#define DEBUG_INTC -//#define DEBUG_INTC_SOURCES - -#define INTC_A7(x) ((x) & 0x1fffffff) +#include "trace.h" void sh_intc_toggle_source(struct intc_source *source, - int enable_adj, int assert_adj) + int enable_adj, int assert_adj) { int enable_changed = 0; int pending_changed = 0; int old_pending; - if ((source->enable_count == source->enable_max) && (enable_adj == -1)) + if (source->enable_count == source->enable_max && enable_adj == -1) { enable_changed = -1; - + } source->enable_count += enable_adj; - if (source->enable_count == source->enable_max) + if (source->enable_count == source->enable_max) { enable_changed = 1; - + } source->asserted += assert_adj; old_pending = source->pending; source->pending = source->asserted && (source->enable_count == source->enable_max); - if (old_pending != source->pending) + if (old_pending != source->pending) { pending_changed = 1; - + } if (pending_changed) { if (source->pending) { source->parent->pending++; @@ -54,35 +51,30 @@ void sh_intc_toggle_source(struct intc_source *source, if (source->parent->pending == 0) { cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD); } - } + } } - if (enable_changed || assert_adj || pending_changed) { -#ifdef DEBUG_INTC_SOURCES - printf("sh_intc: (%d/%d/%d/%d) interrupt source 0x%x %s%s%s\n", - source->parent->pending, - source->asserted, - source->enable_count, - source->enable_max, - source->vect, - source->asserted ? "asserted " : - assert_adj ? "deasserted" : "", - enable_changed == 1 ? "enabled " : - enable_changed == -1 ? "disabled " : "", - source->pending ? "pending" : ""); -#endif - } + if (enable_changed || assert_adj || pending_changed) { + trace_sh_intc_sources(source->parent->pending, source->asserted, + source->enable_count, source->enable_max, + source->vect, source->asserted ? "asserted " : + assert_adj ? "deasserted" : "", + enable_changed == 1 ? "enabled " : + enable_changed == -1 ? "disabled " : "", + source->pending ? "pending" : ""); + } } -static void sh_intc_set_irq (void *opaque, int n, int level) +static void sh_intc_set_irq(void *opaque, int n, int level) { - struct intc_desc *desc = opaque; - struct intc_source *source = &(desc->sources[n]); + struct intc_desc *desc = opaque; + struct intc_source *source = &desc->sources[n]; - if (level && !source->asserted) - sh_intc_toggle_source(source, 0, 1); - else if (!level && source->asserted) - sh_intc_toggle_source(source, 0, -1); + if (level && !source->asserted) { + sh_intc_toggle_source(source, 0, 1); + } else if (!level && source->asserted) { + sh_intc_toggle_source(source, 0, -1); + } } int sh_intc_get_pending_vector(struct intc_desc *desc, int imask) @@ -97,147 +89,124 @@ int sh_intc_get_pending_vector(struct intc_desc *desc, int imask) } for (i = 0; i < desc->nr_sources; i++) { - struct intc_source *source = desc->sources + i; + struct intc_source *source = &desc->sources[i]; - if (source->pending) { -#ifdef DEBUG_INTC_SOURCES - printf("sh_intc: (%d) returning interrupt source 0x%x\n", - desc->pending, source->vect); -#endif + if (source->pending) { + trace_sh_intc_pending(desc->pending, source->vect); return source->vect; - } + } } - - abort(); + g_assert_not_reached(); } -#define INTC_MODE_NONE 0 -#define INTC_MODE_DUAL_SET 1 -#define INTC_MODE_DUAL_CLR 2 -#define INTC_MODE_ENABLE_REG 3 -#define INTC_MODE_MASK_REG 4 -#define INTC_MODE_IS_PRIO 8 - -static unsigned int sh_intc_mode(unsigned long address, - unsigned long set_reg, unsigned long clr_reg) +typedef enum { + INTC_MODE_NONE, + INTC_MODE_DUAL_SET, + INTC_MODE_DUAL_CLR, + INTC_MODE_ENABLE_REG, + INTC_MODE_MASK_REG, +} SHIntCMode; +#define INTC_MODE_IS_PRIO 0x80 + +static SHIntCMode sh_intc_mode(unsigned long address, unsigned long set_reg, + unsigned long clr_reg) { - if ((address != INTC_A7(set_reg)) && - (address != INTC_A7(clr_reg))) + if (address != A7ADDR(set_reg) && address != A7ADDR(clr_reg)) { return INTC_MODE_NONE; - + } if (set_reg && clr_reg) { - if (address == INTC_A7(set_reg)) - return INTC_MODE_DUAL_SET; - else - return INTC_MODE_DUAL_CLR; + return address == A7ADDR(set_reg) ? + INTC_MODE_DUAL_SET : INTC_MODE_DUAL_CLR; } - - if (set_reg) - return INTC_MODE_ENABLE_REG; - else - return INTC_MODE_MASK_REG; + return set_reg ? INTC_MODE_ENABLE_REG : INTC_MODE_MASK_REG; } static void sh_intc_locate(struct intc_desc *desc, - unsigned long address, - unsigned long **datap, - intc_enum **enums, - unsigned int *first, - unsigned int *width, - unsigned int *modep) + unsigned long address, + unsigned long **datap, + intc_enum **enums, + unsigned int *first, + unsigned int *width, + unsigned int *modep) { - unsigned int i, mode; + SHIntCMode mode; + unsigned int i; /* this is slow but works for now */ if (desc->mask_regs) { for (i = 0; i < desc->nr_mask_regs; i++) { - struct intc_mask_reg *mr = desc->mask_regs + i; - - mode = sh_intc_mode(address, mr->set_reg, mr->clr_reg); - if (mode == INTC_MODE_NONE) - continue; - - *modep = mode; - *datap = &mr->value; - *enums = mr->enum_ids; - *first = mr->reg_width - 1; - *width = 1; - return; - } + struct intc_mask_reg *mr = &desc->mask_regs[i]; + + mode = sh_intc_mode(address, mr->set_reg, mr->clr_reg); + if (mode != INTC_MODE_NONE) { + *modep = mode; + *datap = &mr->value; + *enums = mr->enum_ids; + *first = mr->reg_width - 1; + *width = 1; + return; + } + } } if (desc->prio_regs) { for (i = 0; i < desc->nr_prio_regs; i++) { - struct intc_prio_reg *pr = desc->prio_regs + i; - - mode = sh_intc_mode(address, pr->set_reg, pr->clr_reg); - if (mode == INTC_MODE_NONE) - continue; - - *modep = mode | INTC_MODE_IS_PRIO; - *datap = &pr->value; - *enums = pr->enum_ids; - *first = (pr->reg_width / pr->field_width) - 1; - *width = pr->field_width; - return; - } + struct intc_prio_reg *pr = &desc->prio_regs[i]; + + mode = sh_intc_mode(address, pr->set_reg, pr->clr_reg); + if (mode != INTC_MODE_NONE) { + *modep = mode | INTC_MODE_IS_PRIO; + *datap = &pr->value; + *enums = pr->enum_ids; + *first = pr->reg_width / pr->field_width - 1; + *width = pr->field_width; + return; + } + } } - - abort(); + g_assert_not_reached(); } static void sh_intc_toggle_mask(struct intc_desc *desc, intc_enum id, - int enable, int is_group) + int enable, int is_group) { - struct intc_source *source = desc->sources + id; - - if (!id) - return; + struct intc_source *source = &desc->sources[id]; + if (!id) { + return; + } if (!source->next_enum_id && (!source->enable_max || !source->vect)) { -#ifdef DEBUG_INTC_SOURCES - printf("sh_intc: reserved interrupt source %d modified\n", id); -#endif - return; + qemu_log_mask(LOG_UNIMP, + "sh_intc: reserved interrupt source %d modified\n", id); + return; } - if (source->vect) + if (source->vect) { sh_intc_toggle_source(source, enable ? 1 : -1, 0); - -#ifdef DEBUG_INTC - else { - printf("setting interrupt group %d to %d\n", id, !!enable); } -#endif if ((is_group || !source->vect) && source->next_enum_id) { sh_intc_toggle_mask(desc, source->next_enum_id, enable, 1); } -#ifdef DEBUG_INTC if (!source->vect) { - printf("setting interrupt group %d to %d - done\n", id, !!enable); + trace_sh_intc_set(id, !!enable); } -#endif } -static uint64_t sh_intc_read(void *opaque, hwaddr offset, - unsigned size) +static uint64_t sh_intc_read(void *opaque, hwaddr offset, unsigned size) { struct intc_desc *desc = opaque; - intc_enum *enum_ids = NULL; - unsigned int first = 0; - unsigned int width = 0; - unsigned int mode = 0; + intc_enum *enum_ids; + unsigned int first; + unsigned int width; + unsigned int mode; unsigned long *valuep; -#ifdef DEBUG_INTC - printf("sh_intc_read 0x%lx\n", (unsigned long) offset); -#endif - - sh_intc_locate(desc, (unsigned long)offset, &valuep, - &enum_ids, &first, &width, &mode); + sh_intc_locate(desc, (unsigned long)offset, &valuep, + &enum_ids, &first, &width, &mode); + trace_sh_intc_read(size, (uint64_t)offset, *valuep); return *valuep; } @@ -245,45 +214,40 @@ static void sh_intc_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { struct intc_desc *desc = opaque; - intc_enum *enum_ids = NULL; - unsigned int first = 0; - unsigned int width = 0; - unsigned int mode = 0; - unsigned int k; + intc_enum *enum_ids; + unsigned int first; + unsigned int width; + unsigned int mode; unsigned long *valuep; + unsigned int k; unsigned long mask; -#ifdef DEBUG_INTC - printf("sh_intc_write 0x%lx 0x%08x\n", (unsigned long) offset, value); -#endif - - sh_intc_locate(desc, (unsigned long)offset, &valuep, - &enum_ids, &first, &width, &mode); - + trace_sh_intc_write(size, (uint64_t)offset, value); + sh_intc_locate(desc, (unsigned long)offset, &valuep, + &enum_ids, &first, &width, &mode); switch (mode) { - case INTC_MODE_ENABLE_REG | INTC_MODE_IS_PRIO: break; - case INTC_MODE_DUAL_SET: value |= *valuep; break; - case INTC_MODE_DUAL_CLR: value = *valuep & ~value; break; - default: abort(); + case INTC_MODE_ENABLE_REG | INTC_MODE_IS_PRIO: + break; + case INTC_MODE_DUAL_SET: + value |= *valuep; + break; + case INTC_MODE_DUAL_CLR: + value = *valuep & ~value; + break; + default: + g_assert_not_reached(); } for (k = 0; k <= first; k++) { - mask = ((1 << width) - 1) << ((first - k) * width); - - if ((*valuep & mask) == (value & mask)) - continue; -#if 0 - printf("k = %d, first = %d, enum = %d, mask = 0x%08x\n", - k, first, enum_ids[k], (unsigned int)mask); -#endif - sh_intc_toggle_mask(desc, enum_ids[k], value & mask, 0); + mask = (1 << width) - 1; + mask <<= (first - k) * width; + + if ((*valuep & mask) != (value & mask)) { + sh_intc_toggle_mask(desc, enum_ids[k], value & mask, 0); + } } *valuep = value; - -#ifdef DEBUG_INTC - printf("sh_intc_write 0x%lx -> 0x%08x\n", (unsigned long) offset, value); -#endif } static const MemoryRegionOps sh_intc_ops = { @@ -292,155 +256,136 @@ static const MemoryRegionOps sh_intc_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id) -{ - if (id) - return desc->sources + id; - - return NULL; -} - -static unsigned int sh_intc_register(MemoryRegion *sysmem, - struct intc_desc *desc, - const unsigned long address, - const char *type, - const char *action, - const unsigned int index) -{ - char name[60]; - MemoryRegion *iomem, *iomem_p4, *iomem_a7; - - if (!address) { - return 0; - } - - iomem = &desc->iomem; - iomem_p4 = desc->iomem_aliases + index; - iomem_a7 = iomem_p4 + 1; - -#define SH_INTC_IOMEM_FORMAT "interrupt-controller-%s-%s-%s" - snprintf(name, sizeof(name), SH_INTC_IOMEM_FORMAT, type, action, "p4"); - memory_region_init_alias(iomem_p4, NULL, name, iomem, INTC_A7(address), 4); - memory_region_add_subregion(sysmem, P4ADDR(address), iomem_p4); - - snprintf(name, sizeof(name), SH_INTC_IOMEM_FORMAT, type, action, "a7"); - memory_region_init_alias(iomem_a7, NULL, name, iomem, INTC_A7(address), 4); - memory_region_add_subregion(sysmem, A7ADDR(address), iomem_a7); -#undef SH_INTC_IOMEM_FORMAT - - /* used to increment aliases index */ - return 2; -} - static void sh_intc_register_source(struct intc_desc *desc, - intc_enum source, - struct intc_group *groups, - int nr_groups) + intc_enum source, + struct intc_group *groups, + int nr_groups) { unsigned int i, k; - struct intc_source *s; + intc_enum id; if (desc->mask_regs) { for (i = 0; i < desc->nr_mask_regs; i++) { - struct intc_mask_reg *mr = desc->mask_regs + i; - - for (k = 0; k < ARRAY_SIZE(mr->enum_ids); k++) { - if (mr->enum_ids[k] != source) - continue; + struct intc_mask_reg *mr = &desc->mask_regs[i]; - s = sh_intc_source(desc, mr->enum_ids[k]); - if (s) - s->enable_max++; - } - } + for (k = 0; k < ARRAY_SIZE(mr->enum_ids); k++) { + id = mr->enum_ids[k]; + if (id && id == source) { + desc->sources[id].enable_max++; + } + } + } } if (desc->prio_regs) { for (i = 0; i < desc->nr_prio_regs; i++) { - struct intc_prio_reg *pr = desc->prio_regs + i; - - for (k = 0; k < ARRAY_SIZE(pr->enum_ids); k++) { - if (pr->enum_ids[k] != source) - continue; + struct intc_prio_reg *pr = &desc->prio_regs[i]; - s = sh_intc_source(desc, pr->enum_ids[k]); - if (s) - s->enable_max++; - } - } + for (k = 0; k < ARRAY_SIZE(pr->enum_ids); k++) { + id = pr->enum_ids[k]; + if (id && id == source) { + desc->sources[id].enable_max++; + } + } + } } if (groups) { for (i = 0; i < nr_groups; i++) { - struct intc_group *gr = groups + i; + struct intc_group *gr = &groups[i]; - for (k = 0; k < ARRAY_SIZE(gr->enum_ids); k++) { - if (gr->enum_ids[k] != source) - continue; - - s = sh_intc_source(desc, gr->enum_ids[k]); - if (s) - s->enable_max++; - } - } + for (k = 0; k < ARRAY_SIZE(gr->enum_ids); k++) { + id = gr->enum_ids[k]; + if (id && id == source) { + desc->sources[id].enable_max++; + } + } + } } } void sh_intc_register_sources(struct intc_desc *desc, - struct intc_vect *vectors, - int nr_vectors, - struct intc_group *groups, - int nr_groups) + struct intc_vect *vectors, + int nr_vectors, + struct intc_group *groups, + int nr_groups) { unsigned int i, k; + intc_enum id; struct intc_source *s; for (i = 0; i < nr_vectors; i++) { - struct intc_vect *vect = vectors + i; + struct intc_vect *vect = &vectors[i]; - sh_intc_register_source(desc, vect->enum_id, groups, nr_groups); - s = sh_intc_source(desc, vect->enum_id); - if (s) { + sh_intc_register_source(desc, vect->enum_id, groups, nr_groups); + id = vect->enum_id; + if (id) { + s = &desc->sources[id]; s->vect = vect->vect; - -#ifdef DEBUG_INTC_SOURCES - printf("sh_intc: registered source %d -> 0x%04x (%d/%d)\n", - vect->enum_id, s->vect, s->enable_count, s->enable_max); -#endif + trace_sh_intc_register("source", vect->enum_id, s->vect, + s->enable_count, s->enable_max); } } if (groups) { for (i = 0; i < nr_groups; i++) { - struct intc_group *gr = groups + i; + struct intc_group *gr = &groups[i]; + + id = gr->enum_id; + s = &desc->sources[id]; + s->next_enum_id = gr->enum_ids[0]; + + for (k = 1; k < ARRAY_SIZE(gr->enum_ids); k++) { + if (gr->enum_ids[k]) { + id = gr->enum_ids[k - 1]; + s = &desc->sources[id]; + s->next_enum_id = gr->enum_ids[k]; + } + } + trace_sh_intc_register("group", gr->enum_id, 0xffff, + s->enable_count, s->enable_max); + } + } +} + +static unsigned int sh_intc_register(MemoryRegion *sysmem, + struct intc_desc *desc, + const unsigned long address, + const char *type, + const char *action, + const unsigned int index) +{ + char name[60]; + MemoryRegion *iomem, *iomem_p4, *iomem_a7; - s = sh_intc_source(desc, gr->enum_id); - s->next_enum_id = gr->enum_ids[0]; + if (!address) { + return 0; + } - for (k = 1; k < ARRAY_SIZE(gr->enum_ids); k++) { - if (!gr->enum_ids[k]) - continue; + iomem = &desc->iomem; + iomem_p4 = &desc->iomem_aliases[index]; + iomem_a7 = iomem_p4 + 1; - s = sh_intc_source(desc, gr->enum_ids[k - 1]); - s->next_enum_id = gr->enum_ids[k]; - } + snprintf(name, sizeof(name), "intc-%s-%s-%s", type, action, "p4"); + memory_region_init_alias(iomem_p4, NULL, name, iomem, A7ADDR(address), 4); + memory_region_add_subregion(sysmem, P4ADDR(address), iomem_p4); -#ifdef DEBUG_INTC_SOURCES - printf("sh_intc: registered group %d (%d/%d)\n", - gr->enum_id, s->enable_count, s->enable_max); -#endif - } - } + snprintf(name, sizeof(name), "intc-%s-%s-%s", type, action, "a7"); + memory_region_init_alias(iomem_a7, NULL, name, iomem, A7ADDR(address), 4); + memory_region_add_subregion(sysmem, A7ADDR(address), iomem_a7); + + /* used to increment aliases index */ + return 2; } int sh_intc_init(MemoryRegion *sysmem, - struct intc_desc *desc, - int nr_sources, - struct intc_mask_reg *mask_regs, - int nr_mask_regs, - struct intc_prio_reg *prio_regs, - int nr_prio_regs) + struct intc_desc *desc, + int nr_sources, + struct intc_mask_reg *mask_regs, + int nr_mask_regs, + struct intc_prio_reg *prio_regs, + int nr_prio_regs) { unsigned int i, j; @@ -450,65 +395,55 @@ int sh_intc_init(MemoryRegion *sysmem, desc->nr_mask_regs = nr_mask_regs; desc->prio_regs = prio_regs; desc->nr_prio_regs = nr_prio_regs; - /* Allocate 4 MemoryRegions per register (2 actions * 2 aliases). - **/ + /* Allocate 4 MemoryRegions per register (2 actions * 2 aliases) */ desc->iomem_aliases = g_new0(MemoryRegion, (nr_mask_regs + nr_prio_regs) * 4); - - j = 0; - i = sizeof(struct intc_source) * nr_sources; - desc->sources = g_malloc0(i); - - for (i = 0; i < desc->nr_sources; i++) { - struct intc_source *source = desc->sources + i; - - source->parent = desc; + desc->sources = g_new0(struct intc_source, nr_sources); + for (i = 0; i < nr_sources; i++) { + desc->sources[i].parent = desc; } - desc->irqs = qemu_allocate_irqs(sh_intc_set_irq, desc, nr_sources); - - memory_region_init_io(&desc->iomem, NULL, &sh_intc_ops, desc, - "interrupt-controller", 0x100000000ULL); - -#define INT_REG_PARAMS(reg_struct, type, action, j) \ - reg_struct->action##_reg, #type, #action, j + memory_region_init_io(&desc->iomem, NULL, &sh_intc_ops, desc, "intc", + 0x100000000ULL); + j = 0; if (desc->mask_regs) { for (i = 0; i < desc->nr_mask_regs; i++) { - struct intc_mask_reg *mr = desc->mask_regs + i; + struct intc_mask_reg *mr = &desc->mask_regs[i]; - j += sh_intc_register(sysmem, desc, - INT_REG_PARAMS(mr, mask, set, j)); - j += sh_intc_register(sysmem, desc, - INT_REG_PARAMS(mr, mask, clr, j)); - } + j += sh_intc_register(sysmem, desc, mr->set_reg, "mask", "set", j); + j += sh_intc_register(sysmem, desc, mr->clr_reg, "mask", "clr", j); + } } if (desc->prio_regs) { for (i = 0; i < desc->nr_prio_regs; i++) { - struct intc_prio_reg *pr = desc->prio_regs + i; + struct intc_prio_reg *pr = &desc->prio_regs[i]; - j += sh_intc_register(sysmem, desc, - INT_REG_PARAMS(pr, prio, set, j)); - j += sh_intc_register(sysmem, desc, - INT_REG_PARAMS(pr, prio, clr, j)); - } + j += sh_intc_register(sysmem, desc, pr->set_reg, "prio", "set", j); + j += sh_intc_register(sysmem, desc, pr->clr_reg, "prio", "clr", j); + } } -#undef INT_REG_PARAMS return 0; } -/* Assert level <n> IRL interrupt. - 0:deassert. 1:lowest priority,... 15:highest priority. */ +/* + * Assert level <n> IRL interrupt. + * 0:deassert. 1:lowest priority,... 15:highest priority + */ void sh_intc_set_irl(void *opaque, int n, int level) { struct intc_source *s = opaque; int i, irl = level ^ 15; - for (i = 0; (s = sh_intc_source(s->parent, s->next_enum_id)); i++) { - if (i == irl) - sh_intc_toggle_source(s, s->enable_count?0:1, s->asserted?0:1); - else - if (s->asserted) - sh_intc_toggle_source(s, 0, -1); + intc_enum id = s->next_enum_id; + + for (i = 0; id; id = s->next_enum_id, i++) { + s = &s->parent->sources[id]; + if (i == irl) { + sh_intc_toggle_source(s, s->enable_count ? 0 : 1, + s->asserted ? 0 : 1); + } else if (s->asserted) { + sh_intc_toggle_source(s, 0, -1); + } } } diff --git a/hw/intc/trace-events b/hw/intc/trace-events index 6a17d38998..9aba7e3a7a 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -238,3 +238,11 @@ goldfish_pic_write(void *dev, int idx, unsigned int addr, unsigned int size, uin goldfish_pic_reset(void *dev, int idx) "pic: %p goldfish-irq.%d" goldfish_pic_realize(void *dev, int idx) "pic: %p goldfish-irq.%d" goldfish_pic_instance_init(void *dev) "pic: %p goldfish-irq" + +# sh_intc.c +sh_intc_sources(int p, int a, int c, int m, unsigned short v, const char *s1, const char *s2, const char *s3) "(%d/%d/%d/%d) interrupt source 0x%x %s%s%s" +sh_intc_pending(int p, unsigned short v) "(%d) returning interrupt source 0x%x" +sh_intc_register(const char *s, int id, unsigned short v, int c, int m) "%s %u -> 0x%04x (%d/%d)" +sh_intc_read(unsigned size, uint64_t offset, unsigned long val) "size %u 0x%" PRIx64 " -> 0x%lx" +sh_intc_write(unsigned size, uint64_t offset, unsigned long val) "size %u 0x%" PRIx64 " <- 0x%lx" +sh_intc_set(int id, int enable) "setting interrupt group %d to %d" diff --git a/hw/pci-host/sh_pci.c b/hw/pci-host/sh_pci.c index 08c1562e22..719d6ca2a6 100644 --- a/hw/pci-host/sh_pci.c +++ b/hw/pci-host/sh_pci.c @@ -49,13 +49,12 @@ struct SHPCIState { uint32_t iobr; }; -static void sh_pci_reg_write (void *p, hwaddr addr, uint64_t val, - unsigned size) +static void sh_pci_reg_write(void *p, hwaddr addr, uint64_t val, unsigned size) { SHPCIState *pcic = p; PCIHostState *phb = PCI_HOST_BRIDGE(pcic); - switch(addr) { + switch (addr) { case 0 ... 0xfc: stl_le_p(pcic->dev->config + addr, val); break; @@ -75,13 +74,12 @@ static void sh_pci_reg_write (void *p, hwaddr addr, uint64_t val, } } -static uint64_t sh_pci_reg_read (void *p, hwaddr addr, - unsigned size) +static uint64_t sh_pci_reg_read(void *p, hwaddr addr, unsigned size) { SHPCIState *pcic = p; PCIHostState *phb = PCI_HOST_BRIDGE(pcic); - switch(addr) { + switch (addr) { case 0 ... 0xfc: return ldl_le_p(pcic->dev->config + addr); case 0x1c0: diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c index 006010f30a..72759413f3 100644 --- a/hw/sh4/r2d.c +++ b/hw/sh4/r2d.c @@ -26,6 +26,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qapi/error.h" +#include "qemu/error-report.h" #include "cpu.h" #include "hw/sysbus.h" #include "hw/sh4/sh.h" @@ -56,10 +57,10 @@ #define LINUX_LOAD_OFFSET 0x0800000 #define INITRD_LOAD_OFFSET 0x1800000 -#define PA_IRLMSK 0x00 -#define PA_POWOFF 0x30 -#define PA_VERREG 0x32 -#define PA_OUTPORT 0x36 +#define PA_IRLMSK 0x00 +#define PA_POWOFF 0x30 +#define PA_VERREG 0x32 +#define PA_OUTPORT 0x36 typedef struct { uint16_t bcr; @@ -96,38 +97,41 @@ enum r2d_fpga_irq { }; static const struct { short irl; uint16_t msk; } irqtab[NR_IRQS] = { - [CF_IDE] = { 1, 1<<9 }, - [CF_CD] = { 2, 1<<8 }, - [PCI_INTA] = { 9, 1<<14 }, - [PCI_INTB] = { 10, 1<<13 }, - [PCI_INTC] = { 3, 1<<12 }, - [PCI_INTD] = { 0, 1<<11 }, - [SM501] = { 4, 1<<10 }, - [KEY] = { 5, 1<<6 }, - [RTC_A] = { 6, 1<<5 }, - [RTC_T] = { 7, 1<<4 }, - [SDCARD] = { 8, 1<<7 }, - [EXT] = { 11, 1<<0 }, - [TP] = { 12, 1<<15 }, + [CF_IDE] = { 1, 1 << 9 }, + [CF_CD] = { 2, 1 << 8 }, + [PCI_INTA] = { 9, 1 << 14 }, + [PCI_INTB] = { 10, 1 << 13 }, + [PCI_INTC] = { 3, 1 << 12 }, + [PCI_INTD] = { 0, 1 << 11 }, + [SM501] = { 4, 1 << 10 }, + [KEY] = { 5, 1 << 6 }, + [RTC_A] = { 6, 1 << 5 }, + [RTC_T] = { 7, 1 << 4 }, + [SDCARD] = { 8, 1 << 7 }, + [EXT] = { 11, 1 << 0 }, + [TP] = { 12, 1 << 15 }, }; static void update_irl(r2d_fpga_t *fpga) { int i, irl = 15; - for (i = 0; i < NR_IRQS; i++) - if (fpga->irlmon & fpga->irlmsk & irqtab[i].msk) - if (irqtab[i].irl < irl) - irl = irqtab[i].irl; + for (i = 0; i < NR_IRQS; i++) { + if ((fpga->irlmon & fpga->irlmsk & irqtab[i].msk) && + irqtab[i].irl < irl) { + irl = irqtab[i].irl; + } + } qemu_set_irq(fpga->irl, irl ^ 15); } static void r2d_fpga_irq_set(void *opaque, int n, int level) { r2d_fpga_t *fpga = opaque; - if (level) + if (level) { fpga->irlmon |= irqtab[n].msk; - else + } else { fpga->irlmon &= ~irqtab[n].msk; + } update_irl(fpga); } @@ -306,7 +310,7 @@ static void r2d_init(MachineState *machine) /* NIC: rtl8139 on-board, and 2 slots. */ for (i = 0; i < nb_nics; i++) pci_nic_init_nofail(&nd_table[i], pci_bus, - "rtl8139", i==0 ? "2" : NULL); + "rtl8139", i == 0 ? "2" : NULL); /* USB keyboard */ usb_create_simple(usb_bus_find(-1), "usb-kbd"); @@ -321,8 +325,8 @@ static void r2d_init(MachineState *machine) SDRAM_BASE + LINUX_LOAD_OFFSET, INITRD_LOAD_OFFSET - LINUX_LOAD_OFFSET); if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); - exit(1); + error_report("qemu: could not load kernel '%s'", kernel_filename); + exit(1); } /* initialization which should be done by firmware */ @@ -330,7 +334,8 @@ static void r2d_init(MachineState *machine) MEMTXATTRS_UNSPECIFIED, NULL); /* cs3 SDRAM */ address_space_stw(&address_space_memory, SH7750_BCR2, 3 << (3 * 2), MEMTXATTRS_UNSPECIFIED, NULL); /* cs3 32bit */ - reset_info->vector = (SDRAM_BASE + LINUX_LOAD_OFFSET) | 0xa0000000; /* Start from P2 area */ + /* Start from P2 area */ + reset_info->vector = (SDRAM_BASE + LINUX_LOAD_OFFSET) | 0xa0000000; } if (initrd_filename) { @@ -341,8 +346,8 @@ static void r2d_init(MachineState *machine) SDRAM_SIZE - INITRD_LOAD_OFFSET); if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initrd '%s'\n", initrd_filename); - exit(1); + error_report("qemu: could not load initrd '%s'", initrd_filename); + exit(1); } /* initialization which should be done by firmware */ @@ -352,8 +357,10 @@ static void r2d_init(MachineState *machine) } if (kernel_cmdline) { - /* I see no evidence that this .kernel_cmdline buffer requires - NUL-termination, so using strncpy should be ok. */ + /* + * I see no evidence that this .kernel_cmdline buffer requires + * NUL-termination, so using strncpy should be ok. + */ strncpy(boot_params.kernel_cmdline, kernel_cmdline, sizeof(boot_params.kernel_cmdline)); } diff --git a/hw/sh4/sh7750.c b/hw/sh4/sh7750.c index d53a436d8c..43dfb6497b 100644 --- a/hw/sh4/sh7750.c +++ b/hw/sh4/sh7750.c @@ -24,14 +24,19 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/sysbus.h" #include "hw/irq.h" #include "hw/sh4/sh.h" #include "sysemu/sysemu.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" #include "sh7750_regs.h" #include "sh7750_regnames.h" #include "hw/sh4/sh_intc.h" #include "hw/timer/tmu012.h" #include "exec/exec-all.h" +#include "trace.h" #define NB_DEVICES 4 @@ -60,17 +65,17 @@ typedef struct SH7750State { uint16_t gpioic; uint32_t pctra; uint32_t pctrb; - uint16_t portdira; /* Cached */ - uint16_t portpullupa; /* Cached */ - uint16_t portdirb; /* Cached */ - uint16_t portpullupb; /* Cached */ + uint16_t portdira; /* Cached */ + uint16_t portpullupa; /* Cached */ + uint16_t portdirb; /* Cached */ + uint16_t portpullupb; /* Cached */ uint16_t pdtra; uint16_t pdtrb; - uint16_t periph_pdtra; /* Imposed by the peripherals */ - uint16_t periph_portdira; /* Direction seen from the peripherals */ - uint16_t periph_pdtrb; /* Imposed by the peripherals */ - uint16_t periph_portdirb; /* Direction seen from the peripherals */ - sh7750_io_device *devices[NB_DEVICES]; /* External peripherals */ + uint16_t periph_pdtra; /* Imposed by the peripherals */ + uint16_t periph_portdira; /* Direction seen from the peripherals */ + uint16_t periph_pdtrb; /* Imposed by the peripherals */ + uint16_t periph_portdirb; /* Direction seen from the peripherals */ + sh7750_io_device *devices[NB_DEVICES]; /* External peripherals */ /* Cache */ uint32_t ccr; @@ -78,143 +83,145 @@ typedef struct SH7750State { struct intc_desc intc; } SH7750State; -static inline int has_bcr3_and_bcr4(SH7750State * s) +static inline int has_bcr3_and_bcr4(SH7750State *s) { return s->cpu->env.features & SH_FEATURE_BCR3_AND_BCR4; } -/********************************************************************** - I/O ports -**********************************************************************/ -int sh7750_register_io_device(SH7750State * s, sh7750_io_device * device) +/* + * I/O ports + */ + +int sh7750_register_io_device(SH7750State *s, sh7750_io_device *device) { int i; for (i = 0; i < NB_DEVICES; i++) { - if (s->devices[i] == NULL) { - s->devices[i] = device; - return 0; - } + if (s->devices[i] == NULL) { + s->devices[i] = device; + return 0; + } } return -1; } static uint16_t portdir(uint32_t v) { -#define EVENPORTMASK(n) ((v & (1<<((n)<<1))) >> (n)) +#define EVENPORTMASK(n) ((v & (1 << ((n) << 1))) >> (n)) return - EVENPORTMASK(15) | EVENPORTMASK(14) | EVENPORTMASK(13) | - EVENPORTMASK(12) | EVENPORTMASK(11) | EVENPORTMASK(10) | - EVENPORTMASK(9) | EVENPORTMASK(8) | EVENPORTMASK(7) | - EVENPORTMASK(6) | EVENPORTMASK(5) | EVENPORTMASK(4) | - EVENPORTMASK(3) | EVENPORTMASK(2) | EVENPORTMASK(1) | - EVENPORTMASK(0); + EVENPORTMASK(15) | EVENPORTMASK(14) | EVENPORTMASK(13) | + EVENPORTMASK(12) | EVENPORTMASK(11) | EVENPORTMASK(10) | + EVENPORTMASK(9) | EVENPORTMASK(8) | EVENPORTMASK(7) | + EVENPORTMASK(6) | EVENPORTMASK(5) | EVENPORTMASK(4) | + EVENPORTMASK(3) | EVENPORTMASK(2) | EVENPORTMASK(1) | + EVENPORTMASK(0); } static uint16_t portpullup(uint32_t v) { -#define ODDPORTMASK(n) ((v & (1<<(((n)<<1)+1))) >> (n)) +#define ODDPORTMASK(n) ((v & (1 << (((n) << 1) + 1))) >> (n)) return - ODDPORTMASK(15) | ODDPORTMASK(14) | ODDPORTMASK(13) | - ODDPORTMASK(12) | ODDPORTMASK(11) | ODDPORTMASK(10) | - ODDPORTMASK(9) | ODDPORTMASK(8) | ODDPORTMASK(7) | ODDPORTMASK(6) | - ODDPORTMASK(5) | ODDPORTMASK(4) | ODDPORTMASK(3) | ODDPORTMASK(2) | - ODDPORTMASK(1) | ODDPORTMASK(0); + ODDPORTMASK(15) | ODDPORTMASK(14) | ODDPORTMASK(13) | + ODDPORTMASK(12) | ODDPORTMASK(11) | ODDPORTMASK(10) | + ODDPORTMASK(9) | ODDPORTMASK(8) | ODDPORTMASK(7) | ODDPORTMASK(6) | + ODDPORTMASK(5) | ODDPORTMASK(4) | ODDPORTMASK(3) | ODDPORTMASK(2) | + ODDPORTMASK(1) | ODDPORTMASK(0); } -static uint16_t porta_lines(SH7750State * s) +static uint16_t porta_lines(SH7750State *s) { - return (s->portdira & s->pdtra) | /* CPU */ - (s->periph_portdira & s->periph_pdtra) | /* Peripherals */ - (~(s->portdira | s->periph_portdira) & s->portpullupa); /* Pullups */ + return (s->portdira & s->pdtra) | /* CPU */ + (s->periph_portdira & s->periph_pdtra) | /* Peripherals */ + (~(s->portdira | s->periph_portdira) & s->portpullupa); /* Pullups */ } -static uint16_t portb_lines(SH7750State * s) +static uint16_t portb_lines(SH7750State *s) { - return (s->portdirb & s->pdtrb) | /* CPU */ - (s->periph_portdirb & s->periph_pdtrb) | /* Peripherals */ - (~(s->portdirb | s->periph_portdirb) & s->portpullupb); /* Pullups */ + return (s->portdirb & s->pdtrb) | /* CPU */ + (s->periph_portdirb & s->periph_pdtrb) | /* Peripherals */ + (~(s->portdirb | s->periph_portdirb) & s->portpullupb); /* Pullups */ } -static void gen_port_interrupts(SH7750State * s) +static void gen_port_interrupts(SH7750State *s) { /* XXXXX interrupts not generated */ } -static void porta_changed(SH7750State * s, uint16_t prev) +static void porta_changed(SH7750State *s, uint16_t prev) { uint16_t currenta, changes; int i, r = 0; -#if 0 - fprintf(stderr, "porta changed from 0x%04x to 0x%04x\n", - prev, porta_lines(s)); - fprintf(stderr, "pdtra=0x%04x, pctra=0x%08x\n", s->pdtra, s->pctra); -#endif currenta = porta_lines(s); - if (currenta == prev) - return; + if (currenta == prev) { + return; + } + trace_sh7750_porta(prev, currenta, s->pdtra, s->pctra); changes = currenta ^ prev; for (i = 0; i < NB_DEVICES; i++) { - if (s->devices[i] && (s->devices[i]->portamask_trigger & changes)) { - r |= s->devices[i]->port_change_cb(currenta, portb_lines(s), - &s->periph_pdtra, - &s->periph_portdira, - &s->periph_pdtrb, - &s->periph_portdirb); - } + if (s->devices[i] && (s->devices[i]->portamask_trigger & changes)) { + r |= s->devices[i]->port_change_cb(currenta, portb_lines(s), + &s->periph_pdtra, + &s->periph_portdira, + &s->periph_pdtrb, + &s->periph_portdirb); + } } - if (r) - gen_port_interrupts(s); + if (r) { + gen_port_interrupts(s); + } } -static void portb_changed(SH7750State * s, uint16_t prev) +static void portb_changed(SH7750State *s, uint16_t prev) { uint16_t currentb, changes; int i, r = 0; currentb = portb_lines(s); - if (currentb == prev) - return; + if (currentb == prev) { + return; + } + trace_sh7750_portb(prev, currentb, s->pdtrb, s->pctrb); changes = currentb ^ prev; for (i = 0; i < NB_DEVICES; i++) { - if (s->devices[i] && (s->devices[i]->portbmask_trigger & changes)) { - r |= s->devices[i]->port_change_cb(portb_lines(s), currentb, - &s->periph_pdtra, - &s->periph_portdira, - &s->periph_pdtrb, - &s->periph_portdirb); - } + if (s->devices[i] && (s->devices[i]->portbmask_trigger & changes)) { + r |= s->devices[i]->port_change_cb(portb_lines(s), currentb, + &s->periph_pdtra, + &s->periph_portdira, + &s->periph_pdtrb, + &s->periph_portdirb); + } } - if (r) - gen_port_interrupts(s); + if (r) { + gen_port_interrupts(s); + } } -/********************************************************************** - Memory -**********************************************************************/ +/* + * Memory + */ static void error_access(const char *kind, hwaddr addr) { fprintf(stderr, "%s to %s (0x" TARGET_FMT_plx ") not supported\n", - kind, regname(addr), addr); + kind, regname(addr), addr); } static void ignore_access(const char *kind, hwaddr addr) { fprintf(stderr, "%s to %s (0x" TARGET_FMT_plx ") ignored\n", - kind, regname(addr), addr); + kind, regname(addr), addr); } static uint32_t sh7750_mem_readb(void *opaque, hwaddr addr) { switch (addr) { default: - error_access("byte read", addr); + error_access("byte read", addr); abort(); } } @@ -225,30 +232,31 @@ static uint32_t sh7750_mem_readw(void *opaque, hwaddr addr) switch (addr) { case SH7750_BCR2_A7: - return s->bcr2; + return s->bcr2; case SH7750_BCR3_A7: - if(!has_bcr3_and_bcr4(s)) - error_access("word read", addr); - return s->bcr3; + if (!has_bcr3_and_bcr4(s)) { + error_access("word read", addr); + } + return s->bcr3; case SH7750_FRQCR_A7: - return 0; + return 0; case SH7750_PCR_A7: - return s->pcr; + return s->pcr; case SH7750_RFCR_A7: - fprintf(stderr, - "Read access to refresh count register, incrementing\n"); - return s->rfcr++; + fprintf(stderr, + "Read access to refresh count register, incrementing\n"); + return s->rfcr++; case SH7750_PDTRA_A7: - return porta_lines(s); + return porta_lines(s); case SH7750_PDTRB_A7: - return portb_lines(s); + return portb_lines(s); case SH7750_RTCOR_A7: case SH7750_RTCNT_A7: case SH7750_RTCSR_A7: - ignore_access("word read", addr); - return 0; + ignore_access("word read", addr); + return 0; default: - error_access("word read", addr); + error_access("word read", addr); abort(); } } @@ -260,11 +268,12 @@ static uint32_t sh7750_mem_readl(void *opaque, hwaddr addr) switch (addr) { case SH7750_BCR1_A7: - return s->bcr1; + return s->bcr1; case SH7750_BCR4_A7: - if(!has_bcr3_and_bcr4(s)) - error_access("long read", addr); - return s->bcr4; + if (!has_bcr3_and_bcr4(s)) { + error_access("long read", addr); + } + return s->bcr4; case SH7750_WCR1_A7: case SH7750_WCR2_A7: case SH7750_WCR3_A7: @@ -288,31 +297,31 @@ static uint32_t sh7750_mem_readl(void *opaque, hwaddr addr) case SH7750_INTEVT_A7: return s->cpu->env.intevt; case SH7750_CCR_A7: - return s->ccr; - case 0x1f000030: /* Processor version */ + return s->ccr; + case 0x1f000030: /* Processor version */ scc = SUPERH_CPU_GET_CLASS(s->cpu); return scc->pvr; - case 0x1f000040: /* Cache version */ + case 0x1f000040: /* Cache version */ scc = SUPERH_CPU_GET_CLASS(s->cpu); return scc->cvr; - case 0x1f000044: /* Processor revision */ + case 0x1f000044: /* Processor revision */ scc = SUPERH_CPU_GET_CLASS(s->cpu); return scc->prr; default: - error_access("long read", addr); + error_access("long read", addr); abort(); } } #define is_in_sdrmx(a, x) (a >= SH7750_SDMR ## x ## _A7 \ - && a <= (SH7750_SDMR ## x ## _A7 + SH7750_SDMR ## x ## _REGNB)) + && a <= (SH7750_SDMR ## x ## _A7 + SH7750_SDMR ## x ## _REGNB)) static void sh7750_mem_writeb(void *opaque, hwaddr addr, - uint32_t mem_value) + uint32_t mem_value) { if (is_in_sdrmx(addr, 2) || is_in_sdrmx(addr, 3)) { - ignore_access("byte write", addr); - return; + ignore_access("byte write", addr); + return; } error_access("byte write", addr); @@ -320,94 +329,96 @@ static void sh7750_mem_writeb(void *opaque, hwaddr addr, } static void sh7750_mem_writew(void *opaque, hwaddr addr, - uint32_t mem_value) + uint32_t mem_value) { SH7750State *s = opaque; uint16_t temp; switch (addr) { - /* SDRAM controller */ + /* SDRAM controller */ case SH7750_BCR2_A7: s->bcr2 = mem_value; return; case SH7750_BCR3_A7: - if(!has_bcr3_and_bcr4(s)) - error_access("word write", addr); - s->bcr3 = mem_value; - return; + if (!has_bcr3_and_bcr4(s)) { + error_access("word write", addr); + } + s->bcr3 = mem_value; + return; case SH7750_PCR_A7: - s->pcr = mem_value; - return; + s->pcr = mem_value; + return; case SH7750_RTCNT_A7: case SH7750_RTCOR_A7: case SH7750_RTCSR_A7: - ignore_access("word write", addr); - return; - /* IO ports */ + ignore_access("word write", addr); + return; + /* IO ports */ case SH7750_PDTRA_A7: - temp = porta_lines(s); - s->pdtra = mem_value; - porta_changed(s, temp); - return; + temp = porta_lines(s); + s->pdtra = mem_value; + porta_changed(s, temp); + return; case SH7750_PDTRB_A7: - temp = portb_lines(s); - s->pdtrb = mem_value; - portb_changed(s, temp); - return; + temp = portb_lines(s); + s->pdtrb = mem_value; + portb_changed(s, temp); + return; case SH7750_RFCR_A7: - fprintf(stderr, "Write access to refresh count register\n"); - s->rfcr = mem_value; - return; + fprintf(stderr, "Write access to refresh count register\n"); + s->rfcr = mem_value; + return; case SH7750_GPIOIC_A7: - s->gpioic = mem_value; - if (mem_value != 0) { - fprintf(stderr, "I/O interrupts not implemented\n"); + s->gpioic = mem_value; + if (mem_value != 0) { + fprintf(stderr, "I/O interrupts not implemented\n"); abort(); - } - return; + } + return; default: - error_access("word write", addr); + error_access("word write", addr); abort(); } } static void sh7750_mem_writel(void *opaque, hwaddr addr, - uint32_t mem_value) + uint32_t mem_value) { SH7750State *s = opaque; uint16_t temp; switch (addr) { - /* SDRAM controller */ + /* SDRAM controller */ case SH7750_BCR1_A7: s->bcr1 = mem_value; return; case SH7750_BCR4_A7: - if(!has_bcr3_and_bcr4(s)) - error_access("long write", addr); - s->bcr4 = mem_value; - return; + if (!has_bcr3_and_bcr4(s)) { + error_access("long write", addr); + } + s->bcr4 = mem_value; + return; case SH7750_WCR1_A7: case SH7750_WCR2_A7: case SH7750_WCR3_A7: case SH7750_MCR_A7: - ignore_access("long write", addr); - return; - /* IO ports */ + ignore_access("long write", addr); + return; + /* IO ports */ case SH7750_PCTRA_A7: - temp = porta_lines(s); - s->pctra = mem_value; - s->portdira = portdir(mem_value); - s->portpullupa = portpullup(mem_value); - porta_changed(s, temp); - return; + temp = porta_lines(s); + s->pctra = mem_value; + s->portdira = portdir(mem_value); + s->portpullupa = portpullup(mem_value); + porta_changed(s, temp); + return; case SH7750_PCTRB_A7: - temp = portb_lines(s); - s->pctrb = mem_value; - s->portdirb = portdir(mem_value); - s->portpullupb = portpullup(mem_value); - portb_changed(s, temp); - return; + temp = portb_lines(s); + s->pctrb = mem_value; + s->portdirb = portdir(mem_value); + s->portpullupb = portpullup(mem_value); + portb_changed(s, temp); + return; case SH7750_MMUCR_A7: if (mem_value & MMUCR_TI) { cpu_sh4_invalidate_tlb(&s->cpu->env); @@ -443,10 +454,10 @@ static void sh7750_mem_writel(void *opaque, hwaddr addr, s->cpu->env.intevt = mem_value & 0x000007ff; return; case SH7750_CCR_A7: - s->ccr = mem_value; - return; + s->ccr = mem_value; + return; default: - error_access("long write", addr); + error_access("long write", addr); abort(); } } @@ -491,161 +502,161 @@ static const MemoryRegionOps sh7750_mem_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -/* sh775x interrupt controller tables for sh_intc.c +/* + * sh775x interrupt controller tables for sh_intc.c * stolen from linux/arch/sh/kernel/cpu/sh4/setup-sh7750.c */ enum { - UNUSED = 0, - - /* interrupt sources */ - IRL_0, IRL_1, IRL_2, IRL_3, IRL_4, IRL_5, IRL_6, IRL_7, - IRL_8, IRL_9, IRL_A, IRL_B, IRL_C, IRL_D, IRL_E, - IRL0, IRL1, IRL2, IRL3, - HUDI, GPIOI, - DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3, - DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7, - DMAC_DMAE, - PCIC0_PCISERR, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, - PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3, - TMU3, TMU4, TMU0, TMU1, TMU2_TUNI, TMU2_TICPI, - RTC_ATI, RTC_PRI, RTC_CUI, - SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI, - SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI, - WDT, - REF_RCMI, REF_ROVI, - - /* interrupt groups */ - DMAC, PCIC1, TMU2, RTC, SCI1, SCIF, REF, - /* irl bundle */ - IRL, - - NR_SOURCES, + UNUSED = 0, + + /* interrupt sources */ + IRL_0, IRL_1, IRL_2, IRL_3, IRL_4, IRL_5, IRL_6, IRL_7, + IRL_8, IRL_9, IRL_A, IRL_B, IRL_C, IRL_D, IRL_E, + IRL0, IRL1, IRL2, IRL3, + HUDI, GPIOI, + DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3, + DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7, + DMAC_DMAE, + PCIC0_PCISERR, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, + PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3, + TMU3, TMU4, TMU0, TMU1, TMU2_TUNI, TMU2_TICPI, + RTC_ATI, RTC_PRI, RTC_CUI, + SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI, + SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI, + WDT, + REF_RCMI, REF_ROVI, + + /* interrupt groups */ + DMAC, PCIC1, TMU2, RTC, SCI1, SCIF, REF, + /* irl bundle */ + IRL, + + NR_SOURCES, }; static struct intc_vect vectors[] = { - INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620), - INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420), - INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460), - INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0), - INTC_VECT(RTC_CUI, 0x4c0), - INTC_VECT(SCI1_ERI, 0x4e0), INTC_VECT(SCI1_RXI, 0x500), - INTC_VECT(SCI1_TXI, 0x520), INTC_VECT(SCI1_TEI, 0x540), - INTC_VECT(SCIF_ERI, 0x700), INTC_VECT(SCIF_RXI, 0x720), - INTC_VECT(SCIF_BRI, 0x740), INTC_VECT(SCIF_TXI, 0x760), - INTC_VECT(WDT, 0x560), - INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0), + INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620), + INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420), + INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460), + INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0), + INTC_VECT(RTC_CUI, 0x4c0), + INTC_VECT(SCI1_ERI, 0x4e0), INTC_VECT(SCI1_RXI, 0x500), + INTC_VECT(SCI1_TXI, 0x520), INTC_VECT(SCI1_TEI, 0x540), + INTC_VECT(SCIF_ERI, 0x700), INTC_VECT(SCIF_RXI, 0x720), + INTC_VECT(SCIF_BRI, 0x740), INTC_VECT(SCIF_TXI, 0x760), + INTC_VECT(WDT, 0x560), + INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0), }; static struct intc_group groups[] = { - INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI), - INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI), - INTC_GROUP(SCI1, SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI), - INTC_GROUP(SCIF, SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI), - INTC_GROUP(REF, REF_RCMI, REF_ROVI), + INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI), + INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI), + INTC_GROUP(SCI1, SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI), + INTC_GROUP(SCIF, SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI), + INTC_GROUP(REF, REF_RCMI, REF_ROVI), }; static struct intc_prio_reg prio_registers[] = { - { 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } }, - { 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } }, - { 0xffd0000c, 0, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } }, - { 0xffd00010, 0, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } }, - { 0xfe080000, 0, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0, - TMU4, TMU3, - PCIC1, PCIC0_PCISERR } }, + { 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } }, + { 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } }, + { 0xffd0000c, 0, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } }, + { 0xffd00010, 0, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } }, + { 0xfe080000, 0, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0, TMU4, TMU3, + PCIC1, PCIC0_PCISERR } }, }; /* SH7750, SH7750S, SH7751 and SH7091 all have 4-channel DMA controllers */ static struct intc_vect vectors_dma4[] = { - INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660), - INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0), - INTC_VECT(DMAC_DMAE, 0x6c0), + INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660), + INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0), + INTC_VECT(DMAC_DMAE, 0x6c0), }; static struct intc_group groups_dma4[] = { - INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, - DMAC_DMTE3, DMAC_DMAE), + INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, + DMAC_DMTE3, DMAC_DMAE), }; /* SH7750R and SH7751R both have 8-channel DMA controllers */ static struct intc_vect vectors_dma8[] = { - INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660), - INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0), - INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0), - INTC_VECT(DMAC_DMTE6, 0x7c0), INTC_VECT(DMAC_DMTE7, 0x7e0), - INTC_VECT(DMAC_DMAE, 0x6c0), + INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660), + INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0), + INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0), + INTC_VECT(DMAC_DMTE6, 0x7c0), INTC_VECT(DMAC_DMTE7, 0x7e0), + INTC_VECT(DMAC_DMAE, 0x6c0), }; static struct intc_group groups_dma8[] = { - INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, - DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5, - DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE), + INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, + DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5, + DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE), }; /* SH7750R, SH7751 and SH7751R all have two extra timer channels */ static struct intc_vect vectors_tmu34[] = { - INTC_VECT(TMU3, 0xb00), INTC_VECT(TMU4, 0xb80), + INTC_VECT(TMU3, 0xb00), INTC_VECT(TMU4, 0xb80), }; static struct intc_mask_reg mask_registers[] = { - { 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, TMU4, TMU3, - PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, - PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, - PCIC1_PCIDMA3, PCIC0_PCISERR } }, + { 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, TMU4, TMU3, + PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, + PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, + PCIC1_PCIDMA3, PCIC0_PCISERR } }, }; /* SH7750S, SH7750R, SH7751 and SH7751R all have IRLM priority registers */ static struct intc_vect vectors_irlm[] = { - INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0), - INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360), + INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0), + INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360), }; /* SH7751 and SH7751R both have PCI */ static struct intc_vect vectors_pci[] = { - INTC_VECT(PCIC0_PCISERR, 0xa00), INTC_VECT(PCIC1_PCIERR, 0xae0), - INTC_VECT(PCIC1_PCIPWDWN, 0xac0), INTC_VECT(PCIC1_PCIPWON, 0xaa0), - INTC_VECT(PCIC1_PCIDMA0, 0xa80), INTC_VECT(PCIC1_PCIDMA1, 0xa60), - INTC_VECT(PCIC1_PCIDMA2, 0xa40), INTC_VECT(PCIC1_PCIDMA3, 0xa20), + INTC_VECT(PCIC0_PCISERR, 0xa00), INTC_VECT(PCIC1_PCIERR, 0xae0), + INTC_VECT(PCIC1_PCIPWDWN, 0xac0), INTC_VECT(PCIC1_PCIPWON, 0xaa0), + INTC_VECT(PCIC1_PCIDMA0, 0xa80), INTC_VECT(PCIC1_PCIDMA1, 0xa60), + INTC_VECT(PCIC1_PCIDMA2, 0xa40), INTC_VECT(PCIC1_PCIDMA3, 0xa20), }; static struct intc_group groups_pci[] = { - INTC_GROUP(PCIC1, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, - PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3), + INTC_GROUP(PCIC1, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, + PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3), }; static struct intc_vect vectors_irl[] = { - INTC_VECT(IRL_0, 0x200), - INTC_VECT(IRL_1, 0x220), - INTC_VECT(IRL_2, 0x240), - INTC_VECT(IRL_3, 0x260), - INTC_VECT(IRL_4, 0x280), - INTC_VECT(IRL_5, 0x2a0), - INTC_VECT(IRL_6, 0x2c0), - INTC_VECT(IRL_7, 0x2e0), - INTC_VECT(IRL_8, 0x300), - INTC_VECT(IRL_9, 0x320), - INTC_VECT(IRL_A, 0x340), - INTC_VECT(IRL_B, 0x360), - INTC_VECT(IRL_C, 0x380), - INTC_VECT(IRL_D, 0x3a0), - INTC_VECT(IRL_E, 0x3c0), + INTC_VECT(IRL_0, 0x200), + INTC_VECT(IRL_1, 0x220), + INTC_VECT(IRL_2, 0x240), + INTC_VECT(IRL_3, 0x260), + INTC_VECT(IRL_4, 0x280), + INTC_VECT(IRL_5, 0x2a0), + INTC_VECT(IRL_6, 0x2c0), + INTC_VECT(IRL_7, 0x2e0), + INTC_VECT(IRL_8, 0x300), + INTC_VECT(IRL_9, 0x320), + INTC_VECT(IRL_A, 0x340), + INTC_VECT(IRL_B, 0x360), + INTC_VECT(IRL_C, 0x380), + INTC_VECT(IRL_D, 0x3a0), + INTC_VECT(IRL_E, 0x3c0), }; static struct intc_group groups_irl[] = { - INTC_GROUP(IRL, IRL_0, IRL_1, IRL_2, IRL_3, IRL_4, IRL_5, IRL_6, - IRL_7, IRL_8, IRL_9, IRL_A, IRL_B, IRL_C, IRL_D, IRL_E), + INTC_GROUP(IRL, IRL_0, IRL_1, IRL_2, IRL_3, IRL_4, IRL_5, IRL_6, + IRL_7, IRL_8, IRL_9, IRL_A, IRL_B, IRL_C, IRL_D, IRL_E), }; -/********************************************************************** - Memory mapped cache and TLB -**********************************************************************/ +/* + * Memory mapped cache and TLB + */ #define MM_REGION_MASK 0x07000000 #define MM_ICACHE_ADDR (0) @@ -679,7 +690,7 @@ static uint64_t sh7750_mmct_read(void *opaque, hwaddr addr, case MM_ICACHE_ADDR: case MM_ICACHE_DATA: /* do nothing */ - break; + break; case MM_ITLB_ADDR: ret = cpu_sh4_read_mmaped_itlb_addr(&s->cpu->env, addr); break; @@ -689,7 +700,7 @@ static uint64_t sh7750_mmct_read(void *opaque, hwaddr addr, case MM_OCACHE_ADDR: case MM_OCACHE_DATA: /* do nothing */ - break; + break; case MM_UTLB_ADDR: ret = cpu_sh4_read_mmaped_utlb_addr(&s->cpu->env, addr); break; @@ -722,27 +733,27 @@ static void sh7750_mmct_write(void *opaque, hwaddr addr, case MM_ICACHE_ADDR: case MM_ICACHE_DATA: /* do nothing */ - break; + break; case MM_ITLB_ADDR: cpu_sh4_write_mmaped_itlb_addr(&s->cpu->env, addr, mem_value); break; case MM_ITLB_DATA: cpu_sh4_write_mmaped_itlb_data(&s->cpu->env, addr, mem_value); abort(); - break; + break; case MM_OCACHE_ADDR: case MM_OCACHE_DATA: /* do nothing */ - break; + break; case MM_UTLB_ADDR: cpu_sh4_write_mmaped_utlb_addr(&s->cpu->env, addr, mem_value); - break; + break; case MM_UTLB_DATA: cpu_sh4_write_mmaped_utlb_data(&s->cpu->env, addr, mem_value); - break; + break; default: abort(); - break; + break; } } @@ -755,10 +766,13 @@ static const MemoryRegionOps sh7750_mmct_ops = { SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion *sysmem) { SH7750State *s; + DeviceState *dev; + SysBusDevice *sb; + MemoryRegion *mr, *alias; s = g_malloc0(sizeof(SH7750State)); s->cpu = cpu; - s->periph_freq = 60000000; /* 60MHz */ + s->periph_freq = 60000000; /* 60MHz */ memory_region_init_io(&s->iomem, NULL, &sh7750_mem_ops, s, "memory", 0x1fc01000); @@ -791,81 +805,100 @@ SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion *sysmem) memory_region_add_subregion(sysmem, 0xf0000000, &s->mmct_iomem); sh_intc_init(sysmem, &s->intc, NR_SOURCES, - _INTC_ARRAY(mask_registers), - _INTC_ARRAY(prio_registers)); + _INTC_ARRAY(mask_registers), + _INTC_ARRAY(prio_registers)); sh_intc_register_sources(&s->intc, - _INTC_ARRAY(vectors), - _INTC_ARRAY(groups)); + _INTC_ARRAY(vectors), + _INTC_ARRAY(groups)); cpu->env.intc_handle = &s->intc; - sh_serial_init(sysmem, 0x1fe00000, - 0, s->periph_freq, serial_hd(0), - s->intc.irqs[SCI1_ERI], - s->intc.irqs[SCI1_RXI], - s->intc.irqs[SCI1_TXI], - s->intc.irqs[SCI1_TEI], - NULL); - sh_serial_init(sysmem, 0x1fe80000, - SH_SERIAL_FEAT_SCIF, - s->periph_freq, serial_hd(1), - s->intc.irqs[SCIF_ERI], - s->intc.irqs[SCIF_RXI], - s->intc.irqs[SCIF_TXI], - NULL, - s->intc.irqs[SCIF_BRI]); + /* SCI */ + dev = qdev_new(TYPE_SH_SERIAL); + dev->id = g_strdup("sci"); + qdev_prop_set_chr(dev, "chardev", serial_hd(0)); + sb = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(sb, &error_fatal); + sysbus_mmio_map(sb, 0, 0xffe00000); + alias = g_malloc(sizeof(*alias)); + mr = sysbus_mmio_get_region(sb, 0); + memory_region_init_alias(alias, OBJECT(dev), "sci-a7", mr, + 0, memory_region_size(mr)); + memory_region_add_subregion(sysmem, A7ADDR(0xffe00000), alias); + qdev_connect_gpio_out_named(dev, "eri", 0, s->intc.irqs[SCI1_ERI]); + qdev_connect_gpio_out_named(dev, "rxi", 0, s->intc.irqs[SCI1_RXI]); + qdev_connect_gpio_out_named(dev, "txi", 0, s->intc.irqs[SCI1_TXI]); + qdev_connect_gpio_out_named(dev, "tei", 0, s->intc.irqs[SCI1_TEI]); + + /* SCIF */ + dev = qdev_new(TYPE_SH_SERIAL); + dev->id = g_strdup("scif"); + qdev_prop_set_chr(dev, "chardev", serial_hd(1)); + qdev_prop_set_uint8(dev, "features", SH_SERIAL_FEAT_SCIF); + sb = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(sb, &error_fatal); + sysbus_mmio_map(sb, 0, 0xffe80000); + alias = g_malloc(sizeof(*alias)); + mr = sysbus_mmio_get_region(sb, 0); + memory_region_init_alias(alias, OBJECT(dev), "scif-a7", mr, + 0, memory_region_size(mr)); + memory_region_add_subregion(sysmem, A7ADDR(0xffe80000), alias); + qdev_connect_gpio_out_named(dev, "eri", 0, s->intc.irqs[SCIF_ERI]); + qdev_connect_gpio_out_named(dev, "rxi", 0, s->intc.irqs[SCIF_RXI]); + qdev_connect_gpio_out_named(dev, "txi", 0, s->intc.irqs[SCIF_TXI]); + qdev_connect_gpio_out_named(dev, "bri", 0, s->intc.irqs[SCIF_BRI]); tmu012_init(sysmem, 0x1fd80000, - TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK, - s->periph_freq, - s->intc.irqs[TMU0], - s->intc.irqs[TMU1], - s->intc.irqs[TMU2_TUNI], - s->intc.irqs[TMU2_TICPI]); + TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK, + s->periph_freq, + s->intc.irqs[TMU0], + s->intc.irqs[TMU1], + s->intc.irqs[TMU2_TUNI], + s->intc.irqs[TMU2_TICPI]); if (cpu->env.id & (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7751)) { sh_intc_register_sources(&s->intc, - _INTC_ARRAY(vectors_dma4), - _INTC_ARRAY(groups_dma4)); + _INTC_ARRAY(vectors_dma4), + _INTC_ARRAY(groups_dma4)); } if (cpu->env.id & (SH_CPU_SH7750R | SH_CPU_SH7751R)) { sh_intc_register_sources(&s->intc, - _INTC_ARRAY(vectors_dma8), - _INTC_ARRAY(groups_dma8)); + _INTC_ARRAY(vectors_dma8), + _INTC_ARRAY(groups_dma8)); } if (cpu->env.id & (SH_CPU_SH7750R | SH_CPU_SH7751 | SH_CPU_SH7751R)) { sh_intc_register_sources(&s->intc, - _INTC_ARRAY(vectors_tmu34), - NULL, 0); + _INTC_ARRAY(vectors_tmu34), + NULL, 0); tmu012_init(sysmem, 0x1e100000, 0, s->periph_freq, - s->intc.irqs[TMU3], - s->intc.irqs[TMU4], - NULL, NULL); + s->intc.irqs[TMU3], + s->intc.irqs[TMU4], + NULL, NULL); } if (cpu->env.id & (SH_CPU_SH7751_ALL)) { sh_intc_register_sources(&s->intc, - _INTC_ARRAY(vectors_pci), - _INTC_ARRAY(groups_pci)); + _INTC_ARRAY(vectors_pci), + _INTC_ARRAY(groups_pci)); } if (cpu->env.id & (SH_CPU_SH7750S | SH_CPU_SH7750R | SH_CPU_SH7751_ALL)) { sh_intc_register_sources(&s->intc, - _INTC_ARRAY(vectors_irlm), - NULL, 0); + _INTC_ARRAY(vectors_irlm), + NULL, 0); } sh_intc_register_sources(&s->intc, - _INTC_ARRAY(vectors_irl), - _INTC_ARRAY(groups_irl)); + _INTC_ARRAY(vectors_irl), + _INTC_ARRAY(groups_irl)); return s; } qemu_irq sh7750_irl(SH7750State *s) { - sh_intc_toggle_source(sh_intc_source(&s->intc, IRL), 1, 0); /* enable */ - return qemu_allocate_irq(sh_intc_set_irl, sh_intc_source(&s->intc, IRL), 0); + sh_intc_toggle_source(&s->intc.sources[IRL], 1, 0); /* enable */ + return qemu_allocate_irq(sh_intc_set_irl, &s->intc.sources[IRL], 0); } diff --git a/hw/sh4/sh7750_regnames.c b/hw/sh4/sh7750_regnames.c index 0630fe3cf4..e531d46a8e 100644 --- a/hw/sh4/sh7750_regnames.c +++ b/hw/sh4/sh7750_regnames.c @@ -12,85 +12,87 @@ typedef struct { static regname_t regnames[] = { REGNAME(SH7750_PTEH_A7) - REGNAME(SH7750_PTEL_A7) - REGNAME(SH7750_PTEA_A7) - REGNAME(SH7750_TTB_A7) - REGNAME(SH7750_TEA_A7) - REGNAME(SH7750_MMUCR_A7) - REGNAME(SH7750_CCR_A7) - REGNAME(SH7750_QACR0_A7) - REGNAME(SH7750_QACR1_A7) - REGNAME(SH7750_TRA_A7) - REGNAME(SH7750_EXPEVT_A7) - REGNAME(SH7750_INTEVT_A7) - REGNAME(SH7750_STBCR_A7) - REGNAME(SH7750_STBCR2_A7) - REGNAME(SH7750_FRQCR_A7) - REGNAME(SH7750_WTCNT_A7) - REGNAME(SH7750_WTCSR_A7) - REGNAME(SH7750_R64CNT_A7) - REGNAME(SH7750_RSECCNT_A7) - REGNAME(SH7750_RMINCNT_A7) - REGNAME(SH7750_RHRCNT_A7) - REGNAME(SH7750_RWKCNT_A7) - REGNAME(SH7750_RDAYCNT_A7) - REGNAME(SH7750_RMONCNT_A7) - REGNAME(SH7750_RYRCNT_A7) - REGNAME(SH7750_RSECAR_A7) - REGNAME(SH7750_RMINAR_A7) - REGNAME(SH7750_RHRAR_A7) - REGNAME(SH7750_RWKAR_A7) - REGNAME(SH7750_RDAYAR_A7) - REGNAME(SH7750_RMONAR_A7) - REGNAME(SH7750_RCR1_A7) - REGNAME(SH7750_RCR2_A7) - REGNAME(SH7750_BCR1_A7) - REGNAME(SH7750_BCR2_A7) - REGNAME(SH7750_WCR1_A7) - REGNAME(SH7750_WCR2_A7) - REGNAME(SH7750_WCR3_A7) - REGNAME(SH7750_MCR_A7) - REGNAME(SH7750_PCR_A7) - REGNAME(SH7750_RTCSR_A7) - REGNAME(SH7750_RTCNT_A7) - REGNAME(SH7750_RTCOR_A7) - REGNAME(SH7750_RFCR_A7) - REGNAME(SH7750_SAR0_A7) - REGNAME(SH7750_SAR1_A7) - REGNAME(SH7750_SAR2_A7) - REGNAME(SH7750_SAR3_A7) - REGNAME(SH7750_DAR0_A7) - REGNAME(SH7750_DAR1_A7) - REGNAME(SH7750_DAR2_A7) - REGNAME(SH7750_DAR3_A7) - REGNAME(SH7750_DMATCR0_A7) - REGNAME(SH7750_DMATCR1_A7) - REGNAME(SH7750_DMATCR2_A7) - REGNAME(SH7750_DMATCR3_A7) - REGNAME(SH7750_CHCR0_A7) - REGNAME(SH7750_CHCR1_A7) - REGNAME(SH7750_CHCR2_A7) - REGNAME(SH7750_CHCR3_A7) - REGNAME(SH7750_DMAOR_A7) - REGNAME(SH7750_PCTRA_A7) - REGNAME(SH7750_PDTRA_A7) - REGNAME(SH7750_PCTRB_A7) - REGNAME(SH7750_PDTRB_A7) - REGNAME(SH7750_GPIOIC_A7) - REGNAME(SH7750_ICR_A7) - REGNAME(SH7750_BCR3_A7) - REGNAME(SH7750_BCR4_A7) - REGNAME(SH7750_SDMR2_A7) - REGNAME(SH7750_SDMR3_A7) {(uint32_t) - 1, NULL} + REGNAME(SH7750_PTEL_A7) + REGNAME(SH7750_PTEA_A7) + REGNAME(SH7750_TTB_A7) + REGNAME(SH7750_TEA_A7) + REGNAME(SH7750_MMUCR_A7) + REGNAME(SH7750_CCR_A7) + REGNAME(SH7750_QACR0_A7) + REGNAME(SH7750_QACR1_A7) + REGNAME(SH7750_TRA_A7) + REGNAME(SH7750_EXPEVT_A7) + REGNAME(SH7750_INTEVT_A7) + REGNAME(SH7750_STBCR_A7) + REGNAME(SH7750_STBCR2_A7) + REGNAME(SH7750_FRQCR_A7) + REGNAME(SH7750_WTCNT_A7) + REGNAME(SH7750_WTCSR_A7) + REGNAME(SH7750_R64CNT_A7) + REGNAME(SH7750_RSECCNT_A7) + REGNAME(SH7750_RMINCNT_A7) + REGNAME(SH7750_RHRCNT_A7) + REGNAME(SH7750_RWKCNT_A7) + REGNAME(SH7750_RDAYCNT_A7) + REGNAME(SH7750_RMONCNT_A7) + REGNAME(SH7750_RYRCNT_A7) + REGNAME(SH7750_RSECAR_A7) + REGNAME(SH7750_RMINAR_A7) + REGNAME(SH7750_RHRAR_A7) + REGNAME(SH7750_RWKAR_A7) + REGNAME(SH7750_RDAYAR_A7) + REGNAME(SH7750_RMONAR_A7) + REGNAME(SH7750_RCR1_A7) + REGNAME(SH7750_RCR2_A7) + REGNAME(SH7750_BCR1_A7) + REGNAME(SH7750_BCR2_A7) + REGNAME(SH7750_WCR1_A7) + REGNAME(SH7750_WCR2_A7) + REGNAME(SH7750_WCR3_A7) + REGNAME(SH7750_MCR_A7) + REGNAME(SH7750_PCR_A7) + REGNAME(SH7750_RTCSR_A7) + REGNAME(SH7750_RTCNT_A7) + REGNAME(SH7750_RTCOR_A7) + REGNAME(SH7750_RFCR_A7) + REGNAME(SH7750_SAR0_A7) + REGNAME(SH7750_SAR1_A7) + REGNAME(SH7750_SAR2_A7) + REGNAME(SH7750_SAR3_A7) + REGNAME(SH7750_DAR0_A7) + REGNAME(SH7750_DAR1_A7) + REGNAME(SH7750_DAR2_A7) + REGNAME(SH7750_DAR3_A7) + REGNAME(SH7750_DMATCR0_A7) + REGNAME(SH7750_DMATCR1_A7) + REGNAME(SH7750_DMATCR2_A7) + REGNAME(SH7750_DMATCR3_A7) + REGNAME(SH7750_CHCR0_A7) + REGNAME(SH7750_CHCR1_A7) + REGNAME(SH7750_CHCR2_A7) + REGNAME(SH7750_CHCR3_A7) + REGNAME(SH7750_DMAOR_A7) + REGNAME(SH7750_PCTRA_A7) + REGNAME(SH7750_PDTRA_A7) + REGNAME(SH7750_PCTRB_A7) + REGNAME(SH7750_PDTRB_A7) + REGNAME(SH7750_GPIOIC_A7) + REGNAME(SH7750_ICR_A7) + REGNAME(SH7750_BCR3_A7) + REGNAME(SH7750_BCR4_A7) + REGNAME(SH7750_SDMR2_A7) + REGNAME(SH7750_SDMR3_A7) + { (uint32_t)-1, NULL } }; const char *regname(uint32_t addr) { unsigned int i; - for (i = 0; regnames[i].regaddr != (uint32_t) - 1; i++) { - if (regnames[i].regaddr == addr) - return regnames[i].regname; + for (i = 0; regnames[i].regaddr != (uint32_t)-1; i++) { + if (regnames[i].regaddr == addr) { + return regnames[i].regname; + } } return "<unknown reg>"; diff --git a/hw/sh4/sh7750_regs.h b/hw/sh4/sh7750_regs.h index ab073dadc7..beb571d5e9 100644 --- a/hw/sh4/sh7750_regs.h +++ b/hw/sh4/sh7750_regs.h @@ -43,9 +43,8 @@ * All register has 2 addresses: in 0xff000000 - 0xffffffff (P4 address) and * in 0x1f000000 - 0x1fffffff (area 7 address) */ -#define SH7750_P4_BASE 0xff000000 /* Accessible only in - privileged mode */ -#define SH7750_A7_BASE 0x1f000000 /* Accessible only using TLB */ +#define SH7750_P4_BASE 0xff000000 /* Accessible only in privileged mode */ +#define SH7750_A7_BASE 0x1f000000 /* Accessible only using TLB */ #define SH7750_P4_REG32(ofs) (SH7750_P4_BASE + (ofs)) #define SH7750_A7_REG32(ofs) (SH7750_A7_BASE + (ofs)) @@ -55,84 +54,84 @@ */ /* Page Table Entry High register - PTEH */ -#define SH7750_PTEH_REGOFS 0x000000 /* offset */ +#define SH7750_PTEH_REGOFS 0x000000 /* offset */ #define SH7750_PTEH SH7750_P4_REG32(SH7750_PTEH_REGOFS) #define SH7750_PTEH_A7 SH7750_A7_REG32(SH7750_PTEH_REGOFS) -#define SH7750_PTEH_VPN 0xfffffd00 /* Virtual page number */ +#define SH7750_PTEH_VPN 0xfffffd00 /* Virtual page number */ #define SH7750_PTEH_VPN_S 10 -#define SH7750_PTEH_ASID 0x000000ff /* Address space identifier */ +#define SH7750_PTEH_ASID 0x000000ff /* Address space identifier */ #define SH7750_PTEH_ASID_S 0 /* Page Table Entry Low register - PTEL */ -#define SH7750_PTEL_REGOFS 0x000004 /* offset */ +#define SH7750_PTEL_REGOFS 0x000004 /* offset */ #define SH7750_PTEL SH7750_P4_REG32(SH7750_PTEL_REGOFS) #define SH7750_PTEL_A7 SH7750_A7_REG32(SH7750_PTEL_REGOFS) -#define SH7750_PTEL_PPN 0x1ffffc00 /* Physical page number */ +#define SH7750_PTEL_PPN 0x1ffffc00 /* Physical page number */ #define SH7750_PTEL_PPN_S 10 -#define SH7750_PTEL_V 0x00000100 /* Validity (0-entry is invalid) */ -#define SH7750_PTEL_SZ1 0x00000080 /* Page size bit 1 */ -#define SH7750_PTEL_SZ0 0x00000010 /* Page size bit 0 */ -#define SH7750_PTEL_SZ_1KB 0x00000000 /* 1-kbyte page */ -#define SH7750_PTEL_SZ_4KB 0x00000010 /* 4-kbyte page */ -#define SH7750_PTEL_SZ_64KB 0x00000080 /* 64-kbyte page */ -#define SH7750_PTEL_SZ_1MB 0x00000090 /* 1-Mbyte page */ -#define SH7750_PTEL_PR 0x00000060 /* Protection Key Data */ -#define SH7750_PTEL_PR_ROPO 0x00000000 /* read-only in priv mode */ -#define SH7750_PTEL_PR_RWPO 0x00000020 /* read-write in priv mode */ -#define SH7750_PTEL_PR_ROPU 0x00000040 /* read-only in priv or user mode */ -#define SH7750_PTEL_PR_RWPU 0x00000060 /* read-write in priv or user mode */ -#define SH7750_PTEL_C 0x00000008 /* Cacheability - (0 - page not cacheable) */ -#define SH7750_PTEL_D 0x00000004 /* Dirty bit (1 - write has been - performed to a page) */ -#define SH7750_PTEL_SH 0x00000002 /* Share Status bit (1 - page are - shared by processes) */ -#define SH7750_PTEL_WT 0x00000001 /* Write-through bit, specifies the - cache write mode: - 0 - Copy-back mode - 1 - Write-through mode */ +#define SH7750_PTEL_V 0x00000100 /* Validity (0-entry is invalid) */ +#define SH7750_PTEL_SZ1 0x00000080 /* Page size bit 1 */ +#define SH7750_PTEL_SZ0 0x00000010 /* Page size bit 0 */ +#define SH7750_PTEL_SZ_1KB 0x00000000 /* 1-kbyte page */ +#define SH7750_PTEL_SZ_4KB 0x00000010 /* 4-kbyte page */ +#define SH7750_PTEL_SZ_64KB 0x00000080 /* 64-kbyte page */ +#define SH7750_PTEL_SZ_1MB 0x00000090 /* 1-Mbyte page */ +#define SH7750_PTEL_PR 0x00000060 /* Protection Key Data */ +#define SH7750_PTEL_PR_ROPO 0x00000000 /* read-only in priv mode */ +#define SH7750_PTEL_PR_RWPO 0x00000020 /* read-write in priv mode */ +#define SH7750_PTEL_PR_ROPU 0x00000040 /* read-only in priv or user mode */ +#define SH7750_PTEL_PR_RWPU 0x00000060 /* read-write in priv or user mode */ +#define SH7750_PTEL_C 0x00000008 /* Cacheability */ + /* (0 - page not cacheable) */ +#define SH7750_PTEL_D 0x00000004 /* Dirty bit (1 - write has been */ + /* performed to a page) */ +#define SH7750_PTEL_SH 0x00000002 /* Share Status bit (1 - page are */ + /* shared by processes) */ +#define SH7750_PTEL_WT 0x00000001 /* Write-through bit, specifies the */ + /* cache write mode: */ + /* 0 - Copy-back mode */ + /* 1 - Write-through mode */ /* Page Table Entry Assistance register - PTEA */ -#define SH7750_PTEA_REGOFS 0x000034 /* offset */ +#define SH7750_PTEA_REGOFS 0x000034 /* offset */ #define SH7750_PTEA SH7750_P4_REG32(SH7750_PTEA_REGOFS) #define SH7750_PTEA_A7 SH7750_A7_REG32(SH7750_PTEA_REGOFS) -#define SH7750_PTEA_TC 0x00000008 /* Timing Control bit - 0 - use area 5 wait states - 1 - use area 6 wait states */ -#define SH7750_PTEA_SA 0x00000007 /* Space Attribute bits: */ -#define SH7750_PTEA_SA_UNDEF 0x00000000 /* 0 - undefined */ -#define SH7750_PTEA_SA_IOVAR 0x00000001 /* 1 - variable-size I/O space */ -#define SH7750_PTEA_SA_IO8 0x00000002 /* 2 - 8-bit I/O space */ -#define SH7750_PTEA_SA_IO16 0x00000003 /* 3 - 16-bit I/O space */ -#define SH7750_PTEA_SA_CMEM8 0x00000004 /* 4 - 8-bit common memory space */ -#define SH7750_PTEA_SA_CMEM16 0x00000005 /* 5 - 16-bit common memory space */ -#define SH7750_PTEA_SA_AMEM8 0x00000006 /* 6 - 8-bit attr memory space */ -#define SH7750_PTEA_SA_AMEM16 0x00000007 /* 7 - 16-bit attr memory space */ +#define SH7750_PTEA_TC 0x00000008 /* Timing Control bit */ + /* 0 - use area 5 wait states */ + /* 1 - use area 6 wait states */ +#define SH7750_PTEA_SA 0x00000007 /* Space Attribute bits: */ +#define SH7750_PTEA_SA_UNDEF 0x00000000 /* 0 - undefined */ +#define SH7750_PTEA_SA_IOVAR 0x00000001 /* 1 - variable-size I/O space */ +#define SH7750_PTEA_SA_IO8 0x00000002 /* 2 - 8-bit I/O space */ +#define SH7750_PTEA_SA_IO16 0x00000003 /* 3 - 16-bit I/O space */ +#define SH7750_PTEA_SA_CMEM8 0x00000004 /* 4 - 8-bit common memory space */ +#define SH7750_PTEA_SA_CMEM16 0x00000005 /* 5 - 16-bit common memory space */ +#define SH7750_PTEA_SA_AMEM8 0x00000006 /* 6 - 8-bit attr memory space */ +#define SH7750_PTEA_SA_AMEM16 0x00000007 /* 7 - 16-bit attr memory space */ /* Translation table base register */ -#define SH7750_TTB_REGOFS 0x000008 /* offset */ +#define SH7750_TTB_REGOFS 0x000008 /* offset */ #define SH7750_TTB SH7750_P4_REG32(SH7750_TTB_REGOFS) #define SH7750_TTB_A7 SH7750_A7_REG32(SH7750_TTB_REGOFS) /* TLB exeption address register - TEA */ -#define SH7750_TEA_REGOFS 0x00000c /* offset */ +#define SH7750_TEA_REGOFS 0x00000c /* offset */ #define SH7750_TEA SH7750_P4_REG32(SH7750_TEA_REGOFS) #define SH7750_TEA_A7 SH7750_A7_REG32(SH7750_TEA_REGOFS) /* MMU control register - MMUCR */ -#define SH7750_MMUCR_REGOFS 0x000010 /* offset */ +#define SH7750_MMUCR_REGOFS 0x000010 /* offset */ #define SH7750_MMUCR SH7750_P4_REG32(SH7750_MMUCR_REGOFS) #define SH7750_MMUCR_A7 SH7750_A7_REG32(SH7750_MMUCR_REGOFS) -#define SH7750_MMUCR_AT 0x00000001 /* Address translation bit */ -#define SH7750_MMUCR_TI 0x00000004 /* TLB invalidate */ -#define SH7750_MMUCR_SV 0x00000100 /* Single Virtual Mode bit */ -#define SH7750_MMUCR_SQMD 0x00000200 /* Store Queue Mode bit */ -#define SH7750_MMUCR_URC 0x0000FC00 /* UTLB Replace Counter */ +#define SH7750_MMUCR_AT 0x00000001 /* Address translation bit */ +#define SH7750_MMUCR_TI 0x00000004 /* TLB invalidate */ +#define SH7750_MMUCR_SV 0x00000100 /* Single Virtual Mode bit */ +#define SH7750_MMUCR_SQMD 0x00000200 /* Store Queue Mode bit */ +#define SH7750_MMUCR_URC 0x0000FC00 /* UTLB Replace Counter */ #define SH7750_MMUCR_URC_S 10 -#define SH7750_MMUCR_URB 0x00FC0000 /* UTLB Replace Boundary */ +#define SH7750_MMUCR_URB 0x00FC0000 /* UTLB Replace Boundary */ #define SH7750_MMUCR_URB_S 18 -#define SH7750_MMUCR_LRUI 0xFC000000 /* Least Recently Used ITLB */ +#define SH7750_MMUCR_LRUI 0xFC000000 /* Least Recently Used ITLB */ #define SH7750_MMUCR_LRUI_S 26 @@ -145,30 +144,30 @@ */ /* Cache Control Register - CCR */ -#define SH7750_CCR_REGOFS 0x00001c /* offset */ +#define SH7750_CCR_REGOFS 0x00001c /* offset */ #define SH7750_CCR SH7750_P4_REG32(SH7750_CCR_REGOFS) #define SH7750_CCR_A7 SH7750_A7_REG32(SH7750_CCR_REGOFS) -#define SH7750_CCR_IIX 0x00008000 /* IC index enable bit */ -#define SH7750_CCR_ICI 0x00000800 /* IC invalidation bit: - set it to clear IC */ -#define SH7750_CCR_ICE 0x00000100 /* IC enable bit */ -#define SH7750_CCR_OIX 0x00000080 /* OC index enable bit */ -#define SH7750_CCR_ORA 0x00000020 /* OC RAM enable bit - if you set OCE = 0, - you should set ORA = 0 */ -#define SH7750_CCR_OCI 0x00000008 /* OC invalidation bit */ -#define SH7750_CCR_CB 0x00000004 /* Copy-back bit for P1 area */ -#define SH7750_CCR_WT 0x00000002 /* Write-through bit for P0,U0,P3 area */ -#define SH7750_CCR_OCE 0x00000001 /* OC enable bit */ +#define SH7750_CCR_IIX 0x00008000 /* IC index enable bit */ +#define SH7750_CCR_ICI 0x00000800 /* IC invalidation bit: */ + /* set it to clear IC */ +#define SH7750_CCR_ICE 0x00000100 /* IC enable bit */ +#define SH7750_CCR_OIX 0x00000080 /* OC index enable bit */ +#define SH7750_CCR_ORA 0x00000020 /* OC RAM enable bit */ + /* if you set OCE = 0, */ + /* you should set ORA = 0 */ +#define SH7750_CCR_OCI 0x00000008 /* OC invalidation bit */ +#define SH7750_CCR_CB 0x00000004 /* Copy-back bit for P1 area */ +#define SH7750_CCR_WT 0x00000002 /* Write-through bit for P0,U0,P3 area */ +#define SH7750_CCR_OCE 0x00000001 /* OC enable bit */ /* Queue address control register 0 - QACR0 */ -#define SH7750_QACR0_REGOFS 0x000038 /* offset */ +#define SH7750_QACR0_REGOFS 0x000038 /* offset */ #define SH7750_QACR0 SH7750_P4_REG32(SH7750_QACR0_REGOFS) #define SH7750_QACR0_A7 SH7750_A7_REG32(SH7750_QACR0_REGOFS) /* Queue address control register 1 - QACR1 */ -#define SH7750_QACR1_REGOFS 0x00003c /* offset */ +#define SH7750_QACR1_REGOFS 0x00003c /* offset */ #define SH7750_QACR1 SH7750_P4_REG32(SH7750_QACR1_REGOFS) #define SH7750_QACR1_A7 SH7750_A7_REG32(SH7750_QACR1_REGOFS) @@ -178,11 +177,11 @@ */ /* Immediate data for TRAPA instruction - TRA */ -#define SH7750_TRA_REGOFS 0x000020 /* offset */ +#define SH7750_TRA_REGOFS 0x000020 /* offset */ #define SH7750_TRA SH7750_P4_REG32(SH7750_TRA_REGOFS) #define SH7750_TRA_A7 SH7750_A7_REG32(SH7750_TRA_REGOFS) -#define SH7750_TRA_IMM 0x000003fd /* Immediate data operand */ +#define SH7750_TRA_IMM 0x000003fd /* Immediate data operand */ #define SH7750_TRA_IMM_S 2 /* Exeption event register - EXPEVT */ @@ -190,14 +189,14 @@ #define SH7750_EXPEVT SH7750_P4_REG32(SH7750_EXPEVT_REGOFS) #define SH7750_EXPEVT_A7 SH7750_A7_REG32(SH7750_EXPEVT_REGOFS) -#define SH7750_EXPEVT_EX 0x00000fff /* Exeption code */ +#define SH7750_EXPEVT_EX 0x00000fff /* Exeption code */ #define SH7750_EXPEVT_EX_S 0 /* Interrupt event register */ #define SH7750_INTEVT_REGOFS 0x000028 #define SH7750_INTEVT SH7750_P4_REG32(SH7750_INTEVT_REGOFS) #define SH7750_INTEVT_A7 SH7750_A7_REG32(SH7750_INTEVT_REGOFS) -#define SH7750_INTEVT_EX 0x00000fff /* Exeption code */ +#define SH7750_INTEVT_EX 0x00000fff /* Exeption code */ #define SH7750_INTEVT_EX_S 0 /* @@ -206,683 +205,684 @@ #define SH7750_EVT_TO_NUM(evt) ((evt) >> 5) /* Reset exception category */ -#define SH7750_EVT_POWER_ON_RST 0x000 /* Power-on reset */ -#define SH7750_EVT_MANUAL_RST 0x020 /* Manual reset */ -#define SH7750_EVT_TLB_MULT_HIT 0x140 /* TLB multiple-hit exception */ +#define SH7750_EVT_POWER_ON_RST 0x000 /* Power-on reset */ +#define SH7750_EVT_MANUAL_RST 0x020 /* Manual reset */ +#define SH7750_EVT_TLB_MULT_HIT 0x140 /* TLB multiple-hit exception */ /* General exception category */ -#define SH7750_EVT_USER_BREAK 0x1E0 /* User break */ -#define SH7750_EVT_IADDR_ERR 0x0E0 /* Instruction address error */ -#define SH7750_EVT_TLB_READ_MISS 0x040 /* ITLB miss exception / - DTLB miss exception (read) */ -#define SH7750_EVT_TLB_READ_PROTV 0x0A0 /* ITLB protection violation / - DTLB protection violation (read) */ -#define SH7750_EVT_ILLEGAL_INSTR 0x180 /* General Illegal Instruction - exception */ -#define SH7750_EVT_SLOT_ILLEGAL_INSTR 0x1A0 /* Slot Illegal Instruction - exception */ -#define SH7750_EVT_FPU_DISABLE 0x800 /* General FPU disable exception */ -#define SH7750_EVT_SLOT_FPU_DISABLE 0x820 /* Slot FPU disable exception */ -#define SH7750_EVT_DATA_READ_ERR 0x0E0 /* Data address error (read) */ -#define SH7750_EVT_DATA_WRITE_ERR 0x100 /* Data address error (write) */ -#define SH7750_EVT_DTLB_WRITE_MISS 0x060 /* DTLB miss exception (write) */ -#define SH7750_EVT_DTLB_WRITE_PROTV 0x0C0 /* DTLB protection violation - exception (write) */ -#define SH7750_EVT_FPU_EXCEPTION 0x120 /* FPU exception */ -#define SH7750_EVT_INITIAL_PGWRITE 0x080 /* Initial Page Write exception */ -#define SH7750_EVT_TRAPA 0x160 /* Unconditional trap (TRAPA) */ +#define SH7750_EVT_USER_BREAK 0x1E0 /* User break */ +#define SH7750_EVT_IADDR_ERR 0x0E0 /* Instruction address error */ +#define SH7750_EVT_TLB_READ_MISS 0x040 /* ITLB miss exception / */ + /* DTLB miss exception (read) */ +#define SH7750_EVT_TLB_READ_PROTV 0x0A0 /* ITLB protection violation, */ + /* DTLB protection violation */ + /* (read) */ +#define SH7750_EVT_ILLEGAL_INSTR 0x180 /* General Illegal Instruction */ + /* exception */ +#define SH7750_EVT_SLOT_ILLEGAL_INSTR 0x1A0 /* Slot Illegal Instruction */ + /* exception */ +#define SH7750_EVT_FPU_DISABLE 0x800 /* General FPU disable exception */ +#define SH7750_EVT_SLOT_FPU_DISABLE 0x820 /* Slot FPU disable exception */ +#define SH7750_EVT_DATA_READ_ERR 0x0E0 /* Data address error (read) */ +#define SH7750_EVT_DATA_WRITE_ERR 0x100 /* Data address error (write) */ +#define SH7750_EVT_DTLB_WRITE_MISS 0x060 /* DTLB miss exception (write) */ +#define SH7750_EVT_DTLB_WRITE_PROTV 0x0C0 /* DTLB protection violation */ + /* exception (write) */ +#define SH7750_EVT_FPU_EXCEPTION 0x120 /* FPU exception */ +#define SH7750_EVT_INITIAL_PGWRITE 0x080 /* Initial Page Write exception */ +#define SH7750_EVT_TRAPA 0x160 /* Unconditional trap (TRAPA) */ /* Interrupt exception category */ -#define SH7750_EVT_NMI 0x1C0 /* Non-maskable interrupt */ -#define SH7750_EVT_IRQ0 0x200 /* External Interrupt 0 */ -#define SH7750_EVT_IRQ1 0x220 /* External Interrupt 1 */ -#define SH7750_EVT_IRQ2 0x240 /* External Interrupt 2 */ -#define SH7750_EVT_IRQ3 0x260 /* External Interrupt 3 */ -#define SH7750_EVT_IRQ4 0x280 /* External Interrupt 4 */ -#define SH7750_EVT_IRQ5 0x2A0 /* External Interrupt 5 */ -#define SH7750_EVT_IRQ6 0x2C0 /* External Interrupt 6 */ -#define SH7750_EVT_IRQ7 0x2E0 /* External Interrupt 7 */ -#define SH7750_EVT_IRQ8 0x300 /* External Interrupt 8 */ -#define SH7750_EVT_IRQ9 0x320 /* External Interrupt 9 */ -#define SH7750_EVT_IRQA 0x340 /* External Interrupt A */ -#define SH7750_EVT_IRQB 0x360 /* External Interrupt B */ -#define SH7750_EVT_IRQC 0x380 /* External Interrupt C */ -#define SH7750_EVT_IRQD 0x3A0 /* External Interrupt D */ -#define SH7750_EVT_IRQE 0x3C0 /* External Interrupt E */ +#define SH7750_EVT_NMI 0x1C0 /* Non-maskable interrupt */ +#define SH7750_EVT_IRQ0 0x200 /* External Interrupt 0 */ +#define SH7750_EVT_IRQ1 0x220 /* External Interrupt 1 */ +#define SH7750_EVT_IRQ2 0x240 /* External Interrupt 2 */ +#define SH7750_EVT_IRQ3 0x260 /* External Interrupt 3 */ +#define SH7750_EVT_IRQ4 0x280 /* External Interrupt 4 */ +#define SH7750_EVT_IRQ5 0x2A0 /* External Interrupt 5 */ +#define SH7750_EVT_IRQ6 0x2C0 /* External Interrupt 6 */ +#define SH7750_EVT_IRQ7 0x2E0 /* External Interrupt 7 */ +#define SH7750_EVT_IRQ8 0x300 /* External Interrupt 8 */ +#define SH7750_EVT_IRQ9 0x320 /* External Interrupt 9 */ +#define SH7750_EVT_IRQA 0x340 /* External Interrupt A */ +#define SH7750_EVT_IRQB 0x360 /* External Interrupt B */ +#define SH7750_EVT_IRQC 0x380 /* External Interrupt C */ +#define SH7750_EVT_IRQD 0x3A0 /* External Interrupt D */ +#define SH7750_EVT_IRQE 0x3C0 /* External Interrupt E */ /* Peripheral Module Interrupts - Timer Unit (TMU) */ -#define SH7750_EVT_TUNI0 0x400 /* TMU Underflow Interrupt 0 */ -#define SH7750_EVT_TUNI1 0x420 /* TMU Underflow Interrupt 1 */ -#define SH7750_EVT_TUNI2 0x440 /* TMU Underflow Interrupt 2 */ -#define SH7750_EVT_TICPI2 0x460 /* TMU Input Capture Interrupt 2 */ +#define SH7750_EVT_TUNI0 0x400 /* TMU Underflow Interrupt 0 */ +#define SH7750_EVT_TUNI1 0x420 /* TMU Underflow Interrupt 1 */ +#define SH7750_EVT_TUNI2 0x440 /* TMU Underflow Interrupt 2 */ +#define SH7750_EVT_TICPI2 0x460 /* TMU Input Capture Interrupt 2 */ /* Peripheral Module Interrupts - Real-Time Clock (RTC) */ -#define SH7750_EVT_RTC_ATI 0x480 /* Alarm Interrupt Request */ -#define SH7750_EVT_RTC_PRI 0x4A0 /* Periodic Interrupt Request */ -#define SH7750_EVT_RTC_CUI 0x4C0 /* Carry Interrupt Request */ +#define SH7750_EVT_RTC_ATI 0x480 /* Alarm Interrupt Request */ +#define SH7750_EVT_RTC_PRI 0x4A0 /* Periodic Interrupt Request */ +#define SH7750_EVT_RTC_CUI 0x4C0 /* Carry Interrupt Request */ /* Peripheral Module Interrupts - Serial Communication Interface (SCI) */ -#define SH7750_EVT_SCI_ERI 0x4E0 /* Receive Error */ -#define SH7750_EVT_SCI_RXI 0x500 /* Receive Data Register Full */ -#define SH7750_EVT_SCI_TXI 0x520 /* Transmit Data Register Empty */ -#define SH7750_EVT_SCI_TEI 0x540 /* Transmit End */ +#define SH7750_EVT_SCI_ERI 0x4E0 /* Receive Error */ +#define SH7750_EVT_SCI_RXI 0x500 /* Receive Data Register Full */ +#define SH7750_EVT_SCI_TXI 0x520 /* Transmit Data Register Empty */ +#define SH7750_EVT_SCI_TEI 0x540 /* Transmit End */ /* Peripheral Module Interrupts - Watchdog Timer (WDT) */ -#define SH7750_EVT_WDT_ITI 0x560 /* Interval Timer Interrupt - (used when WDT operates in - interval timer mode) */ +#define SH7750_EVT_WDT_ITI 0x560 /* Interval Timer Interrupt */ + /* (used when WDT operates in */ + /* interval timer mode) */ /* Peripheral Module Interrupts - Memory Refresh Unit (REF) */ -#define SH7750_EVT_REF_RCMI 0x580 /* Compare-match Interrupt */ -#define SH7750_EVT_REF_ROVI 0x5A0 /* Refresh Counter Overflow - interrupt */ +#define SH7750_EVT_REF_RCMI 0x580 /* Compare-match Interrupt */ +#define SH7750_EVT_REF_ROVI 0x5A0 /* Refresh Counter Overflow */ + /* interrupt */ /* Peripheral Module Interrupts - Hitachi User Debug Interface (H-UDI) */ -#define SH7750_EVT_HUDI 0x600 /* UDI interrupt */ +#define SH7750_EVT_HUDI 0x600 /* UDI interrupt */ /* Peripheral Module Interrupts - General-Purpose I/O (GPIO) */ -#define SH7750_EVT_GPIO 0x620 /* GPIO Interrupt */ +#define SH7750_EVT_GPIO 0x620 /* GPIO Interrupt */ /* Peripheral Module Interrupts - DMA Controller (DMAC) */ -#define SH7750_EVT_DMAC_DMTE0 0x640 /* DMAC 0 Transfer End Interrupt */ -#define SH7750_EVT_DMAC_DMTE1 0x660 /* DMAC 1 Transfer End Interrupt */ -#define SH7750_EVT_DMAC_DMTE2 0x680 /* DMAC 2 Transfer End Interrupt */ -#define SH7750_EVT_DMAC_DMTE3 0x6A0 /* DMAC 3 Transfer End Interrupt */ -#define SH7750_EVT_DMAC_DMAE 0x6C0 /* DMAC Address Error Interrupt */ - -/* Peripheral Module Interrupts - Serial Communication Interface with FIFO */ -/* (SCIF) */ -#define SH7750_EVT_SCIF_ERI 0x700 /* Receive Error */ -#define SH7750_EVT_SCIF_RXI 0x720 /* Receive FIFO Data Full or - Receive Data ready interrupt */ -#define SH7750_EVT_SCIF_BRI 0x740 /* Break or overrun error */ -#define SH7750_EVT_SCIF_TXI 0x760 /* Transmit FIFO Data Empty */ +#define SH7750_EVT_DMAC_DMTE0 0x640 /* DMAC 0 Transfer End Interrupt */ +#define SH7750_EVT_DMAC_DMTE1 0x660 /* DMAC 1 Transfer End Interrupt */ +#define SH7750_EVT_DMAC_DMTE2 0x680 /* DMAC 2 Transfer End Interrupt */ +#define SH7750_EVT_DMAC_DMTE3 0x6A0 /* DMAC 3 Transfer End Interrupt */ +#define SH7750_EVT_DMAC_DMAE 0x6C0 /* DMAC Address Error Interrupt */ + +/* Peripheral Module Interrupts Serial Communication Interface w/ FIFO (SCIF) */ +#define SH7750_EVT_SCIF_ERI 0x700 /* Receive Error */ +#define SH7750_EVT_SCIF_RXI 0x720 /* Receive FIFO Data Full or */ + /* Receive Data ready interrupt */ +#define SH7750_EVT_SCIF_BRI 0x740 /* Break or overrun error */ +#define SH7750_EVT_SCIF_TXI 0x760 /* Transmit FIFO Data Empty */ /* * Power Management */ -#define SH7750_STBCR_REGOFS 0xC00004 /* offset */ +#define SH7750_STBCR_REGOFS 0xC00004 /* offset */ #define SH7750_STBCR SH7750_P4_REG32(SH7750_STBCR_REGOFS) #define SH7750_STBCR_A7 SH7750_A7_REG32(SH7750_STBCR_REGOFS) -#define SH7750_STBCR_STBY 0x80 /* Specifies a transition to standby mode: - 0 - Transition to SLEEP mode on SLEEP - 1 - Transition to STANDBY mode on SLEEP */ -#define SH7750_STBCR_PHZ 0x40 /* State of peripheral module pins in - standby mode: - 0 - normal state - 1 - high-impendance state */ +#define SH7750_STBCR_STBY 0x80 /* Specifies a transition to standby mode: */ + /* 0 Transition to SLEEP mode on SLEEP */ + /* 1 Transition to STANDBY mode on SLEEP */ +#define SH7750_STBCR_PHZ 0x40 /* State of peripheral module pins in */ + /* standby mode: */ + /* 0 normal state */ + /* 1 high-impendance state */ -#define SH7750_STBCR_PPU 0x20 /* Peripheral module pins pull-up controls */ -#define SH7750_STBCR_MSTP4 0x10 /* Stopping the clock supply to DMAC */ +#define SH7750_STBCR_PPU 0x20 /* Peripheral module pins pull-up controls */ +#define SH7750_STBCR_MSTP4 0x10 /* Stopping the clock supply to DMAC */ #define SH7750_STBCR_DMAC_STP SH7750_STBCR_MSTP4 -#define SH7750_STBCR_MSTP3 0x08 /* Stopping the clock supply to SCIF */ +#define SH7750_STBCR_MSTP3 0x08 /* Stopping the clock supply to SCIF */ #define SH7750_STBCR_SCIF_STP SH7750_STBCR_MSTP3 -#define SH7750_STBCR_MSTP2 0x04 /* Stopping the clock supply to TMU */ +#define SH7750_STBCR_MSTP2 0x04 /* Stopping the clock supply to TMU */ #define SH7750_STBCR_TMU_STP SH7750_STBCR_MSTP2 -#define SH7750_STBCR_MSTP1 0x02 /* Stopping the clock supply to RTC */ +#define SH7750_STBCR_MSTP1 0x02 /* Stopping the clock supply to RTC */ #define SH7750_STBCR_RTC_STP SH7750_STBCR_MSTP1 -#define SH7750_STBCR_MSPT0 0x01 /* Stopping the clock supply to SCI */ +#define SH7750_STBCR_MSPT0 0x01 /* Stopping the clock supply to SCI */ #define SH7750_STBCR_SCI_STP SH7750_STBCR_MSTP0 #define SH7750_STBCR_STBY 0x80 -#define SH7750_STBCR2_REGOFS 0xC00010 /* offset */ +#define SH7750_STBCR2_REGOFS 0xC00010 /* offset */ #define SH7750_STBCR2 SH7750_P4_REG32(SH7750_STBCR2_REGOFS) #define SH7750_STBCR2_A7 SH7750_A7_REG32(SH7750_STBCR2_REGOFS) -#define SH7750_STBCR2_DSLP 0x80 /* Specifies transition to deep sleep mode: - 0 - transition to sleep or standby mode - as it is specified in STBY bit - 1 - transition to deep sleep mode on - execution of SLEEP instruction */ -#define SH7750_STBCR2_MSTP6 0x02 /* Stopping the clock supply to Store Queue - in the cache controller */ +#define SH7750_STBCR2_DSLP 0x80 /* Specifies transition to deep sleep mode */ + /* 0 transition to sleep or standby mode */ + /* as it is specified in STBY bit */ + /* 1 transition to deep sleep mode on */ + /* execution of SLEEP instruction */ +#define SH7750_STBCR2_MSTP6 0x02 /* Stopping the clock supply to the */ + /* Store Queue in the cache controller */ #define SH7750_STBCR2_SQ_STP SH7750_STBCR2_MSTP6 -#define SH7750_STBCR2_MSTP5 0x01 /* Stopping the clock supply to the User - Break Controller (UBC) */ +#define SH7750_STBCR2_MSTP5 0x01 /* Stopping the clock supply to the */ + /* User Break Controller (UBC) */ #define SH7750_STBCR2_UBC_STP SH7750_STBCR2_MSTP5 /* * Clock Pulse Generator (CPG) */ -#define SH7750_FRQCR_REGOFS 0xC00000 /* offset */ +#define SH7750_FRQCR_REGOFS 0xC00000 /* offset */ #define SH7750_FRQCR SH7750_P4_REG32(SH7750_FRQCR_REGOFS) #define SH7750_FRQCR_A7 SH7750_A7_REG32(SH7750_FRQCR_REGOFS) -#define SH7750_FRQCR_CKOEN 0x0800 /* Clock Output Enable - 0 - CKIO pin goes to HiZ/pullup - 1 - Clock is output from CKIO */ -#define SH7750_FRQCR_PLL1EN 0x0400 /* PLL circuit 1 enable */ -#define SH7750_FRQCR_PLL2EN 0x0200 /* PLL circuit 2 enable */ - -#define SH7750_FRQCR_IFC 0x01C0 /* CPU clock frequency division ratio: */ -#define SH7750_FRQCR_IFCDIV1 0x0000 /* 0 - * 1 */ -#define SH7750_FRQCR_IFCDIV2 0x0040 /* 1 - * 1/2 */ -#define SH7750_FRQCR_IFCDIV3 0x0080 /* 2 - * 1/3 */ -#define SH7750_FRQCR_IFCDIV4 0x00C0 /* 3 - * 1/4 */ -#define SH7750_FRQCR_IFCDIV6 0x0100 /* 4 - * 1/6 */ -#define SH7750_FRQCR_IFCDIV8 0x0140 /* 5 - * 1/8 */ - -#define SH7750_FRQCR_BFC 0x0038 /* Bus clock frequency division ratio: */ -#define SH7750_FRQCR_BFCDIV1 0x0000 /* 0 - * 1 */ -#define SH7750_FRQCR_BFCDIV2 0x0008 /* 1 - * 1/2 */ -#define SH7750_FRQCR_BFCDIV3 0x0010 /* 2 - * 1/3 */ -#define SH7750_FRQCR_BFCDIV4 0x0018 /* 3 - * 1/4 */ -#define SH7750_FRQCR_BFCDIV6 0x0020 /* 4 - * 1/6 */ -#define SH7750_FRQCR_BFCDIV8 0x0028 /* 5 - * 1/8 */ - -#define SH7750_FRQCR_PFC 0x0007 /* Peripheral module clock frequency - division ratio: */ -#define SH7750_FRQCR_PFCDIV2 0x0000 /* 0 - * 1/2 */ -#define SH7750_FRQCR_PFCDIV3 0x0001 /* 1 - * 1/3 */ -#define SH7750_FRQCR_PFCDIV4 0x0002 /* 2 - * 1/4 */ -#define SH7750_FRQCR_PFCDIV6 0x0003 /* 3 - * 1/6 */ -#define SH7750_FRQCR_PFCDIV8 0x0004 /* 4 - * 1/8 */ +#define SH7750_FRQCR_CKOEN 0x0800 /* Clock Output Enable */ + /* 0 - CKIO pin goes to HiZ/pullup */ + /* 1 - Clock is output from CKIO */ +#define SH7750_FRQCR_PLL1EN 0x0400 /* PLL circuit 1 enable */ +#define SH7750_FRQCR_PLL2EN 0x0200 /* PLL circuit 2 enable */ + +#define SH7750_FRQCR_IFC 0x01C0 /* CPU clock frequency division ratio: */ +#define SH7750_FRQCR_IFCDIV1 0x0000 /* 0 - * 1 */ +#define SH7750_FRQCR_IFCDIV2 0x0040 /* 1 - * 1/2 */ +#define SH7750_FRQCR_IFCDIV3 0x0080 /* 2 - * 1/3 */ +#define SH7750_FRQCR_IFCDIV4 0x00C0 /* 3 - * 1/4 */ +#define SH7750_FRQCR_IFCDIV6 0x0100 /* 4 - * 1/6 */ +#define SH7750_FRQCR_IFCDIV8 0x0140 /* 5 - * 1/8 */ + +#define SH7750_FRQCR_BFC 0x0038 /* Bus clock frequency division ratio: */ +#define SH7750_FRQCR_BFCDIV1 0x0000 /* 0 - * 1 */ +#define SH7750_FRQCR_BFCDIV2 0x0008 /* 1 - * 1/2 */ +#define SH7750_FRQCR_BFCDIV3 0x0010 /* 2 - * 1/3 */ +#define SH7750_FRQCR_BFCDIV4 0x0018 /* 3 - * 1/4 */ +#define SH7750_FRQCR_BFCDIV6 0x0020 /* 4 - * 1/6 */ +#define SH7750_FRQCR_BFCDIV8 0x0028 /* 5 - * 1/8 */ + +#define SH7750_FRQCR_PFC 0x0007 /* Peripheral module clock frequency */ + /* division ratio: */ +#define SH7750_FRQCR_PFCDIV2 0x0000 /* 0 - * 1/2 */ +#define SH7750_FRQCR_PFCDIV3 0x0001 /* 1 - * 1/3 */ +#define SH7750_FRQCR_PFCDIV4 0x0002 /* 2 - * 1/4 */ +#define SH7750_FRQCR_PFCDIV6 0x0003 /* 3 - * 1/6 */ +#define SH7750_FRQCR_PFCDIV8 0x0004 /* 4 - * 1/8 */ /* * Watchdog Timer (WDT) */ /* Watchdog Timer Counter register - WTCNT */ -#define SH7750_WTCNT_REGOFS 0xC00008 /* offset */ +#define SH7750_WTCNT_REGOFS 0xC00008 /* offset */ #define SH7750_WTCNT SH7750_P4_REG32(SH7750_WTCNT_REGOFS) #define SH7750_WTCNT_A7 SH7750_A7_REG32(SH7750_WTCNT_REGOFS) -#define SH7750_WTCNT_KEY 0x5A00 /* When WTCNT byte register written, - you have to set the upper byte to - 0x5A */ +#define SH7750_WTCNT_KEY 0x5A00 /* When WTCNT byte register written, you */ + /* have to set the upper byte to 0x5A */ /* Watchdog Timer Control/Status register - WTCSR */ -#define SH7750_WTCSR_REGOFS 0xC0000C /* offset */ +#define SH7750_WTCSR_REGOFS 0xC0000C /* offset */ #define SH7750_WTCSR SH7750_P4_REG32(SH7750_WTCSR_REGOFS) #define SH7750_WTCSR_A7 SH7750_A7_REG32(SH7750_WTCSR_REGOFS) -#define SH7750_WTCSR_KEY 0xA500 /* When WTCSR byte register written, - you have to set the upper byte to - 0xA5 */ -#define SH7750_WTCSR_TME 0x80 /* Timer enable (1-upcount start) */ -#define SH7750_WTCSR_MODE 0x40 /* Timer Mode Select: */ -#define SH7750_WTCSR_MODE_WT 0x40 /* Watchdog Timer Mode */ -#define SH7750_WTCSR_MODE_IT 0x00 /* Interval Timer Mode */ -#define SH7750_WTCSR_RSTS 0x20 /* Reset Select: */ -#define SH7750_WTCSR_RST_MAN 0x20 /* Manual Reset */ -#define SH7750_WTCSR_RST_PWR 0x00 /* Power-on Reset */ -#define SH7750_WTCSR_WOVF 0x10 /* Watchdog Timer Overflow Flag */ -#define SH7750_WTCSR_IOVF 0x08 /* Interval Timer Overflow Flag */ -#define SH7750_WTCSR_CKS 0x07 /* Clock Select: */ -#define SH7750_WTCSR_CKS_DIV32 0x00 /* 1/32 of frequency divider 2 input */ -#define SH7750_WTCSR_CKS_DIV64 0x01 /* 1/64 */ -#define SH7750_WTCSR_CKS_DIV128 0x02 /* 1/128 */ -#define SH7750_WTCSR_CKS_DIV256 0x03 /* 1/256 */ -#define SH7750_WTCSR_CKS_DIV512 0x04 /* 1/512 */ -#define SH7750_WTCSR_CKS_DIV1024 0x05 /* 1/1024 */ -#define SH7750_WTCSR_CKS_DIV2048 0x06 /* 1/2048 */ -#define SH7750_WTCSR_CKS_DIV4096 0x07 /* 1/4096 */ +#define SH7750_WTCSR_KEY 0xA500 /* When WTCSR byte register written, you */ + /* have to set the upper byte to 0xA5 */ +#define SH7750_WTCSR_TME 0x80 /* Timer enable (1-upcount start) */ +#define SH7750_WTCSR_MODE 0x40 /* Timer Mode Select: */ +#define SH7750_WTCSR_MODE_WT 0x40 /* Watchdog Timer Mode */ +#define SH7750_WTCSR_MODE_IT 0x00 /* Interval Timer Mode */ +#define SH7750_WTCSR_RSTS 0x20 /* Reset Select: */ +#define SH7750_WTCSR_RST_MAN 0x20 /* Manual Reset */ +#define SH7750_WTCSR_RST_PWR 0x00 /* Power-on Reset */ +#define SH7750_WTCSR_WOVF 0x10 /* Watchdog Timer Overflow Flag */ +#define SH7750_WTCSR_IOVF 0x08 /* Interval Timer Overflow Flag */ +#define SH7750_WTCSR_CKS 0x07 /* Clock Select: */ +#define SH7750_WTCSR_CKS_DIV32 0x00 /* 1/32 of frequency divider 2 input */ +#define SH7750_WTCSR_CKS_DIV64 0x01 /* 1/64 */ +#define SH7750_WTCSR_CKS_DIV128 0x02 /* 1/128 */ +#define SH7750_WTCSR_CKS_DIV256 0x03 /* 1/256 */ +#define SH7750_WTCSR_CKS_DIV512 0x04 /* 1/512 */ +#define SH7750_WTCSR_CKS_DIV1024 0x05 /* 1/1024 */ +#define SH7750_WTCSR_CKS_DIV2048 0x06 /* 1/2048 */ +#define SH7750_WTCSR_CKS_DIV4096 0x07 /* 1/4096 */ /* * Real-Time Clock (RTC) */ /* 64-Hz Counter Register (byte, read-only) - R64CNT */ -#define SH7750_R64CNT_REGOFS 0xC80000 /* offset */ +#define SH7750_R64CNT_REGOFS 0xC80000 /* offset */ #define SH7750_R64CNT SH7750_P4_REG32(SH7750_R64CNT_REGOFS) #define SH7750_R64CNT_A7 SH7750_A7_REG32(SH7750_R64CNT_REGOFS) /* Second Counter Register (byte, BCD-coded) - RSECCNT */ -#define SH7750_RSECCNT_REGOFS 0xC80004 /* offset */ +#define SH7750_RSECCNT_REGOFS 0xC80004 /* offset */ #define SH7750_RSECCNT SH7750_P4_REG32(SH7750_RSECCNT_REGOFS) #define SH7750_RSECCNT_A7 SH7750_A7_REG32(SH7750_RSECCNT_REGOFS) /* Minute Counter Register (byte, BCD-coded) - RMINCNT */ -#define SH7750_RMINCNT_REGOFS 0xC80008 /* offset */ +#define SH7750_RMINCNT_REGOFS 0xC80008 /* offset */ #define SH7750_RMINCNT SH7750_P4_REG32(SH7750_RMINCNT_REGOFS) #define SH7750_RMINCNT_A7 SH7750_A7_REG32(SH7750_RMINCNT_REGOFS) /* Hour Counter Register (byte, BCD-coded) - RHRCNT */ -#define SH7750_RHRCNT_REGOFS 0xC8000C /* offset */ +#define SH7750_RHRCNT_REGOFS 0xC8000C /* offset */ #define SH7750_RHRCNT SH7750_P4_REG32(SH7750_RHRCNT_REGOFS) #define SH7750_RHRCNT_A7 SH7750_A7_REG32(SH7750_RHRCNT_REGOFS) /* Day-of-Week Counter Register (byte) - RWKCNT */ -#define SH7750_RWKCNT_REGOFS 0xC80010 /* offset */ +#define SH7750_RWKCNT_REGOFS 0xC80010 /* offset */ #define SH7750_RWKCNT SH7750_P4_REG32(SH7750_RWKCNT_REGOFS) #define SH7750_RWKCNT_A7 SH7750_A7_REG32(SH7750_RWKCNT_REGOFS) -#define SH7750_RWKCNT_SUN 0 /* Sunday */ -#define SH7750_RWKCNT_MON 1 /* Monday */ -#define SH7750_RWKCNT_TUE 2 /* Tuesday */ -#define SH7750_RWKCNT_WED 3 /* Wednesday */ -#define SH7750_RWKCNT_THU 4 /* Thursday */ -#define SH7750_RWKCNT_FRI 5 /* Friday */ -#define SH7750_RWKCNT_SAT 6 /* Saturday */ +#define SH7750_RWKCNT_SUN 0 /* Sunday */ +#define SH7750_RWKCNT_MON 1 /* Monday */ +#define SH7750_RWKCNT_TUE 2 /* Tuesday */ +#define SH7750_RWKCNT_WED 3 /* Wednesday */ +#define SH7750_RWKCNT_THU 4 /* Thursday */ +#define SH7750_RWKCNT_FRI 5 /* Friday */ +#define SH7750_RWKCNT_SAT 6 /* Saturday */ /* Day Counter Register (byte, BCD-coded) - RDAYCNT */ -#define SH7750_RDAYCNT_REGOFS 0xC80014 /* offset */ +#define SH7750_RDAYCNT_REGOFS 0xC80014 /* offset */ #define SH7750_RDAYCNT SH7750_P4_REG32(SH7750_RDAYCNT_REGOFS) #define SH7750_RDAYCNT_A7 SH7750_A7_REG32(SH7750_RDAYCNT_REGOFS) /* Month Counter Register (byte, BCD-coded) - RMONCNT */ -#define SH7750_RMONCNT_REGOFS 0xC80018 /* offset */ +#define SH7750_RMONCNT_REGOFS 0xC80018 /* offset */ #define SH7750_RMONCNT SH7750_P4_REG32(SH7750_RMONCNT_REGOFS) #define SH7750_RMONCNT_A7 SH7750_A7_REG32(SH7750_RMONCNT_REGOFS) /* Year Counter Register (half, BCD-coded) - RYRCNT */ -#define SH7750_RYRCNT_REGOFS 0xC8001C /* offset */ +#define SH7750_RYRCNT_REGOFS 0xC8001C /* offset */ #define SH7750_RYRCNT SH7750_P4_REG32(SH7750_RYRCNT_REGOFS) #define SH7750_RYRCNT_A7 SH7750_A7_REG32(SH7750_RYRCNT_REGOFS) /* Second Alarm Register (byte, BCD-coded) - RSECAR */ -#define SH7750_RSECAR_REGOFS 0xC80020 /* offset */ +#define SH7750_RSECAR_REGOFS 0xC80020 /* offset */ #define SH7750_RSECAR SH7750_P4_REG32(SH7750_RSECAR_REGOFS) #define SH7750_RSECAR_A7 SH7750_A7_REG32(SH7750_RSECAR_REGOFS) -#define SH7750_RSECAR_ENB 0x80 /* Second Alarm Enable */ +#define SH7750_RSECAR_ENB 0x80 /* Second Alarm Enable */ /* Minute Alarm Register (byte, BCD-coded) - RMINAR */ -#define SH7750_RMINAR_REGOFS 0xC80024 /* offset */ +#define SH7750_RMINAR_REGOFS 0xC80024 /* offset */ #define SH7750_RMINAR SH7750_P4_REG32(SH7750_RMINAR_REGOFS) #define SH7750_RMINAR_A7 SH7750_A7_REG32(SH7750_RMINAR_REGOFS) -#define SH7750_RMINAR_ENB 0x80 /* Minute Alarm Enable */ +#define SH7750_RMINAR_ENB 0x80 /* Minute Alarm Enable */ /* Hour Alarm Register (byte, BCD-coded) - RHRAR */ -#define SH7750_RHRAR_REGOFS 0xC80028 /* offset */ +#define SH7750_RHRAR_REGOFS 0xC80028 /* offset */ #define SH7750_RHRAR SH7750_P4_REG32(SH7750_RHRAR_REGOFS) #define SH7750_RHRAR_A7 SH7750_A7_REG32(SH7750_RHRAR_REGOFS) -#define SH7750_RHRAR_ENB 0x80 /* Hour Alarm Enable */ +#define SH7750_RHRAR_ENB 0x80 /* Hour Alarm Enable */ /* Day-of-Week Alarm Register (byte) - RWKAR */ -#define SH7750_RWKAR_REGOFS 0xC8002C /* offset */ +#define SH7750_RWKAR_REGOFS 0xC8002C /* offset */ #define SH7750_RWKAR SH7750_P4_REG32(SH7750_RWKAR_REGOFS) #define SH7750_RWKAR_A7 SH7750_A7_REG32(SH7750_RWKAR_REGOFS) -#define SH7750_RWKAR_ENB 0x80 /* Day-of-week Alarm Enable */ +#define SH7750_RWKAR_ENB 0x80 /* Day-of-week Alarm Enable */ -#define SH7750_RWKAR_SUN 0 /* Sunday */ -#define SH7750_RWKAR_MON 1 /* Monday */ -#define SH7750_RWKAR_TUE 2 /* Tuesday */ -#define SH7750_RWKAR_WED 3 /* Wednesday */ -#define SH7750_RWKAR_THU 4 /* Thursday */ -#define SH7750_RWKAR_FRI 5 /* Friday */ -#define SH7750_RWKAR_SAT 6 /* Saturday */ +#define SH7750_RWKAR_SUN 0 /* Sunday */ +#define SH7750_RWKAR_MON 1 /* Monday */ +#define SH7750_RWKAR_TUE 2 /* Tuesday */ +#define SH7750_RWKAR_WED 3 /* Wednesday */ +#define SH7750_RWKAR_THU 4 /* Thursday */ +#define SH7750_RWKAR_FRI 5 /* Friday */ +#define SH7750_RWKAR_SAT 6 /* Saturday */ /* Day Alarm Register (byte, BCD-coded) - RDAYAR */ -#define SH7750_RDAYAR_REGOFS 0xC80030 /* offset */ +#define SH7750_RDAYAR_REGOFS 0xC80030 /* offset */ #define SH7750_RDAYAR SH7750_P4_REG32(SH7750_RDAYAR_REGOFS) #define SH7750_RDAYAR_A7 SH7750_A7_REG32(SH7750_RDAYAR_REGOFS) -#define SH7750_RDAYAR_ENB 0x80 /* Day Alarm Enable */ +#define SH7750_RDAYAR_ENB 0x80 /* Day Alarm Enable */ /* Month Counter Register (byte, BCD-coded) - RMONAR */ -#define SH7750_RMONAR_REGOFS 0xC80034 /* offset */ +#define SH7750_RMONAR_REGOFS 0xC80034 /* offset */ #define SH7750_RMONAR SH7750_P4_REG32(SH7750_RMONAR_REGOFS) #define SH7750_RMONAR_A7 SH7750_A7_REG32(SH7750_RMONAR_REGOFS) -#define SH7750_RMONAR_ENB 0x80 /* Month Alarm Enable */ +#define SH7750_RMONAR_ENB 0x80 /* Month Alarm Enable */ /* RTC Control Register 1 (byte) - RCR1 */ -#define SH7750_RCR1_REGOFS 0xC80038 /* offset */ +#define SH7750_RCR1_REGOFS 0xC80038 /* offset */ #define SH7750_RCR1 SH7750_P4_REG32(SH7750_RCR1_REGOFS) #define SH7750_RCR1_A7 SH7750_A7_REG32(SH7750_RCR1_REGOFS) -#define SH7750_RCR1_CF 0x80 /* Carry Flag */ -#define SH7750_RCR1_CIE 0x10 /* Carry Interrupt Enable */ -#define SH7750_RCR1_AIE 0x08 /* Alarm Interrupt Enable */ -#define SH7750_RCR1_AF 0x01 /* Alarm Flag */ +#define SH7750_RCR1_CF 0x80 /* Carry Flag */ +#define SH7750_RCR1_CIE 0x10 /* Carry Interrupt Enable */ +#define SH7750_RCR1_AIE 0x08 /* Alarm Interrupt Enable */ +#define SH7750_RCR1_AF 0x01 /* Alarm Flag */ /* RTC Control Register 2 (byte) - RCR2 */ -#define SH7750_RCR2_REGOFS 0xC8003C /* offset */ +#define SH7750_RCR2_REGOFS 0xC8003C /* offset */ #define SH7750_RCR2 SH7750_P4_REG32(SH7750_RCR2_REGOFS) #define SH7750_RCR2_A7 SH7750_A7_REG32(SH7750_RCR2_REGOFS) -#define SH7750_RCR2_PEF 0x80 /* Periodic Interrupt Flag */ -#define SH7750_RCR2_PES 0x70 /* Periodic Interrupt Enable: */ -#define SH7750_RCR2_PES_DIS 0x00 /* Periodic Interrupt Disabled */ -#define SH7750_RCR2_PES_DIV256 0x10 /* Generated at 1/256 sec interval */ -#define SH7750_RCR2_PES_DIV64 0x20 /* Generated at 1/64 sec interval */ -#define SH7750_RCR2_PES_DIV16 0x30 /* Generated at 1/16 sec interval */ -#define SH7750_RCR2_PES_DIV4 0x40 /* Generated at 1/4 sec interval */ -#define SH7750_RCR2_PES_DIV2 0x50 /* Generated at 1/2 sec interval */ -#define SH7750_RCR2_PES_x1 0x60 /* Generated at 1 sec interval */ -#define SH7750_RCR2_PES_x2 0x70 /* Generated at 2 sec interval */ -#define SH7750_RCR2_RTCEN 0x08 /* RTC Crystal Oscillator is Operated */ -#define SH7750_RCR2_ADJ 0x04 /* 30-Second Adjastment */ -#define SH7750_RCR2_RESET 0x02 /* Frequency divider circuits are reset */ -#define SH7750_RCR2_START 0x01 /* 0 - sec, min, hr, day-of-week, month, - year counters are stopped - 1 - sec, min, hr, day-of-week, month, - year counters operate normally */ +#define SH7750_RCR2_PEF 0x80 /* Periodic Interrupt Flag */ +#define SH7750_RCR2_PES 0x70 /* Periodic Interrupt Enable: */ +#define SH7750_RCR2_PES_DIS 0x00 /* Periodic Interrupt Disabled */ +#define SH7750_RCR2_PES_DIV256 0x10 /* Generated at 1/256 sec interval */ +#define SH7750_RCR2_PES_DIV64 0x20 /* Generated at 1/64 sec interval */ +#define SH7750_RCR2_PES_DIV16 0x30 /* Generated at 1/16 sec interval */ +#define SH7750_RCR2_PES_DIV4 0x40 /* Generated at 1/4 sec interval */ +#define SH7750_RCR2_PES_DIV2 0x50 /* Generated at 1/2 sec interval */ +#define SH7750_RCR2_PES_x1 0x60 /* Generated at 1 sec interval */ +#define SH7750_RCR2_PES_x2 0x70 /* Generated at 2 sec interval */ +#define SH7750_RCR2_RTCEN 0x08 /* RTC Crystal Oscillator is Operated */ +#define SH7750_RCR2_ADJ 0x04 /* 30-Second Adjastment */ +#define SH7750_RCR2_RESET 0x02 /* Frequency divider circuits are reset */ +#define SH7750_RCR2_START 0x01 /* 0 - sec, min, hr, day-of-week, month, */ + /* year counters are stopped */ + /* 1 - sec, min, hr, day-of-week, month, */ + /* year counters operate normally */ /* * Bus State Controller - BSC */ /* Bus Control Register 1 - BCR1 */ -#define SH7750_BCR1_REGOFS 0x800000 /* offset */ +#define SH7750_BCR1_REGOFS 0x800000 /* offset */ #define SH7750_BCR1 SH7750_P4_REG32(SH7750_BCR1_REGOFS) #define SH7750_BCR1_A7 SH7750_A7_REG32(SH7750_BCR1_REGOFS) -#define SH7750_BCR1_ENDIAN 0x80000000 /* Endianness (1 - little endian) */ -#define SH7750_BCR1_MASTER 0x40000000 /* Master/Slave mode (1-master) */ -#define SH7750_BCR1_A0MPX 0x20000000 /* Area 0 Memory Type (0-SRAM,1-MPX) */ -#define SH7750_BCR1_IPUP 0x02000000 /* Input Pin Pull-up Control: - 0 - pull-up resistor is on for - control input pins - 1 - pull-up resistor is off */ -#define SH7750_BCR1_OPUP 0x01000000 /* Output Pin Pull-up Control: - 0 - pull-up resistor is on for - control output pins - 1 - pull-up resistor is off */ -#define SH7750_BCR1_A1MBC 0x00200000 /* Area 1 SRAM Byte Control Mode: - 0 - Area 1 SRAM is set to - normal mode - 1 - Area 1 SRAM is set to byte - control mode */ -#define SH7750_BCR1_A4MBC 0x00100000 /* Area 4 SRAM Byte Control Mode: - 0 - Area 4 SRAM is set to - normal mode - 1 - Area 4 SRAM is set to byte - control mode */ -#define SH7750_BCR1_BREQEN 0x00080000 /* BREQ Enable: - 0 - External requests are not - accepted - 1 - External requests are - accepted */ -#define SH7750_BCR1_PSHR 0x00040000 /* Partial Sharing Bit: - 0 - Master Mode - 1 - Partial-sharing Mode */ -#define SH7750_BCR1_MEMMPX 0x00020000 /* Area 1 to 6 MPX Interface: - 0 - SRAM/burst ROM interface - 1 - MPX interface */ -#define SH7750_BCR1_HIZMEM 0x00008000 /* High Impendance Control. Specifies - the state of A[25:0], BS\, CSn\, - RD/WR\, CE2A\, CE2B\ in standby - mode and when bus is released: - 0 - signals go to High-Z mode - 1 - signals driven */ -#define SH7750_BCR1_HIZCNT 0x00004000 /* High Impendance Control. Specifies - the state of the RAS\, RAS2\, WEn\, - CASn\, DQMn, RD\, CASS\, FRAME\, - RD2\ signals in standby mode and - when bus is released: - 0 - signals go to High-Z mode - 1 - signals driven */ -#define SH7750_BCR1_A0BST 0x00003800 /* Area 0 Burst ROM Control */ -#define SH7750_BCR1_A0BST_SRAM 0x0000 /* Area 0 accessed as SRAM i/f */ -#define SH7750_BCR1_A0BST_ROM4 0x0800 /* Area 0 accessed as burst ROM - interface, 4 cosequtive access */ -#define SH7750_BCR1_A0BST_ROM8 0x1000 /* Area 0 accessed as burst ROM - interface, 8 cosequtive access */ -#define SH7750_BCR1_A0BST_ROM16 0x1800 /* Area 0 accessed as burst ROM - interface, 16 cosequtive access */ -#define SH7750_BCR1_A0BST_ROM32 0x2000 /* Area 0 accessed as burst ROM - interface, 32 cosequtive access */ - -#define SH7750_BCR1_A5BST 0x00000700 /* Area 5 Burst ROM Control */ -#define SH7750_BCR1_A5BST_SRAM 0x0000 /* Area 5 accessed as SRAM i/f */ -#define SH7750_BCR1_A5BST_ROM4 0x0100 /* Area 5 accessed as burst ROM - interface, 4 cosequtive access */ -#define SH7750_BCR1_A5BST_ROM8 0x0200 /* Area 5 accessed as burst ROM - interface, 8 cosequtive access */ -#define SH7750_BCR1_A5BST_ROM16 0x0300 /* Area 5 accessed as burst ROM - interface, 16 cosequtive access */ -#define SH7750_BCR1_A5BST_ROM32 0x0400 /* Area 5 accessed as burst ROM - interface, 32 cosequtive access */ - -#define SH7750_BCR1_A6BST 0x000000E0 /* Area 6 Burst ROM Control */ -#define SH7750_BCR1_A6BST_SRAM 0x0000 /* Area 6 accessed as SRAM i/f */ -#define SH7750_BCR1_A6BST_ROM4 0x0020 /* Area 6 accessed as burst ROM - interface, 4 cosequtive access */ -#define SH7750_BCR1_A6BST_ROM8 0x0040 /* Area 6 accessed as burst ROM - interface, 8 cosequtive access */ -#define SH7750_BCR1_A6BST_ROM16 0x0060 /* Area 6 accessed as burst ROM - interface, 16 cosequtive access */ -#define SH7750_BCR1_A6BST_ROM32 0x0080 /* Area 6 accessed as burst ROM - interface, 32 cosequtive access */ - -#define SH7750_BCR1_DRAMTP 0x001C /* Area 2 and 3 Memory Type */ -#define SH7750_BCR1_DRAMTP_2SRAM_3SRAM 0x0000 /* Area 2 and 3 are SRAM or MPX - interface. */ -#define SH7750_BCR1_DRAMTP_2SRAM_3SDRAM 0x0008 /* Area 2 - SRAM/MPX, Area 3 - - synchronous DRAM */ -#define SH7750_BCR1_DRAMTP_2SDRAM_3SDRAM 0x000C /* Area 2 and 3 are synchronous - DRAM interface */ -#define SH7750_BCR1_DRAMTP_2SRAM_3DRAM 0x0010 /* Area 2 - SRAM/MPX, Area 3 - - DRAM interface */ -#define SH7750_BCR1_DRAMTP_2DRAM_3DRAM 0x0014 /* Area 2 and 3 are DRAM - interface */ - -#define SH7750_BCR1_A56PCM 0x00000001 /* Area 5 and 6 Bus Type: - 0 - SRAM interface - 1 - PCMCIA interface */ +#define SH7750_BCR1_ENDIAN 0x80000000 /* Endianness (1 - little endian) */ +#define SH7750_BCR1_MASTER 0x40000000 /* Master/Slave mode (1-master) */ +#define SH7750_BCR1_A0MPX 0x20000000 /* Area 0 Memory Type (0-SRAM,1-MPX) */ +#define SH7750_BCR1_IPUP 0x02000000 /* Input Pin Pull-up Control: */ + /* 0 - pull-up resistor is on for */ + /* control input pins */ + /* 1 - pull-up resistor is off */ +#define SH7750_BCR1_OPUP 0x01000000 /* Output Pin Pull-up Control: */ + /* 0 - pull-up resistor is on for */ + /* control output pins */ + /* 1 - pull-up resistor is off */ +#define SH7750_BCR1_A1MBC 0x00200000 /* Area 1 SRAM Byte Control Mode: */ + /* 0 - Area 1 SRAM is set to */ + /* normal mode */ + /* 1 - Area 1 SRAM is set to byte */ + /* control mode */ +#define SH7750_BCR1_A4MBC 0x00100000 /* Area 4 SRAM Byte Control Mode: */ + /* 0 - Area 4 SRAM is set to */ + /* normal mode */ + /* 1 - Area 4 SRAM is set to byte */ + /* control mode */ +#define SH7750_BCR1_BREQEN 0x00080000 /* BREQ Enable: */ + /* 0 - External requests are not */ + /* accepted */ + /* 1 - External requests are */ + /* accepted */ +#define SH7750_BCR1_PSHR 0x00040000 /* Partial Sharing Bit: */ + /* 0 - Master Mode */ + /* 1 - Partial-sharing Mode */ +#define SH7750_BCR1_MEMMPX 0x00020000 /* Area 1 to 6 MPX Interface: */ + /* 0 - SRAM/burst ROM interface */ + /* 1 - MPX interface */ +#define SH7750_BCR1_HIZMEM 0x00008000 /* High Impendance Control. */ + /* Specifies the state of A[25:0], */ + /* BS\, CSn\, RD/WR\, CE2A\, CE2B\ */ + /* in standby mode and when bus is */ + /* released: */ + /* 0 - signals go to High-Z mode */ + /* 1 - signals driven */ +#define SH7750_BCR1_HIZCNT 0x00004000 /* High Impendance Control. */ + /* Specifies the state of the */ + /* RAS\, RAS2\, WEn\, CASn\, DQMn, */ + /* RD\, CASS\, FRAME\, RD2\ */ + /* signals in standby mode and */ + /* when bus is released: */ + /* 0 - signals go to High-Z mode */ + /* 1 - signals driven */ +#define SH7750_BCR1_A0BST 0x00003800 /* Area 0 Burst ROM Control */ +#define SH7750_BCR1_A0BST_SRAM 0x0000 /* Area 0 accessed as SRAM i/f */ +#define SH7750_BCR1_A0BST_ROM4 0x0800 /* Area 0 accessed as burst ROM */ + /* interface, 4 cosequtive access */ +#define SH7750_BCR1_A0BST_ROM8 0x1000 /* Area 0 accessed as burst ROM */ + /* interface, 8 cosequtive access */ +#define SH7750_BCR1_A0BST_ROM16 0x1800 /* Area 0 accessed as burst ROM */ + /* interface, 16 cosequtive access */ +#define SH7750_BCR1_A0BST_ROM32 0x2000 /* Area 0 accessed as burst ROM */ + /* interface, 32 cosequtive access */ + +#define SH7750_BCR1_A5BST 0x00000700 /* Area 5 Burst ROM Control */ +#define SH7750_BCR1_A5BST_SRAM 0x0000 /* Area 5 accessed as SRAM i/f */ +#define SH7750_BCR1_A5BST_ROM4 0x0100 /* Area 5 accessed as burst ROM */ + /* interface, 4 cosequtive access */ +#define SH7750_BCR1_A5BST_ROM8 0x0200 /* Area 5 accessed as burst ROM */ + /* interface, 8 cosequtive access */ +#define SH7750_BCR1_A5BST_ROM16 0x0300 /* Area 5 accessed as burst ROM */ + /* interface, 16 cosequtive access */ +#define SH7750_BCR1_A5BST_ROM32 0x0400 /* Area 5 accessed as burst ROM */ + /* interface, 32 cosequtive access */ + +#define SH7750_BCR1_A6BST 0x000000E0 /* Area 6 Burst ROM Control */ +#define SH7750_BCR1_A6BST_SRAM 0x0000 /* Area 6 accessed as SRAM i/f */ +#define SH7750_BCR1_A6BST_ROM4 0x0020 /* Area 6 accessed as burst ROM */ + /* interface, 4 cosequtive access */ +#define SH7750_BCR1_A6BST_ROM8 0x0040 /* Area 6 accessed as burst ROM */ + /* interface, 8 cosequtive access */ +#define SH7750_BCR1_A6BST_ROM16 0x0060 /* Area 6 accessed as burst ROM */ + /* interface, 16 cosequtive access */ +#define SH7750_BCR1_A6BST_ROM32 0x0080 /* Area 6 accessed as burst ROM */ + /* interface, 32 cosequtive access */ + +#define SH7750_BCR1_DRAMTP 0x001C /* Area 2 and 3 Memory Type */ +#define SH7750_BCR1_DRAMTP_2SRAM_3SRAM 0x0000 /* Area 2 and 3 are SRAM or */ + /* MPX interface. */ +#define SH7750_BCR1_DRAMTP_2SRAM_3SDRAM 0x0008 /* Area 2 - SRAM/MPX, Area 3 */ + /* synchronous DRAM */ +#define SH7750_BCR1_DRAMTP_2SDRAM_3SDRAM 0x000C /* Area 2 and 3 are */ + /* synchronous DRAM interface */ +#define SH7750_BCR1_DRAMTP_2SRAM_3DRAM 0x0010 /* Area 2 - SRAM/MPX, Area 3 */ + /* DRAM interface */ +#define SH7750_BCR1_DRAMTP_2DRAM_3DRAM 0x0014 /* Area 2 and 3 are DRAM */ + /* interface */ + +#define SH7750_BCR1_A56PCM 0x00000001 /* Area 5 and 6 Bus Type: */ + /* 0 - SRAM interface */ + /* 1 - PCMCIA interface */ /* Bus Control Register 2 (half) - BCR2 */ -#define SH7750_BCR2_REGOFS 0x800004 /* offset */ +#define SH7750_BCR2_REGOFS 0x800004 /* offset */ #define SH7750_BCR2 SH7750_P4_REG32(SH7750_BCR2_REGOFS) #define SH7750_BCR2_A7 SH7750_A7_REG32(SH7750_BCR2_REGOFS) -#define SH7750_BCR2_A0SZ 0xC000 /* Area 0 Bus Width */ +#define SH7750_BCR2_A0SZ 0xC000 /* Area 0 Bus Width */ #define SH7750_BCR2_A0SZ_S 14 -#define SH7750_BCR2_A6SZ 0x3000 /* Area 6 Bus Width */ +#define SH7750_BCR2_A6SZ 0x3000 /* Area 6 Bus Width */ #define SH7750_BCR2_A6SZ_S 12 -#define SH7750_BCR2_A5SZ 0x0C00 /* Area 5 Bus Width */ +#define SH7750_BCR2_A5SZ 0x0C00 /* Area 5 Bus Width */ #define SH7750_BCR2_A5SZ_S 10 -#define SH7750_BCR2_A4SZ 0x0300 /* Area 4 Bus Width */ +#define SH7750_BCR2_A4SZ 0x0300 /* Area 4 Bus Width */ #define SH7750_BCR2_A4SZ_S 8 -#define SH7750_BCR2_A3SZ 0x00C0 /* Area 3 Bus Width */ +#define SH7750_BCR2_A3SZ 0x00C0 /* Area 3 Bus Width */ #define SH7750_BCR2_A3SZ_S 6 -#define SH7750_BCR2_A2SZ 0x0030 /* Area 2 Bus Width */ +#define SH7750_BCR2_A2SZ 0x0030 /* Area 2 Bus Width */ #define SH7750_BCR2_A2SZ_S 4 -#define SH7750_BCR2_A1SZ 0x000C /* Area 1 Bus Width */ +#define SH7750_BCR2_A1SZ 0x000C /* Area 1 Bus Width */ #define SH7750_BCR2_A1SZ_S 2 -#define SH7750_BCR2_SZ_64 0 /* 64 bits */ -#define SH7750_BCR2_SZ_8 1 /* 8 bits */ -#define SH7750_BCR2_SZ_16 2 /* 16 bits */ -#define SH7750_BCR2_SZ_32 3 /* 32 bits */ -#define SH7750_BCR2_PORTEN 0x0001 /* Port Function Enable : - 0 - D51-D32 are not used as a port - 1 - D51-D32 are used as a port */ +#define SH7750_BCR2_SZ_64 0 /* 64 bits */ +#define SH7750_BCR2_SZ_8 1 /* 8 bits */ +#define SH7750_BCR2_SZ_16 2 /* 16 bits */ +#define SH7750_BCR2_SZ_32 3 /* 32 bits */ +#define SH7750_BCR2_PORTEN 0x0001 /* Port Function Enable */ + /* 0 - D51-D32 are not used as a port */ + /* 1 - D51-D32 are used as a port */ /* Wait Control Register 1 - WCR1 */ -#define SH7750_WCR1_REGOFS 0x800008 /* offset */ +#define SH7750_WCR1_REGOFS 0x800008 /* offset */ #define SH7750_WCR1 SH7750_P4_REG32(SH7750_WCR1_REGOFS) #define SH7750_WCR1_A7 SH7750_A7_REG32(SH7750_WCR1_REGOFS) -#define SH7750_WCR1_DMAIW 0x70000000 /* DACK Device Inter-Cycle Idle - specification */ +#define SH7750_WCR1_DMAIW 0x70000000 /* DACK Device Inter-Cycle Idle */ + /* specification */ #define SH7750_WCR1_DMAIW_S 28 -#define SH7750_WCR1_A6IW 0x07000000 /* Area 6 Inter-Cycle Idle spec. */ +#define SH7750_WCR1_A6IW 0x07000000 /* Area 6 Inter-Cycle Idle spec. */ #define SH7750_WCR1_A6IW_S 24 -#define SH7750_WCR1_A5IW 0x00700000 /* Area 5 Inter-Cycle Idle spec. */ +#define SH7750_WCR1_A5IW 0x00700000 /* Area 5 Inter-Cycle Idle spec. */ #define SH7750_WCR1_A5IW_S 20 -#define SH7750_WCR1_A4IW 0x00070000 /* Area 4 Inter-Cycle Idle spec. */ +#define SH7750_WCR1_A4IW 0x00070000 /* Area 4 Inter-Cycle Idle spec. */ #define SH7750_WCR1_A4IW_S 16 -#define SH7750_WCR1_A3IW 0x00007000 /* Area 3 Inter-Cycle Idle spec. */ +#define SH7750_WCR1_A3IW 0x00007000 /* Area 3 Inter-Cycle Idle spec. */ #define SH7750_WCR1_A3IW_S 12 -#define SH7750_WCR1_A2IW 0x00000700 /* Area 2 Inter-Cycle Idle spec. */ +#define SH7750_WCR1_A2IW 0x00000700 /* Area 2 Inter-Cycle Idle spec. */ #define SH7750_WCR1_A2IW_S 8 -#define SH7750_WCR1_A1IW 0x00000070 /* Area 1 Inter-Cycle Idle spec. */ +#define SH7750_WCR1_A1IW 0x00000070 /* Area 1 Inter-Cycle Idle spec. */ #define SH7750_WCR1_A1IW_S 4 -#define SH7750_WCR1_A0IW 0x00000007 /* Area 0 Inter-Cycle Idle spec. */ +#define SH7750_WCR1_A0IW 0x00000007 /* Area 0 Inter-Cycle Idle spec. */ #define SH7750_WCR1_A0IW_S 0 /* Wait Control Register 2 - WCR2 */ -#define SH7750_WCR2_REGOFS 0x80000C /* offset */ +#define SH7750_WCR2_REGOFS 0x80000C /* offset */ #define SH7750_WCR2 SH7750_P4_REG32(SH7750_WCR2_REGOFS) #define SH7750_WCR2_A7 SH7750_A7_REG32(SH7750_WCR2_REGOFS) -#define SH7750_WCR2_A6W 0xE0000000 /* Area 6 Wait Control */ +#define SH7750_WCR2_A6W 0xE0000000 /* Area 6 Wait Control */ #define SH7750_WCR2_A6W_S 29 -#define SH7750_WCR2_A6B 0x1C000000 /* Area 6 Burst Pitch */ +#define SH7750_WCR2_A6B 0x1C000000 /* Area 6 Burst Pitch */ #define SH7750_WCR2_A6B_S 26 -#define SH7750_WCR2_A5W 0x03800000 /* Area 5 Wait Control */ +#define SH7750_WCR2_A5W 0x03800000 /* Area 5 Wait Control */ #define SH7750_WCR2_A5W_S 23 -#define SH7750_WCR2_A5B 0x00700000 /* Area 5 Burst Pitch */ +#define SH7750_WCR2_A5B 0x00700000 /* Area 5 Burst Pitch */ #define SH7750_WCR2_A5B_S 20 -#define SH7750_WCR2_A4W 0x000E0000 /* Area 4 Wait Control */ +#define SH7750_WCR2_A4W 0x000E0000 /* Area 4 Wait Control */ #define SH7750_WCR2_A4W_S 17 -#define SH7750_WCR2_A3W 0x0000E000 /* Area 3 Wait Control */ +#define SH7750_WCR2_A3W 0x0000E000 /* Area 3 Wait Control */ #define SH7750_WCR2_A3W_S 13 -#define SH7750_WCR2_A2W 0x00000E00 /* Area 2 Wait Control */ +#define SH7750_WCR2_A2W 0x00000E00 /* Area 2 Wait Control */ #define SH7750_WCR2_A2W_S 9 -#define SH7750_WCR2_A1W 0x000001C0 /* Area 1 Wait Control */ +#define SH7750_WCR2_A1W 0x000001C0 /* Area 1 Wait Control */ #define SH7750_WCR2_A1W_S 6 -#define SH7750_WCR2_A0W 0x00000038 /* Area 0 Wait Control */ +#define SH7750_WCR2_A0W 0x00000038 /* Area 0 Wait Control */ #define SH7750_WCR2_A0W_S 3 -#define SH7750_WCR2_A0B 0x00000007 /* Area 0 Burst Pitch */ +#define SH7750_WCR2_A0B 0x00000007 /* Area 0 Burst Pitch */ #define SH7750_WCR2_A0B_S 0 -#define SH7750_WCR2_WS0 0 /* 0 wait states inserted */ -#define SH7750_WCR2_WS1 1 /* 1 wait states inserted */ -#define SH7750_WCR2_WS2 2 /* 2 wait states inserted */ -#define SH7750_WCR2_WS3 3 /* 3 wait states inserted */ -#define SH7750_WCR2_WS6 4 /* 6 wait states inserted */ -#define SH7750_WCR2_WS9 5 /* 9 wait states inserted */ -#define SH7750_WCR2_WS12 6 /* 12 wait states inserted */ -#define SH7750_WCR2_WS15 7 /* 15 wait states inserted */ - -#define SH7750_WCR2_BPWS0 0 /* 0 wait states inserted from 2nd access */ -#define SH7750_WCR2_BPWS1 1 /* 1 wait states inserted from 2nd access */ -#define SH7750_WCR2_BPWS2 2 /* 2 wait states inserted from 2nd access */ -#define SH7750_WCR2_BPWS3 3 /* 3 wait states inserted from 2nd access */ -#define SH7750_WCR2_BPWS4 4 /* 4 wait states inserted from 2nd access */ -#define SH7750_WCR2_BPWS5 5 /* 5 wait states inserted from 2nd access */ -#define SH7750_WCR2_BPWS6 6 /* 6 wait states inserted from 2nd access */ -#define SH7750_WCR2_BPWS7 7 /* 7 wait states inserted from 2nd access */ +#define SH7750_WCR2_WS0 0 /* 0 wait states inserted */ +#define SH7750_WCR2_WS1 1 /* 1 wait states inserted */ +#define SH7750_WCR2_WS2 2 /* 2 wait states inserted */ +#define SH7750_WCR2_WS3 3 /* 3 wait states inserted */ +#define SH7750_WCR2_WS6 4 /* 6 wait states inserted */ +#define SH7750_WCR2_WS9 5 /* 9 wait states inserted */ +#define SH7750_WCR2_WS12 6 /* 12 wait states inserted */ +#define SH7750_WCR2_WS15 7 /* 15 wait states inserted */ + +#define SH7750_WCR2_BPWS0 0 /* 0 wait states inserted from 2nd access */ +#define SH7750_WCR2_BPWS1 1 /* 1 wait states inserted from 2nd access */ +#define SH7750_WCR2_BPWS2 2 /* 2 wait states inserted from 2nd access */ +#define SH7750_WCR2_BPWS3 3 /* 3 wait states inserted from 2nd access */ +#define SH7750_WCR2_BPWS4 4 /* 4 wait states inserted from 2nd access */ +#define SH7750_WCR2_BPWS5 5 /* 5 wait states inserted from 2nd access */ +#define SH7750_WCR2_BPWS6 6 /* 6 wait states inserted from 2nd access */ +#define SH7750_WCR2_BPWS7 7 /* 7 wait states inserted from 2nd access */ /* DRAM CAS\ Assertion Delay (area 3,2) */ -#define SH7750_WCR2_DRAM_CAS_ASW1 0 /* 1 cycle */ -#define SH7750_WCR2_DRAM_CAS_ASW2 1 /* 2 cycles */ -#define SH7750_WCR2_DRAM_CAS_ASW3 2 /* 3 cycles */ -#define SH7750_WCR2_DRAM_CAS_ASW4 3 /* 4 cycles */ -#define SH7750_WCR2_DRAM_CAS_ASW7 4 /* 7 cycles */ -#define SH7750_WCR2_DRAM_CAS_ASW10 5 /* 10 cycles */ -#define SH7750_WCR2_DRAM_CAS_ASW13 6 /* 13 cycles */ -#define SH7750_WCR2_DRAM_CAS_ASW16 7 /* 16 cycles */ +#define SH7750_WCR2_DRAM_CAS_ASW1 0 /* 1 cycle */ +#define SH7750_WCR2_DRAM_CAS_ASW2 1 /* 2 cycles */ +#define SH7750_WCR2_DRAM_CAS_ASW3 2 /* 3 cycles */ +#define SH7750_WCR2_DRAM_CAS_ASW4 3 /* 4 cycles */ +#define SH7750_WCR2_DRAM_CAS_ASW7 4 /* 7 cycles */ +#define SH7750_WCR2_DRAM_CAS_ASW10 5 /* 10 cycles */ +#define SH7750_WCR2_DRAM_CAS_ASW13 6 /* 13 cycles */ +#define SH7750_WCR2_DRAM_CAS_ASW16 7 /* 16 cycles */ /* SDRAM CAS\ Latency Cycles */ -#define SH7750_WCR2_SDRAM_CAS_LAT1 1 /* 1 cycle */ -#define SH7750_WCR2_SDRAM_CAS_LAT2 2 /* 2 cycles */ -#define SH7750_WCR2_SDRAM_CAS_LAT3 3 /* 3 cycles */ -#define SH7750_WCR2_SDRAM_CAS_LAT4 4 /* 4 cycles */ -#define SH7750_WCR2_SDRAM_CAS_LAT5 5 /* 5 cycles */ +#define SH7750_WCR2_SDRAM_CAS_LAT1 1 /* 1 cycle */ +#define SH7750_WCR2_SDRAM_CAS_LAT2 2 /* 2 cycles */ +#define SH7750_WCR2_SDRAM_CAS_LAT3 3 /* 3 cycles */ +#define SH7750_WCR2_SDRAM_CAS_LAT4 4 /* 4 cycles */ +#define SH7750_WCR2_SDRAM_CAS_LAT5 5 /* 5 cycles */ /* Wait Control Register 3 - WCR3 */ -#define SH7750_WCR3_REGOFS 0x800010 /* offset */ +#define SH7750_WCR3_REGOFS 0x800010 /* offset */ #define SH7750_WCR3 SH7750_P4_REG32(SH7750_WCR3_REGOFS) #define SH7750_WCR3_A7 SH7750_A7_REG32(SH7750_WCR3_REGOFS) -#define SH7750_WCR3_A6S 0x04000000 /* Area 6 Write Strobe Setup time */ -#define SH7750_WCR3_A6H 0x03000000 /* Area 6 Data Hold Time */ +#define SH7750_WCR3_A6S 0x04000000 /* Area 6 Write Strobe Setup time */ +#define SH7750_WCR3_A6H 0x03000000 /* Area 6 Data Hold Time */ #define SH7750_WCR3_A6H_S 24 -#define SH7750_WCR3_A5S 0x00400000 /* Area 5 Write Strobe Setup time */ -#define SH7750_WCR3_A5H 0x00300000 /* Area 5 Data Hold Time */ +#define SH7750_WCR3_A5S 0x00400000 /* Area 5 Write Strobe Setup time */ +#define SH7750_WCR3_A5H 0x00300000 /* Area 5 Data Hold Time */ #define SH7750_WCR3_A5H_S 20 -#define SH7750_WCR3_A4S 0x00040000 /* Area 4 Write Strobe Setup time */ -#define SH7750_WCR3_A4H 0x00030000 /* Area 4 Data Hold Time */ +#define SH7750_WCR3_A4S 0x00040000 /* Area 4 Write Strobe Setup time */ +#define SH7750_WCR3_A4H 0x00030000 /* Area 4 Data Hold Time */ #define SH7750_WCR3_A4H_S 16 -#define SH7750_WCR3_A3S 0x00004000 /* Area 3 Write Strobe Setup time */ -#define SH7750_WCR3_A3H 0x00003000 /* Area 3 Data Hold Time */ +#define SH7750_WCR3_A3S 0x00004000 /* Area 3 Write Strobe Setup time */ +#define SH7750_WCR3_A3H 0x00003000 /* Area 3 Data Hold Time */ #define SH7750_WCR3_A3H_S 12 -#define SH7750_WCR3_A2S 0x00000400 /* Area 2 Write Strobe Setup time */ -#define SH7750_WCR3_A2H 0x00000300 /* Area 2 Data Hold Time */ +#define SH7750_WCR3_A2S 0x00000400 /* Area 2 Write Strobe Setup time */ +#define SH7750_WCR3_A2H 0x00000300 /* Area 2 Data Hold Time */ #define SH7750_WCR3_A2H_S 8 -#define SH7750_WCR3_A1S 0x00000040 /* Area 1 Write Strobe Setup time */ -#define SH7750_WCR3_A1H 0x00000030 /* Area 1 Data Hold Time */ +#define SH7750_WCR3_A1S 0x00000040 /* Area 1 Write Strobe Setup time */ +#define SH7750_WCR3_A1H 0x00000030 /* Area 1 Data Hold Time */ #define SH7750_WCR3_A1H_S 4 -#define SH7750_WCR3_A0S 0x00000004 /* Area 0 Write Strobe Setup time */ -#define SH7750_WCR3_A0H 0x00000003 /* Area 0 Data Hold Time */ +#define SH7750_WCR3_A0S 0x00000004 /* Area 0 Write Strobe Setup time */ +#define SH7750_WCR3_A0H 0x00000003 /* Area 0 Data Hold Time */ #define SH7750_WCR3_A0H_S 0 -#define SH7750_WCR3_DHWS_0 0 /* 0 wait states data hold time */ -#define SH7750_WCR3_DHWS_1 1 /* 1 wait states data hold time */ -#define SH7750_WCR3_DHWS_2 2 /* 2 wait states data hold time */ -#define SH7750_WCR3_DHWS_3 3 /* 3 wait states data hold time */ +#define SH7750_WCR3_DHWS_0 0 /* 0 wait states data hold time */ +#define SH7750_WCR3_DHWS_1 1 /* 1 wait states data hold time */ +#define SH7750_WCR3_DHWS_2 2 /* 2 wait states data hold time */ +#define SH7750_WCR3_DHWS_3 3 /* 3 wait states data hold time */ -#define SH7750_MCR_REGOFS 0x800014 /* offset */ +#define SH7750_MCR_REGOFS 0x800014 /* offset */ #define SH7750_MCR SH7750_P4_REG32(SH7750_MCR_REGOFS) #define SH7750_MCR_A7 SH7750_A7_REG32(SH7750_MCR_REGOFS) -#define SH7750_MCR_RASD 0x80000000 /* RAS Down mode */ -#define SH7750_MCR_MRSET 0x40000000 /* SDRAM Mode Register Set */ -#define SH7750_MCR_PALL 0x00000000 /* SDRAM Precharge All cmd. Mode */ -#define SH7750_MCR_TRC 0x38000000 /* RAS Precharge Time at End of - Refresh: */ -#define SH7750_MCR_TRC_0 0x00000000 /* 0 */ -#define SH7750_MCR_TRC_3 0x08000000 /* 3 */ -#define SH7750_MCR_TRC_6 0x10000000 /* 6 */ -#define SH7750_MCR_TRC_9 0x18000000 /* 9 */ -#define SH7750_MCR_TRC_12 0x20000000 /* 12 */ -#define SH7750_MCR_TRC_15 0x28000000 /* 15 */ -#define SH7750_MCR_TRC_18 0x30000000 /* 18 */ -#define SH7750_MCR_TRC_21 0x38000000 /* 21 */ - -#define SH7750_MCR_TCAS 0x00800000 /* CAS Negation Period */ -#define SH7750_MCR_TCAS_1 0x00000000 /* 1 */ -#define SH7750_MCR_TCAS_2 0x00800000 /* 2 */ - -#define SH7750_MCR_TPC 0x00380000 /* DRAM: RAS Precharge Period - SDRAM: minimum number of cycles - until the next bank active cmd - is output after precharging */ +#define SH7750_MCR_RASD 0x80000000 /* RAS Down mode */ +#define SH7750_MCR_MRSET 0x40000000 /* SDRAM Mode Register Set */ +#define SH7750_MCR_PALL 0x00000000 /* SDRAM Precharge All cmd. Mode */ +#define SH7750_MCR_TRC 0x38000000 /* RAS Precharge Time at End of */ + /* Refresh: */ +#define SH7750_MCR_TRC_0 0x00000000 /* 0 */ +#define SH7750_MCR_TRC_3 0x08000000 /* 3 */ +#define SH7750_MCR_TRC_6 0x10000000 /* 6 */ +#define SH7750_MCR_TRC_9 0x18000000 /* 9 */ +#define SH7750_MCR_TRC_12 0x20000000 /* 12 */ +#define SH7750_MCR_TRC_15 0x28000000 /* 15 */ +#define SH7750_MCR_TRC_18 0x30000000 /* 18 */ +#define SH7750_MCR_TRC_21 0x38000000 /* 21 */ + +#define SH7750_MCR_TCAS 0x00800000 /* CAS Negation Period */ +#define SH7750_MCR_TCAS_1 0x00000000 /* 1 */ +#define SH7750_MCR_TCAS_2 0x00800000 /* 2 */ + +#define SH7750_MCR_TPC 0x00380000 /* DRAM: RAS Precharge Period */ + /* SDRAM: minimum number of cycles */ + /* until the next bank active cmd */ + /* is output after precharging */ #define SH7750_MCR_TPC_S 19 -#define SH7750_MCR_TPC_SDRAM_1 0x00000000 /* 1 cycle */ -#define SH7750_MCR_TPC_SDRAM_2 0x00080000 /* 2 cycles */ -#define SH7750_MCR_TPC_SDRAM_3 0x00100000 /* 3 cycles */ -#define SH7750_MCR_TPC_SDRAM_4 0x00180000 /* 4 cycles */ -#define SH7750_MCR_TPC_SDRAM_5 0x00200000 /* 5 cycles */ -#define SH7750_MCR_TPC_SDRAM_6 0x00280000 /* 6 cycles */ -#define SH7750_MCR_TPC_SDRAM_7 0x00300000 /* 7 cycles */ -#define SH7750_MCR_TPC_SDRAM_8 0x00380000 /* 8 cycles */ - -#define SH7750_MCR_RCD 0x00030000 /* DRAM: RAS-CAS Assertion Delay time - SDRAM: bank active-read/write cmd - delay time */ -#define SH7750_MCR_RCD_DRAM_2 0x00000000 /* DRAM delay 2 clocks */ -#define SH7750_MCR_RCD_DRAM_3 0x00010000 /* DRAM delay 3 clocks */ -#define SH7750_MCR_RCD_DRAM_4 0x00020000 /* DRAM delay 4 clocks */ -#define SH7750_MCR_RCD_DRAM_5 0x00030000 /* DRAM delay 5 clocks */ -#define SH7750_MCR_RCD_SDRAM_2 0x00010000 /* DRAM delay 2 clocks */ -#define SH7750_MCR_RCD_SDRAM_3 0x00020000 /* DRAM delay 3 clocks */ -#define SH7750_MCR_RCD_SDRAM_4 0x00030000 /* DRAM delay 4 clocks */ - -#define SH7750_MCR_TRWL 0x0000E000 /* SDRAM Write Precharge Delay */ -#define SH7750_MCR_TRWL_1 0x00000000 /* 1 */ -#define SH7750_MCR_TRWL_2 0x00002000 /* 2 */ -#define SH7750_MCR_TRWL_3 0x00004000 /* 3 */ -#define SH7750_MCR_TRWL_4 0x00006000 /* 4 */ -#define SH7750_MCR_TRWL_5 0x00008000 /* 5 */ - -#define SH7750_MCR_TRAS 0x00001C00 /* DRAM: CAS-Before-RAS Refresh RAS - asserting period - SDRAM: Command interval after - synchronous DRAM refresh */ -#define SH7750_MCR_TRAS_DRAM_2 0x00000000 /* 2 */ -#define SH7750_MCR_TRAS_DRAM_3 0x00000400 /* 3 */ -#define SH7750_MCR_TRAS_DRAM_4 0x00000800 /* 4 */ -#define SH7750_MCR_TRAS_DRAM_5 0x00000C00 /* 5 */ -#define SH7750_MCR_TRAS_DRAM_6 0x00001000 /* 6 */ -#define SH7750_MCR_TRAS_DRAM_7 0x00001400 /* 7 */ -#define SH7750_MCR_TRAS_DRAM_8 0x00001800 /* 8 */ -#define SH7750_MCR_TRAS_DRAM_9 0x00001C00 /* 9 */ - -#define SH7750_MCR_TRAS_SDRAM_TRC_4 0x00000000 /* 4 + TRC */ -#define SH7750_MCR_TRAS_SDRAM_TRC_5 0x00000400 /* 5 + TRC */ -#define SH7750_MCR_TRAS_SDRAM_TRC_6 0x00000800 /* 6 + TRC */ -#define SH7750_MCR_TRAS_SDRAM_TRC_7 0x00000C00 /* 7 + TRC */ -#define SH7750_MCR_TRAS_SDRAM_TRC_8 0x00001000 /* 8 + TRC */ -#define SH7750_MCR_TRAS_SDRAM_TRC_9 0x00001400 /* 9 + TRC */ -#define SH7750_MCR_TRAS_SDRAM_TRC_10 0x00001800 /* 10 + TRC */ -#define SH7750_MCR_TRAS_SDRAM_TRC_11 0x00001C00 /* 11 + TRC */ - -#define SH7750_MCR_BE 0x00000200 /* Burst Enable */ -#define SH7750_MCR_SZ 0x00000180 /* Memory Data Size */ -#define SH7750_MCR_SZ_64 0x00000000 /* 64 bits */ -#define SH7750_MCR_SZ_16 0x00000100 /* 16 bits */ -#define SH7750_MCR_SZ_32 0x00000180 /* 32 bits */ - -#define SH7750_MCR_AMX 0x00000078 /* Address Multiplexing */ +#define SH7750_MCR_TPC_SDRAM_1 0x00000000 /* 1 cycle */ +#define SH7750_MCR_TPC_SDRAM_2 0x00080000 /* 2 cycles */ +#define SH7750_MCR_TPC_SDRAM_3 0x00100000 /* 3 cycles */ +#define SH7750_MCR_TPC_SDRAM_4 0x00180000 /* 4 cycles */ +#define SH7750_MCR_TPC_SDRAM_5 0x00200000 /* 5 cycles */ +#define SH7750_MCR_TPC_SDRAM_6 0x00280000 /* 6 cycles */ +#define SH7750_MCR_TPC_SDRAM_7 0x00300000 /* 7 cycles */ +#define SH7750_MCR_TPC_SDRAM_8 0x00380000 /* 8 cycles */ + +#define SH7750_MCR_RCD 0x00030000 /* DRAM: RAS-CAS Assertion Delay */ + /* time */ + /* SDRAM: bank active-read/write */ + /* command delay time */ +#define SH7750_MCR_RCD_DRAM_2 0x00000000 /* DRAM delay 2 clocks */ +#define SH7750_MCR_RCD_DRAM_3 0x00010000 /* DRAM delay 3 clocks */ +#define SH7750_MCR_RCD_DRAM_4 0x00020000 /* DRAM delay 4 clocks */ +#define SH7750_MCR_RCD_DRAM_5 0x00030000 /* DRAM delay 5 clocks */ +#define SH7750_MCR_RCD_SDRAM_2 0x00010000 /* DRAM delay 2 clocks */ +#define SH7750_MCR_RCD_SDRAM_3 0x00020000 /* DRAM delay 3 clocks */ +#define SH7750_MCR_RCD_SDRAM_4 0x00030000 /* DRAM delay 4 clocks */ + +#define SH7750_MCR_TRWL 0x0000E000 /* SDRAM Write Precharge Delay */ +#define SH7750_MCR_TRWL_1 0x00000000 /* 1 */ +#define SH7750_MCR_TRWL_2 0x00002000 /* 2 */ +#define SH7750_MCR_TRWL_3 0x00004000 /* 3 */ +#define SH7750_MCR_TRWL_4 0x00006000 /* 4 */ +#define SH7750_MCR_TRWL_5 0x00008000 /* 5 */ + +#define SH7750_MCR_TRAS 0x00001C00 /* DRAM: CAS-Before-RAS Refresh RAS */ + /* asserting period */ + /* SDRAM: Command interval after */ + /* synchronous DRAM refresh */ +#define SH7750_MCR_TRAS_DRAM_2 0x00000000 /* 2 */ +#define SH7750_MCR_TRAS_DRAM_3 0x00000400 /* 3 */ +#define SH7750_MCR_TRAS_DRAM_4 0x00000800 /* 4 */ +#define SH7750_MCR_TRAS_DRAM_5 0x00000C00 /* 5 */ +#define SH7750_MCR_TRAS_DRAM_6 0x00001000 /* 6 */ +#define SH7750_MCR_TRAS_DRAM_7 0x00001400 /* 7 */ +#define SH7750_MCR_TRAS_DRAM_8 0x00001800 /* 8 */ +#define SH7750_MCR_TRAS_DRAM_9 0x00001C00 /* 9 */ + +#define SH7750_MCR_TRAS_SDRAM_TRC_4 0x00000000 /* 4 + TRC */ +#define SH7750_MCR_TRAS_SDRAM_TRC_5 0x00000400 /* 5 + TRC */ +#define SH7750_MCR_TRAS_SDRAM_TRC_6 0x00000800 /* 6 + TRC */ +#define SH7750_MCR_TRAS_SDRAM_TRC_7 0x00000C00 /* 7 + TRC */ +#define SH7750_MCR_TRAS_SDRAM_TRC_8 0x00001000 /* 8 + TRC */ +#define SH7750_MCR_TRAS_SDRAM_TRC_9 0x00001400 /* 9 + TRC */ +#define SH7750_MCR_TRAS_SDRAM_TRC_10 0x00001800 /* 10 + TRC */ +#define SH7750_MCR_TRAS_SDRAM_TRC_11 0x00001C00 /* 11 + TRC */ + +#define SH7750_MCR_BE 0x00000200 /* Burst Enable */ +#define SH7750_MCR_SZ 0x00000180 /* Memory Data Size */ +#define SH7750_MCR_SZ_64 0x00000000 /* 64 bits */ +#define SH7750_MCR_SZ_16 0x00000100 /* 16 bits */ +#define SH7750_MCR_SZ_32 0x00000180 /* 32 bits */ + +#define SH7750_MCR_AMX 0x00000078 /* Address Multiplexing */ #define SH7750_MCR_AMX_S 3 -#define SH7750_MCR_AMX_DRAM_8BIT_COL 0x00000000 /* 8-bit column addr */ -#define SH7750_MCR_AMX_DRAM_9BIT_COL 0x00000008 /* 9-bit column addr */ -#define SH7750_MCR_AMX_DRAM_10BIT_COL 0x00000010 /* 10-bit column addr */ -#define SH7750_MCR_AMX_DRAM_11BIT_COL 0x00000018 /* 11-bit column addr */ -#define SH7750_MCR_AMX_DRAM_12BIT_COL 0x00000020 /* 12-bit column addr */ +#define SH7750_MCR_AMX_DRAM_8BIT_COL 0x00000000 /* 8-bit column addr */ +#define SH7750_MCR_AMX_DRAM_9BIT_COL 0x00000008 /* 9-bit column addr */ +#define SH7750_MCR_AMX_DRAM_10BIT_COL 0x00000010 /* 10-bit column addr */ +#define SH7750_MCR_AMX_DRAM_11BIT_COL 0x00000018 /* 11-bit column addr */ +#define SH7750_MCR_AMX_DRAM_12BIT_COL 0x00000020 /* 12-bit column addr */ /* See SH7750 Hardware Manual for SDRAM address multiplexor selection */ -#define SH7750_MCR_RFSH 0x00000004 /* Refresh Control */ -#define SH7750_MCR_RMODE 0x00000002 /* Refresh Mode: */ -#define SH7750_MCR_RMODE_NORMAL 0x00000000 /* Normal Refresh Mode */ -#define SH7750_MCR_RMODE_SELF 0x00000002 /* Self-Refresh Mode */ -#define SH7750_MCR_RMODE_EDO 0x00000001 /* EDO Mode */ +#define SH7750_MCR_RFSH 0x00000004 /* Refresh Control */ +#define SH7750_MCR_RMODE 0x00000002 /* Refresh Mode: */ +#define SH7750_MCR_RMODE_NORMAL 0x00000000 /* Normal Refresh Mode */ +#define SH7750_MCR_RMODE_SELF 0x00000002 /* Self-Refresh Mode */ +#define SH7750_MCR_RMODE_EDO 0x00000001 /* EDO Mode */ /* SDRAM Mode Set address */ #define SH7750_SDRAM_MODE_A2_BASE 0xFF900000 @@ -894,119 +894,119 @@ /* PCMCIA Control Register (half) - PCR */ -#define SH7750_PCR_REGOFS 0x800018 /* offset */ +#define SH7750_PCR_REGOFS 0x800018 /* offset */ #define SH7750_PCR SH7750_P4_REG32(SH7750_PCR_REGOFS) #define SH7750_PCR_A7 SH7750_A7_REG32(SH7750_PCR_REGOFS) -#define SH7750_PCR_A5PCW 0xC000 /* Area 5 PCMCIA Wait - Number of wait - states to be added to the number of - waits specified by WCR2 in a low-speed - PCMCIA wait cycle */ -#define SH7750_PCR_A5PCW_0 0x0000 /* 0 waits inserted */ -#define SH7750_PCR_A5PCW_15 0x4000 /* 15 waits inserted */ -#define SH7750_PCR_A5PCW_30 0x8000 /* 30 waits inserted */ -#define SH7750_PCR_A5PCW_50 0xC000 /* 50 waits inserted */ - -#define SH7750_PCR_A6PCW 0x3000 /* Area 6 PCMCIA Wait - Number of wait - states to be added to the number of - waits specified by WCR2 in a low-speed - PCMCIA wait cycle */ -#define SH7750_PCR_A6PCW_0 0x0000 /* 0 waits inserted */ -#define SH7750_PCR_A6PCW_15 0x1000 /* 15 waits inserted */ -#define SH7750_PCR_A6PCW_30 0x2000 /* 30 waits inserted */ -#define SH7750_PCR_A6PCW_50 0x3000 /* 50 waits inserted */ - -#define SH7750_PCR_A5TED 0x0E00 /* Area 5 Address-OE\/WE\ Assertion Delay, - delay time from address output to - OE\/WE\ assertion on the connected - PCMCIA interface */ +#define SH7750_PCR_A5PCW 0xC000 /* Area 5 PCMCIA Wait - Number of wait */ + /* states to be added to the number of */ + /* waits specified by WCR2 in a */ + /* low-speed PCMCIA wait cycle */ +#define SH7750_PCR_A5PCW_0 0x0000 /* 0 waits inserted */ +#define SH7750_PCR_A5PCW_15 0x4000 /* 15 waits inserted */ +#define SH7750_PCR_A5PCW_30 0x8000 /* 30 waits inserted */ +#define SH7750_PCR_A5PCW_50 0xC000 /* 50 waits inserted */ + +#define SH7750_PCR_A6PCW 0x3000 /* Area 6 PCMCIA Wait - Number of wait */ + /* states to be added to the number of */ + /* waits specified by WCR2 in a */ + /* low-speed PCMCIA wait cycle */ +#define SH7750_PCR_A6PCW_0 0x0000 /* 0 waits inserted */ +#define SH7750_PCR_A6PCW_15 0x1000 /* 15 waits inserted */ +#define SH7750_PCR_A6PCW_30 0x2000 /* 30 waits inserted */ +#define SH7750_PCR_A6PCW_50 0x3000 /* 50 waits inserted */ + +#define SH7750_PCR_A5TED 0x0E00 /* Area 5 Addr-OE\/WE\ Assertion Delay */ + /* delay time from address output to */ + /* OE\/WE\ assertion on the connected */ + /* PCMCIA interface */ #define SH7750_PCR_A5TED_S 9 -#define SH7750_PCR_A6TED 0x01C0 /* Area 6 Address-OE\/WE\ Assertion Delay */ +#define SH7750_PCR_A6TED 0x01C0 /* Area 6 Addr-OE\/WE\ Assertion Delay */ #define SH7750_PCR_A6TED_S 6 -#define SH7750_PCR_TED_0WS 0 /* 0 Waits inserted */ -#define SH7750_PCR_TED_1WS 1 /* 1 Waits inserted */ -#define SH7750_PCR_TED_2WS 2 /* 2 Waits inserted */ -#define SH7750_PCR_TED_3WS 3 /* 3 Waits inserted */ -#define SH7750_PCR_TED_6WS 4 /* 6 Waits inserted */ -#define SH7750_PCR_TED_9WS 5 /* 9 Waits inserted */ -#define SH7750_PCR_TED_12WS 6 /* 12 Waits inserted */ -#define SH7750_PCR_TED_15WS 7 /* 15 Waits inserted */ - -#define SH7750_PCR_A5TEH 0x0038 /* Area 5 OE\/WE\ Negation Address delay, - address hold delay time from OE\/WE\ - negation in a write on the connected - PCMCIA interface */ +#define SH7750_PCR_TED_0WS 0 /* 0 Waits inserted */ +#define SH7750_PCR_TED_1WS 1 /* 1 Waits inserted */ +#define SH7750_PCR_TED_2WS 2 /* 2 Waits inserted */ +#define SH7750_PCR_TED_3WS 3 /* 3 Waits inserted */ +#define SH7750_PCR_TED_6WS 4 /* 6 Waits inserted */ +#define SH7750_PCR_TED_9WS 5 /* 9 Waits inserted */ +#define SH7750_PCR_TED_12WS 6 /* 12 Waits inserted */ +#define SH7750_PCR_TED_15WS 7 /* 15 Waits inserted */ + +#define SH7750_PCR_A5TEH 0x0038 /* Area 5 OE\/WE\ Negation Addr delay, */ + /* address hold delay time from OE\/WE\ */ + /* negation in a write on the connected */ + /* PCMCIA interface */ #define SH7750_PCR_A5TEH_S 3 -#define SH7750_PCR_A6TEH 0x0007 /* Area 6 OE\/WE\ Negation Address delay */ +#define SH7750_PCR_A6TEH 0x0007 /* Area 6 OE\/WE\ Negation Address delay */ #define SH7750_PCR_A6TEH_S 0 -#define SH7750_PCR_TEH_0WS 0 /* 0 Waits inserted */ -#define SH7750_PCR_TEH_1WS 1 /* 1 Waits inserted */ -#define SH7750_PCR_TEH_2WS 2 /* 2 Waits inserted */ -#define SH7750_PCR_TEH_3WS 3 /* 3 Waits inserted */ -#define SH7750_PCR_TEH_6WS 4 /* 6 Waits inserted */ -#define SH7750_PCR_TEH_9WS 5 /* 9 Waits inserted */ -#define SH7750_PCR_TEH_12WS 6 /* 12 Waits inserted */ -#define SH7750_PCR_TEH_15WS 7 /* 15 Waits inserted */ +#define SH7750_PCR_TEH_0WS 0 /* 0 Waits inserted */ +#define SH7750_PCR_TEH_1WS 1 /* 1 Waits inserted */ +#define SH7750_PCR_TEH_2WS 2 /* 2 Waits inserted */ +#define SH7750_PCR_TEH_3WS 3 /* 3 Waits inserted */ +#define SH7750_PCR_TEH_6WS 4 /* 6 Waits inserted */ +#define SH7750_PCR_TEH_9WS 5 /* 9 Waits inserted */ +#define SH7750_PCR_TEH_12WS 6 /* 12 Waits inserted */ +#define SH7750_PCR_TEH_15WS 7 /* 15 Waits inserted */ /* Refresh Timer Control/Status Register (half) - RTSCR */ -#define SH7750_RTCSR_REGOFS 0x80001C /* offset */ +#define SH7750_RTCSR_REGOFS 0x80001C /* offset */ #define SH7750_RTCSR SH7750_P4_REG32(SH7750_RTCSR_REGOFS) #define SH7750_RTCSR_A7 SH7750_A7_REG32(SH7750_RTCSR_REGOFS) -#define SH7750_RTCSR_KEY 0xA500 /* RTCSR write key */ -#define SH7750_RTCSR_CMF 0x0080 /* Compare-Match Flag (indicates a - match between the refresh timer - counter and refresh time constant) */ -#define SH7750_RTCSR_CMIE 0x0040 /* Compare-Match Interrupt Enable */ -#define SH7750_RTCSR_CKS 0x0038 /* Refresh Counter Clock Selects */ -#define SH7750_RTCSR_CKS_DIS 0x0000 /* Clock Input Disabled */ -#define SH7750_RTCSR_CKS_CKIO_DIV4 0x0008 /* Bus Clock / 4 */ -#define SH7750_RTCSR_CKS_CKIO_DIV16 0x0010 /* Bus Clock / 16 */ -#define SH7750_RTCSR_CKS_CKIO_DIV64 0x0018 /* Bus Clock / 64 */ -#define SH7750_RTCSR_CKS_CKIO_DIV256 0x0020 /* Bus Clock / 256 */ -#define SH7750_RTCSR_CKS_CKIO_DIV1024 0x0028 /* Bus Clock / 1024 */ -#define SH7750_RTCSR_CKS_CKIO_DIV2048 0x0030 /* Bus Clock / 2048 */ -#define SH7750_RTCSR_CKS_CKIO_DIV4096 0x0038 /* Bus Clock / 4096 */ - -#define SH7750_RTCSR_OVF 0x0004 /* Refresh Count Overflow Flag */ -#define SH7750_RTCSR_OVIE 0x0002 /* Refresh Count Overflow Interrupt - Enable */ -#define SH7750_RTCSR_LMTS 0x0001 /* Refresh Count Overflow Limit Select */ -#define SH7750_RTCSR_LMTS_1024 0x0000 /* Count Limit is 1024 */ -#define SH7750_RTCSR_LMTS_512 0x0001 /* Count Limit is 512 */ +#define SH7750_RTCSR_KEY 0xA500 /* RTCSR write key */ +#define SH7750_RTCSR_CMF 0x0080 /* Compare-Match Flag (indicates a */ + /* match between the refresh timer */ + /* counter and refresh time constant) */ +#define SH7750_RTCSR_CMIE 0x0040 /* Compare-Match Interrupt Enable */ +#define SH7750_RTCSR_CKS 0x0038 /* Refresh Counter Clock Selects */ +#define SH7750_RTCSR_CKS_DIS 0x0000 /* Clock Input Disabled */ +#define SH7750_RTCSR_CKS_CKIO_DIV4 0x0008 /* Bus Clock / 4 */ +#define SH7750_RTCSR_CKS_CKIO_DIV16 0x0010 /* Bus Clock / 16 */ +#define SH7750_RTCSR_CKS_CKIO_DIV64 0x0018 /* Bus Clock / 64 */ +#define SH7750_RTCSR_CKS_CKIO_DIV256 0x0020 /* Bus Clock / 256 */ +#define SH7750_RTCSR_CKS_CKIO_DIV1024 0x0028 /* Bus Clock / 1024 */ +#define SH7750_RTCSR_CKS_CKIO_DIV2048 0x0030 /* Bus Clock / 2048 */ +#define SH7750_RTCSR_CKS_CKIO_DIV4096 0x0038 /* Bus Clock / 4096 */ + +#define SH7750_RTCSR_OVF 0x0004 /* Refresh Count Overflow Flag */ +#define SH7750_RTCSR_OVIE 0x0002 /* Refresh Count Overflow Interrupt */ + /* Enable */ +#define SH7750_RTCSR_LMTS 0x0001 /* Refresh Count Overflow Limit Select */ +#define SH7750_RTCSR_LMTS_1024 0x0000 /* Count Limit is 1024 */ +#define SH7750_RTCSR_LMTS_512 0x0001 /* Count Limit is 512 */ /* Refresh Timer Counter (half) - RTCNT */ -#define SH7750_RTCNT_REGOFS 0x800020 /* offset */ +#define SH7750_RTCNT_REGOFS 0x800020 /* offset */ #define SH7750_RTCNT SH7750_P4_REG32(SH7750_RTCNT_REGOFS) #define SH7750_RTCNT_A7 SH7750_A7_REG32(SH7750_RTCNT_REGOFS) -#define SH7750_RTCNT_KEY 0xA500 /* RTCNT write key */ +#define SH7750_RTCNT_KEY 0xA500 /* RTCNT write key */ /* Refresh Time Constant Register (half) - RTCOR */ -#define SH7750_RTCOR_REGOFS 0x800024 /* offset */ +#define SH7750_RTCOR_REGOFS 0x800024 /* offset */ #define SH7750_RTCOR SH7750_P4_REG32(SH7750_RTCOR_REGOFS) #define SH7750_RTCOR_A7 SH7750_A7_REG32(SH7750_RTCOR_REGOFS) -#define SH7750_RTCOR_KEY 0xA500 /* RTCOR write key */ +#define SH7750_RTCOR_KEY 0xA500 /* RTCOR write key */ /* Refresh Count Register (half) - RFCR */ -#define SH7750_RFCR_REGOFS 0x800028 /* offset */ +#define SH7750_RFCR_REGOFS 0x800028 /* offset */ #define SH7750_RFCR SH7750_P4_REG32(SH7750_RFCR_REGOFS) #define SH7750_RFCR_A7 SH7750_A7_REG32(SH7750_RFCR_REGOFS) -#define SH7750_RFCR_KEY 0xA400 /* RFCR write key */ +#define SH7750_RFCR_KEY 0xA400 /* RFCR write key */ /* Synchronous DRAM mode registers - SDMR */ -#define SH7750_SDMR2_REGOFS 0x900000 /* base offset */ -#define SH7750_SDMR2_REGNB 0x0FFC /* nb of register */ +#define SH7750_SDMR2_REGOFS 0x900000 /* base offset */ +#define SH7750_SDMR2_REGNB 0x0FFC /* nb of register */ #define SH7750_SDMR2 SH7750_P4_REG32(SH7750_SDMR2_REGOFS) #define SH7750_SDMR2_A7 SH7750_A7_REG32(SH7750_SDMR2_REGOFS) -#define SH7750_SDMR3_REGOFS 0x940000 /* offset */ -#define SH7750_SDMR3_REGNB 0x0FFC /* nb of register */ +#define SH7750_SDMR3_REGOFS 0x940000 /* offset */ +#define SH7750_SDMR3_REGNB 0x0FFC /* nb of register */ #define SH7750_SDMR3 SH7750_P4_REG32(SH7750_SDMR3_REGOFS) #define SH7750_SDMR3_A7 SH7750_A7_REG32(SH7750_SDMR3_REGOFS) @@ -1015,7 +1015,7 @@ */ /* DMA Source Address Register - SAR0, SAR1, SAR2, SAR3 */ -#define SH7750_SAR_REGOFS(n) (0xA00000 + ((n)*16)) /* offset */ +#define SH7750_SAR_REGOFS(n) (0xA00000 + ((n) * 16)) /* offset */ #define SH7750_SAR(n) SH7750_P4_REG32(SH7750_SAR_REGOFS(n)) #define SH7750_SAR_A7(n) SH7750_A7_REG32(SH7750_SAR_REGOFS(n)) #define SH7750_SAR0 SH7750_SAR(0) @@ -1028,7 +1028,7 @@ #define SH7750_SAR3_A7 SH7750_SAR_A7(3) /* DMA Destination Address Register - DAR0, DAR1, DAR2, DAR3 */ -#define SH7750_DAR_REGOFS(n) (0xA00004 + ((n)*16)) /* offset */ +#define SH7750_DAR_REGOFS(n) (0xA00004 + ((n) * 16)) /* offset */ #define SH7750_DAR(n) SH7750_P4_REG32(SH7750_DAR_REGOFS(n)) #define SH7750_DAR_A7(n) SH7750_A7_REG32(SH7750_DAR_REGOFS(n)) #define SH7750_DAR0 SH7750_DAR(0) @@ -1041,7 +1041,7 @@ #define SH7750_DAR3_A7 SH7750_DAR_A7(3) /* DMA Transfer Count Register - DMATCR0, DMATCR1, DMATCR2, DMATCR3 */ -#define SH7750_DMATCR_REGOFS(n) (0xA00008 + ((n)*16)) /* offset */ +#define SH7750_DMATCR_REGOFS(n) (0xA00008 + ((n) * 16)) /* offset */ #define SH7750_DMATCR(n) SH7750_P4_REG32(SH7750_DMATCR_REGOFS(n)) #define SH7750_DMATCR_A7(n) SH7750_A7_REG32(SH7750_DMATCR_REGOFS(n)) #define SH7750_DMATCR0_P4 SH7750_DMATCR(0) @@ -1054,7 +1054,7 @@ #define SH7750_DMATCR3_A7 SH7750_DMATCR_A7(3) /* DMA Channel Control Register - CHCR0, CHCR1, CHCR2, CHCR3 */ -#define SH7750_CHCR_REGOFS(n) (0xA0000C + ((n)*16)) /* offset */ +#define SH7750_CHCR_REGOFS(n) (0xA0000C + ((n) * 16)) /* offset */ #define SH7750_CHCR(n) SH7750_P4_REG32(SH7750_CHCR_REGOFS(n)) #define SH7750_CHCR_A7(n) SH7750_A7_REG32(SH7750_CHCR_REGOFS(n)) #define SH7750_CHCR0 SH7750_CHCR(0) @@ -1066,227 +1066,227 @@ #define SH7750_CHCR2_A7 SH7750_CHCR_A7(2) #define SH7750_CHCR3_A7 SH7750_CHCR_A7(3) -#define SH7750_CHCR_SSA 0xE0000000 /* Source Address Space Attribute */ -#define SH7750_CHCR_SSA_PCMCIA 0x00000000 /* Reserved in PCMCIA access */ -#define SH7750_CHCR_SSA_DYNBSZ 0x20000000 /* Dynamic Bus Sizing I/O space */ -#define SH7750_CHCR_SSA_IO8 0x40000000 /* 8-bit I/O space */ -#define SH7750_CHCR_SSA_IO16 0x60000000 /* 16-bit I/O space */ -#define SH7750_CHCR_SSA_CMEM8 0x80000000 /* 8-bit common memory space */ -#define SH7750_CHCR_SSA_CMEM16 0xA0000000 /* 16-bit common memory space */ -#define SH7750_CHCR_SSA_AMEM8 0xC0000000 /* 8-bit attribute memory space */ -#define SH7750_CHCR_SSA_AMEM16 0xE0000000 /* 16-bit attribute memory space */ - -#define SH7750_CHCR_STC 0x10000000 /* Source Address Wait Control Select, - specifies CS5 or CS6 space wait - control for PCMCIA access */ - -#define SH7750_CHCR_DSA 0x0E000000 /* Source Address Space Attribute */ -#define SH7750_CHCR_DSA_PCMCIA 0x00000000 /* Reserved in PCMCIA access */ -#define SH7750_CHCR_DSA_DYNBSZ 0x02000000 /* Dynamic Bus Sizing I/O space */ -#define SH7750_CHCR_DSA_IO8 0x04000000 /* 8-bit I/O space */ -#define SH7750_CHCR_DSA_IO16 0x06000000 /* 16-bit I/O space */ -#define SH7750_CHCR_DSA_CMEM8 0x08000000 /* 8-bit common memory space */ -#define SH7750_CHCR_DSA_CMEM16 0x0A000000 /* 16-bit common memory space */ -#define SH7750_CHCR_DSA_AMEM8 0x0C000000 /* 8-bit attribute memory space */ -#define SH7750_CHCR_DSA_AMEM16 0x0E000000 /* 16-bit attribute memory space */ - -#define SH7750_CHCR_DTC 0x01000000 /* Destination Address Wait Control - Select, specifies CS5 or CS6 - space wait control for PCMCIA - access */ - -#define SH7750_CHCR_DS 0x00080000 /* DREQ\ Select : */ -#define SH7750_CHCR_DS_LOWLVL 0x00000000 /* Low Level Detection */ -#define SH7750_CHCR_DS_FALL 0x00080000 /* Falling Edge Detection */ - -#define SH7750_CHCR_RL 0x00040000 /* Request Check Level: */ -#define SH7750_CHCR_RL_ACTH 0x00000000 /* DRAK is an active high out */ -#define SH7750_CHCR_RL_ACTL 0x00040000 /* DRAK is an active low out */ - -#define SH7750_CHCR_AM 0x00020000 /* Acknowledge Mode: */ -#define SH7750_CHCR_AM_RD 0x00000000 /* DACK is output in read cycle */ -#define SH7750_CHCR_AM_WR 0x00020000 /* DACK is output in write cycle */ - -#define SH7750_CHCR_AL 0x00010000 /* Acknowledge Level: */ -#define SH7750_CHCR_AL_ACTH 0x00000000 /* DACK is an active high out */ -#define SH7750_CHCR_AL_ACTL 0x00010000 /* DACK is an active low out */ - -#define SH7750_CHCR_DM 0x0000C000 /* Destination Address Mode: */ -#define SH7750_CHCR_DM_FIX 0x00000000 /* Destination Addr Fixed */ -#define SH7750_CHCR_DM_INC 0x00004000 /* Destination Addr Incremented */ -#define SH7750_CHCR_DM_DEC 0x00008000 /* Destination Addr Decremented */ - -#define SH7750_CHCR_SM 0x00003000 /* Source Address Mode: */ -#define SH7750_CHCR_SM_FIX 0x00000000 /* Source Addr Fixed */ -#define SH7750_CHCR_SM_INC 0x00001000 /* Source Addr Incremented */ -#define SH7750_CHCR_SM_DEC 0x00002000 /* Source Addr Decremented */ - -#define SH7750_CHCR_RS 0x00000F00 /* Request Source Select: */ -#define SH7750_CHCR_RS_ER_DA_EA_TO_EA 0x000 /* External Request, Dual Address - Mode (External Addr Space-> - External Addr Space) */ -#define SH7750_CHCR_RS_ER_SA_EA_TO_ED 0x200 /* External Request, Single - Address Mode (External Addr - Space -> External Device) */ -#define SH7750_CHCR_RS_ER_SA_ED_TO_EA 0x300 /* External Request, Single - Address Mode, (External - Device -> External Addr - Space) */ -#define SH7750_CHCR_RS_AR_EA_TO_EA 0x400 /* Auto-Request (External Addr - Space -> External Addr Space) */ - -#define SH7750_CHCR_RS_AR_EA_TO_OCP 0x500 /* Auto-Request (External Addr - Space -> On-chip Peripheral - Module) */ -#define SH7750_CHCR_RS_AR_OCP_TO_EA 0x600 /* Auto-Request (On-chip - Peripheral Module -> - External Addr Space */ -#define SH7750_CHCR_RS_SCITX_EA_TO_SC 0x800 /* SCI Transmit-Data-Empty intr - transfer request (external - address space -> SCTDR1) */ -#define SH7750_CHCR_RS_SCIRX_SC_TO_EA 0x900 /* SCI Receive-Data-Full intr - transfer request (SCRDR1 -> - External Addr Space) */ -#define SH7750_CHCR_RS_SCIFTX_EA_TO_SC 0xA00 /* SCIF Transmit-Data-Empty intr - transfer request (external - address space -> SCFTDR1) */ -#define SH7750_CHCR_RS_SCIFRX_SC_TO_EA 0xB00 /* SCIF Receive-Data-Full intr - transfer request (SCFRDR2 -> - External Addr Space) */ -#define SH7750_CHCR_RS_TMU2_EA_TO_EA 0xC00 /* TMU Channel 2 (input capture - interrupt), (external address - space -> external address - space) */ -#define SH7750_CHCR_RS_TMU2_EA_TO_OCP 0xD00 /* TMU Channel 2 (input capture - interrupt), (external address - space -> on-chip peripheral - module) */ -#define SH7750_CHCR_RS_TMU2_OCP_TO_EA 0xE00 /* TMU Channel 2 (input capture - interrupt), (on-chip - peripheral module -> external - address space) */ - -#define SH7750_CHCR_TM 0x00000080 /* Transmit mode: */ -#define SH7750_CHCR_TM_CSTEAL 0x00000000 /* Cycle Steal Mode */ -#define SH7750_CHCR_TM_BURST 0x00000080 /* Burst Mode */ - -#define SH7750_CHCR_TS 0x00000070 /* Transmit Size: */ -#define SH7750_CHCR_TS_QUAD 0x00000000 /* Quadword Size (64 bits) */ -#define SH7750_CHCR_TS_BYTE 0x00000010 /* Byte Size (8 bit) */ -#define SH7750_CHCR_TS_WORD 0x00000020 /* Word Size (16 bit) */ -#define SH7750_CHCR_TS_LONG 0x00000030 /* Longword Size (32 bit) */ -#define SH7750_CHCR_TS_BLOCK 0x00000040 /* 32-byte block transfer */ - -#define SH7750_CHCR_IE 0x00000004 /* Interrupt Enable */ -#define SH7750_CHCR_TE 0x00000002 /* Transfer End */ -#define SH7750_CHCR_DE 0x00000001 /* DMAC Enable */ +#define SH7750_CHCR_SSA 0xE0000000 /* Source Address Space Attribute */ +#define SH7750_CHCR_SSA_PCMCIA 0x00000000 /* Reserved in PCMCIA access */ +#define SH7750_CHCR_SSA_DYNBSZ 0x20000000 /* Dynamic Bus Sizing I/O space */ +#define SH7750_CHCR_SSA_IO8 0x40000000 /* 8-bit I/O space */ +#define SH7750_CHCR_SSA_IO16 0x60000000 /* 16-bit I/O space */ +#define SH7750_CHCR_SSA_CMEM8 0x80000000 /* 8-bit common memory space */ +#define SH7750_CHCR_SSA_CMEM16 0xA0000000 /* 16-bit common memory space */ +#define SH7750_CHCR_SSA_AMEM8 0xC0000000 /* 8-bit attribute memory space */ +#define SH7750_CHCR_SSA_AMEM16 0xE0000000 /* 16-bit attribute memory space */ + +#define SH7750_CHCR_STC 0x10000000 /* Source Addr Wait Control Select */ + /* specifies CS5 or CS6 space wait */ + /* control for PCMCIA access */ + +#define SH7750_CHCR_DSA 0x0E000000 /* Source Address Space Attribute */ +#define SH7750_CHCR_DSA_PCMCIA 0x00000000 /* Reserved in PCMCIA access */ +#define SH7750_CHCR_DSA_DYNBSZ 0x02000000 /* Dynamic Bus Sizing I/O space */ +#define SH7750_CHCR_DSA_IO8 0x04000000 /* 8-bit I/O space */ +#define SH7750_CHCR_DSA_IO16 0x06000000 /* 16-bit I/O space */ +#define SH7750_CHCR_DSA_CMEM8 0x08000000 /* 8-bit common memory space */ +#define SH7750_CHCR_DSA_CMEM16 0x0A000000 /* 16-bit common memory space */ +#define SH7750_CHCR_DSA_AMEM8 0x0C000000 /* 8-bit attribute memory space */ +#define SH7750_CHCR_DSA_AMEM16 0x0E000000 /* 16-bit attribute memory space */ + +#define SH7750_CHCR_DTC 0x01000000 /* Destination Address Wait Control */ + /* Select, specifies CS5 or CS6 */ + /* space wait control for PCMCIA */ + /* access */ + +#define SH7750_CHCR_DS 0x00080000 /* DREQ\ Select : */ +#define SH7750_CHCR_DS_LOWLVL 0x00000000 /* Low Level Detection */ +#define SH7750_CHCR_DS_FALL 0x00080000 /* Falling Edge Detection */ + +#define SH7750_CHCR_RL 0x00040000 /* Request Check Level: */ +#define SH7750_CHCR_RL_ACTH 0x00000000 /* DRAK is an active high out */ +#define SH7750_CHCR_RL_ACTL 0x00040000 /* DRAK is an active low out */ + +#define SH7750_CHCR_AM 0x00020000 /* Acknowledge Mode: */ +#define SH7750_CHCR_AM_RD 0x00000000 /* DACK is output in read cycle */ +#define SH7750_CHCR_AM_WR 0x00020000 /* DACK is output in write cycle */ + +#define SH7750_CHCR_AL 0x00010000 /* Acknowledge Level: */ +#define SH7750_CHCR_AL_ACTH 0x00000000 /* DACK is an active high out */ +#define SH7750_CHCR_AL_ACTL 0x00010000 /* DACK is an active low out */ + +#define SH7750_CHCR_DM 0x0000C000 /* Destination Address Mode: */ +#define SH7750_CHCR_DM_FIX 0x00000000 /* Destination Addr Fixed */ +#define SH7750_CHCR_DM_INC 0x00004000 /* Destination Addr Incremented */ +#define SH7750_CHCR_DM_DEC 0x00008000 /* Destination Addr Decremented */ + +#define SH7750_CHCR_SM 0x00003000 /* Source Address Mode: */ +#define SH7750_CHCR_SM_FIX 0x00000000 /* Source Addr Fixed */ +#define SH7750_CHCR_SM_INC 0x00001000 /* Source Addr Incremented */ +#define SH7750_CHCR_SM_DEC 0x00002000 /* Source Addr Decremented */ + +#define SH7750_CHCR_RS 0x00000F00 /* Request Source Select: */ +#define SH7750_CHCR_RS_ER_DA_EA_TO_EA 0x000 /* External Request, Dual Addr */ + /* Mode, External Addr Space */ + /* -> External Addr Space) */ +#define SH7750_CHCR_RS_ER_SA_EA_TO_ED 0x200 /* External Request, Single */ + /* Address Mode (Ext. Addr */ + /* Space -> External Device) */ +#define SH7750_CHCR_RS_ER_SA_ED_TO_EA 0x300 /* External Request, Single */ + /* Address Mode, (External */ + /* Device -> External Addr */ + /* Space) */ +#define SH7750_CHCR_RS_AR_EA_TO_EA 0x400 /* Auto-Request (External Addr */ + /* Space -> Ext. Addr Space) */ + +#define SH7750_CHCR_RS_AR_EA_TO_OCP 0x500 /* Auto-Request (External Addr */ + /* Space -> On-chip */ + /* Peripheral Module) */ +#define SH7750_CHCR_RS_AR_OCP_TO_EA 0x600 /* Auto-Request (On-chip */ + /* Peripheral Module -> */ + /* External Addr Space */ +#define SH7750_CHCR_RS_SCITX_EA_TO_SC 0x800 /* SCI Transmit-Data-Empty intr */ + /* transfer request (external */ + /* address space -> SCTDR1) */ +#define SH7750_CHCR_RS_SCIRX_SC_TO_EA 0x900 /* SCI Receive-Data-Full intr */ + /* transfer request (SCRDR1 */ + /* -> External Addr Space) */ +#define SH7750_CHCR_RS_SCIFTX_EA_TO_SC 0xA00 /* SCIF TX-Data-Empty intr */ + /* transfer request (external */ + /* address space -> SCFTDR1) */ +#define SH7750_CHCR_RS_SCIFRX_SC_TO_EA 0xB00 /* SCIF Receive-Data-Full intr */ + /* transfer request (SCFRDR2 */ + /* -> External Addr Space) */ +#define SH7750_CHCR_RS_TMU2_EA_TO_EA 0xC00 /* TMU Channel 2 (input capture */ + /* interrupt), (external */ + /* address space -> external */ + /* address space) */ +#define SH7750_CHCR_RS_TMU2_EA_TO_OCP 0xD00 /* TMU Channel 2 (input capture */ + /* interrupt), (external */ + /* address space -> on-chip */ + /* peripheral module) */ +#define SH7750_CHCR_RS_TMU2_OCP_TO_EA 0xE00 /* TMU Channel 2 (input capture */ + /* interrupt), (on-chip */ + /* peripheral module -> */ + /* external address space) */ + +#define SH7750_CHCR_TM 0x00000080 /* Transmit mode: */ +#define SH7750_CHCR_TM_CSTEAL 0x00000000 /* Cycle Steal Mode */ +#define SH7750_CHCR_TM_BURST 0x00000080 /* Burst Mode */ + +#define SH7750_CHCR_TS 0x00000070 /* Transmit Size: */ +#define SH7750_CHCR_TS_QUAD 0x00000000 /* Quadword Size (64 bits) */ +#define SH7750_CHCR_TS_BYTE 0x00000010 /* Byte Size (8 bit) */ +#define SH7750_CHCR_TS_WORD 0x00000020 /* Word Size (16 bit) */ +#define SH7750_CHCR_TS_LONG 0x00000030 /* Longword Size (32 bit) */ +#define SH7750_CHCR_TS_BLOCK 0x00000040 /* 32-byte block transfer */ + +#define SH7750_CHCR_IE 0x00000004 /* Interrupt Enable */ +#define SH7750_CHCR_TE 0x00000002 /* Transfer End */ +#define SH7750_CHCR_DE 0x00000001 /* DMAC Enable */ /* DMA Operation Register - DMAOR */ -#define SH7750_DMAOR_REGOFS 0xA00040 /* offset */ +#define SH7750_DMAOR_REGOFS 0xA00040 /* offset */ #define SH7750_DMAOR SH7750_P4_REG32(SH7750_DMAOR_REGOFS) #define SH7750_DMAOR_A7 SH7750_A7_REG32(SH7750_DMAOR_REGOFS) -#define SH7750_DMAOR_DDT 0x00008000 /* On-Demand Data Transfer Mode */ +#define SH7750_DMAOR_DDT 0x00008000 /* On-Demand Data Transfer Mode */ -#define SH7750_DMAOR_PR 0x00000300 /* Priority Mode: */ -#define SH7750_DMAOR_PR_0123 0x00000000 /* CH0 > CH1 > CH2 > CH3 */ -#define SH7750_DMAOR_PR_0231 0x00000100 /* CH0 > CH2 > CH3 > CH1 */ -#define SH7750_DMAOR_PR_2013 0x00000200 /* CH2 > CH0 > CH1 > CH3 */ -#define SH7750_DMAOR_PR_RR 0x00000300 /* Round-robin mode */ +#define SH7750_DMAOR_PR 0x00000300 /* Priority Mode: */ +#define SH7750_DMAOR_PR_0123 0x00000000 /* CH0 > CH1 > CH2 > CH3 */ +#define SH7750_DMAOR_PR_0231 0x00000100 /* CH0 > CH2 > CH3 > CH1 */ +#define SH7750_DMAOR_PR_2013 0x00000200 /* CH2 > CH0 > CH1 > CH3 */ +#define SH7750_DMAOR_PR_RR 0x00000300 /* Round-robin mode */ -#define SH7750_DMAOR_COD 0x00000010 /* Check Overrun for DREQ\ */ -#define SH7750_DMAOR_AE 0x00000004 /* Address Error flag */ -#define SH7750_DMAOR_NMIF 0x00000002 /* NMI Flag */ -#define SH7750_DMAOR_DME 0x00000001 /* DMAC Master Enable */ +#define SH7750_DMAOR_COD 0x00000010 /* Check Overrun for DREQ\ */ +#define SH7750_DMAOR_AE 0x00000004 /* Address Error flag */ +#define SH7750_DMAOR_NMIF 0x00000002 /* NMI Flag */ +#define SH7750_DMAOR_DME 0x00000001 /* DMAC Master Enable */ /* * I/O Ports */ /* Port Control Register A - PCTRA */ -#define SH7750_PCTRA_REGOFS 0x80002C /* offset */ +#define SH7750_PCTRA_REGOFS 0x80002C /* offset */ #define SH7750_PCTRA SH7750_P4_REG32(SH7750_PCTRA_REGOFS) #define SH7750_PCTRA_A7 SH7750_A7_REG32(SH7750_PCTRA_REGOFS) -#define SH7750_PCTRA_PBPUP(n) 0 /* Bit n is pulled up */ -#define SH7750_PCTRA_PBNPUP(n) (1 << ((n)*2+1)) /* Bit n is not pulled up */ -#define SH7750_PCTRA_PBINP(n) 0 /* Bit n is an input */ -#define SH7750_PCTRA_PBOUT(n) (1 << ((n)*2)) /* Bit n is an output */ +#define SH7750_PCTRA_PBPUP(n) 0 /* Bit n is pulled up */ +#define SH7750_PCTRA_PBNPUP(n) (1 << ((n) * 2 + 1)) /* Bit n is not pulled up */ +#define SH7750_PCTRA_PBINP(n) 0 /* Bit n is an input */ +#define SH7750_PCTRA_PBOUT(n) (1 << ((n) * 2)) /* Bit n is an output */ /* Port Data Register A - PDTRA(half) */ -#define SH7750_PDTRA_REGOFS 0x800030 /* offset */ +#define SH7750_PDTRA_REGOFS 0x800030 /* offset */ #define SH7750_PDTRA SH7750_P4_REG32(SH7750_PDTRA_REGOFS) #define SH7750_PDTRA_A7 SH7750_A7_REG32(SH7750_PDTRA_REGOFS) #define SH7750_PDTRA_BIT(n) (1 << (n)) /* Port Control Register B - PCTRB */ -#define SH7750_PCTRB_REGOFS 0x800040 /* offset */ +#define SH7750_PCTRB_REGOFS 0x800040 /* offset */ #define SH7750_PCTRB SH7750_P4_REG32(SH7750_PCTRB_REGOFS) #define SH7750_PCTRB_A7 SH7750_A7_REG32(SH7750_PCTRB_REGOFS) -#define SH7750_PCTRB_PBPUP(n) 0 /* Bit n is pulled up */ -#define SH7750_PCTRB_PBNPUP(n) (1 << ((n-16)*2+1)) /* Bit n is not pulled up */ -#define SH7750_PCTRB_PBINP(n) 0 /* Bit n is an input */ -#define SH7750_PCTRB_PBOUT(n) (1 << ((n-16)*2)) /* Bit n is an output */ +#define SH7750_PCTRB_PBPUP(n) 0 /* Bit n is pulled up */ +#define SH7750_PCTRB_PBNPUP(n) (1 << ((n - 16) * 2 + 1)) /* Bit n is not pulled up */ +#define SH7750_PCTRB_PBINP(n) 0 /* Bit n is an input */ +#define SH7750_PCTRB_PBOUT(n) (1 << ((n - 16) * 2)) /* Bit n is an output */ /* Port Data Register B - PDTRB(half) */ -#define SH7750_PDTRB_REGOFS 0x800044 /* offset */ +#define SH7750_PDTRB_REGOFS 0x800044 /* offset */ #define SH7750_PDTRB SH7750_P4_REG32(SH7750_PDTRB_REGOFS) #define SH7750_PDTRB_A7 SH7750_A7_REG32(SH7750_PDTRB_REGOFS) -#define SH7750_PDTRB_BIT(n) (1 << ((n)-16)) +#define SH7750_PDTRB_BIT(n) (1 << ((n) - 16)) /* GPIO Interrupt Control Register - GPIOIC(half) */ -#define SH7750_GPIOIC_REGOFS 0x800048 /* offset */ +#define SH7750_GPIOIC_REGOFS 0x800048 /* offset */ #define SH7750_GPIOIC SH7750_P4_REG32(SH7750_GPIOIC_REGOFS) #define SH7750_GPIOIC_A7 SH7750_A7_REG32(SH7750_GPIOIC_REGOFS) -#define SH7750_GPIOIC_PTIREN(n) (1 << (n)) /* Port n is used as a GPIO int */ +#define SH7750_GPIOIC_PTIREN(n) (1 << (n)) /* Port n is used as a GPIO int */ /* * Interrupt Controller - INTC */ /* Interrupt Control Register - ICR (half) */ -#define SH7750_ICR_REGOFS 0xD00000 /* offset */ +#define SH7750_ICR_REGOFS 0xD00000 /* offset */ #define SH7750_ICR SH7750_P4_REG32(SH7750_ICR_REGOFS) #define SH7750_ICR_A7 SH7750_A7_REG32(SH7750_ICR_REGOFS) -#define SH7750_ICR_NMIL 0x8000 /* NMI Input Level */ -#define SH7750_ICR_MAI 0x4000 /* NMI Interrupt Mask */ +#define SH7750_ICR_NMIL 0x8000 /* NMI Input Level */ +#define SH7750_ICR_MAI 0x4000 /* NMI Interrupt Mask */ -#define SH7750_ICR_NMIB 0x0200 /* NMI Block Mode: */ -#define SH7750_ICR_NMIB_BLK 0x0000 /* NMI requests held pending while - SR.BL bit is set to 1 */ -#define SH7750_ICR_NMIB_NBLK 0x0200 /* NMI requests detected when SR.BL bit - set to 1 */ +#define SH7750_ICR_NMIB 0x0200 /* NMI Block Mode: */ +#define SH7750_ICR_NMIB_BLK 0x0000 /* NMI requests held pending while */ + /* SR.BL bit is set to 1 */ +#define SH7750_ICR_NMIB_NBLK 0x0200 /* NMI requests detected when SR.BL */ + /* bit set to 1 */ -#define SH7750_ICR_NMIE 0x0100 /* NMI Edge Select: */ -#define SH7750_ICR_NMIE_FALL 0x0000 /* Interrupt request detected on falling - edge of NMI input */ -#define SH7750_ICR_NMIE_RISE 0x0100 /* Interrupt request detected on rising - edge of NMI input */ +#define SH7750_ICR_NMIE 0x0100 /* NMI Edge Select: */ +#define SH7750_ICR_NMIE_FALL 0x0000 /* Interrupt request detected on */ + /* falling edge of NMI input */ +#define SH7750_ICR_NMIE_RISE 0x0100 /* Interrupt request detected on */ + /* rising edge of NMI input */ -#define SH7750_ICR_IRLM 0x0080 /* IRL Pin Mode: */ -#define SH7750_ICR_IRLM_ENC 0x0000 /* IRL\ pins used as a level-encoded - interrupt requests */ -#define SH7750_ICR_IRLM_RAW 0x0080 /* IRL\ pins used as a four independent - interrupt requests */ +#define SH7750_ICR_IRLM 0x0080 /* IRL Pin Mode: */ +#define SH7750_ICR_IRLM_ENC 0x0000 /* IRL\ pins used as a level-encoded */ + /* interrupt requests */ +#define SH7750_ICR_IRLM_RAW 0x0080 /* IRL\ pins used as a four */ + /* independent interrupt requests */ /* * User Break Controller registers */ -#define SH7750_BARA 0x200000 /* Break address regiser A */ -#define SH7750_BAMRA 0x200004 /* Break address mask regiser A */ -#define SH7750_BBRA 0x200008 /* Break bus cycle regiser A */ -#define SH7750_BARB 0x20000c /* Break address regiser B */ -#define SH7750_BAMRB 0x200010 /* Break address mask regiser B */ -#define SH7750_BBRB 0x200014 /* Break bus cycle regiser B */ -#define SH7750_BASRB 0x000018 /* Break ASID regiser B */ -#define SH7750_BDRB 0x200018 /* Break data regiser B */ -#define SH7750_BDMRB 0x20001c /* Break data mask regiser B */ -#define SH7750_BRCR 0x200020 /* Break control register */ - -#define SH7750_BRCR_UDBE 0x0001 /* User break debug enable bit */ +#define SH7750_BARA 0x200000 /* Break address regiser A */ +#define SH7750_BAMRA 0x200004 /* Break address mask regiser A */ +#define SH7750_BBRA 0x200008 /* Break bus cycle regiser A */ +#define SH7750_BARB 0x20000c /* Break address regiser B */ +#define SH7750_BAMRB 0x200010 /* Break address mask regiser B */ +#define SH7750_BBRB 0x200014 /* Break bus cycle regiser B */ +#define SH7750_BASRB 0x000018 /* Break ASID regiser B */ +#define SH7750_BDRB 0x200018 /* Break data regiser B */ +#define SH7750_BDMRB 0x20001c /* Break data mask regiser B */ +#define SH7750_BRCR 0x200020 /* Break control register */ + +#define SH7750_BRCR_UDBE 0x0001 /* User break debug enable bit */ /* * Missing in RTEMS, added for QEMU diff --git a/hw/sh4/shix.c b/hw/sh4/shix.c index b0579aa0f1..aa812512f0 100644 --- a/hw/sh4/shix.c +++ b/hw/sh4/shix.c @@ -22,11 +22,11 @@ * THE SOFTWARE. */ /* - Shix 2.0 board by Alexis Polti, described at - https://web.archive.org/web/20070917001736/perso.enst.fr/~polti/realisations/shix20 - - More information in target/sh4/README.sh4 -*/ + * Shix 2.0 board by Alexis Polti, described at + * https://web.archive.org/web/20070917001736/perso.enst.fr/~polti/realisations/shix20 + * + * More information in target/sh4/README.sh4 + */ #include "qemu/osdep.h" #include "qapi/error.h" #include "cpu.h" @@ -48,7 +48,7 @@ static void shix_init(MachineState *machine) MemoryRegion *rom = g_new(MemoryRegion, 1); MemoryRegion *sdram = g_new(MemoryRegion, 2); const char *bios_name = machine->firmware ?: BIOS_FILENAME; - + cpu = SUPERH_CPU(cpu_create(machine->cpu_type)); /* Allocate memory space */ diff --git a/hw/sh4/trace-events b/hw/sh4/trace-events new file mode 100644 index 0000000000..4b61cd56c8 --- /dev/null +++ b/hw/sh4/trace-events @@ -0,0 +1,3 @@ +# sh7750.c +sh7750_porta(uint16_t prev, uint16_t cur, uint16_t pdtr, uint16_t pctr) "porta changed from 0x%04x to 0x%04x\npdtra=0x%04x, pctra=0x%08x" +sh7750_portb(uint16_t prev, uint16_t cur, uint16_t pdtr, uint16_t pctr) "portb changed from 0x%04x to 0x%04x\npdtrb=0x%04x, pctrb=0x%08x" diff --git a/hw/sh4/trace.h b/hw/sh4/trace.h new file mode 100644 index 0000000000..e2c13323b7 --- /dev/null +++ b/hw/sh4/trace.h @@ -0,0 +1 @@ +#include "trace/trace-hw_sh4.h" diff --git a/hw/timer/sh_timer.c b/hw/timer/sh_timer.c index 58af1a1edb..c72c327bfa 100644 --- a/hw/timer/sh_timer.c +++ b/hw/timer/sh_timer.c @@ -10,13 +10,12 @@ #include "qemu/osdep.h" #include "exec/memory.h" -#include "hw/hw.h" +#include "qemu/log.h" #include "hw/irq.h" #include "hw/sh4/sh.h" #include "hw/timer/tmu012.h" #include "hw/ptimer.h" - -//#define DEBUG_TIMER +#include "trace.h" #define TIMER_TCR_TPSC (7 << 0) #define TIMER_TCR_CKEG (3 << 3) @@ -46,24 +45,24 @@ typedef struct { int feat; int enabled; qemu_irq irq; -} sh_timer_state; +} SHTimerState; /* Check all active timers, and schedule the next timer interrupt. */ -static void sh_timer_update(sh_timer_state *s) +static void sh_timer_update(SHTimerState *s) { int new_level = s->int_level && (s->tcr & TIMER_TCR_UNIE); - if (new_level != s->old_level) - qemu_set_irq (s->irq, new_level); - + if (new_level != s->old_level) { + qemu_set_irq(s->irq, new_level); + } s->old_level = s->int_level; s->int_level = new_level; } static uint32_t sh_timer_read(void *opaque, hwaddr offset) { - sh_timer_state *s = (sh_timer_state *)opaque; + SHTimerState *s = opaque; switch (offset >> 2) { case OFFSET_TCOR: @@ -73,19 +72,18 @@ static uint32_t sh_timer_read(void *opaque, hwaddr offset) case OFFSET_TCR: return s->tcr | (s->int_level ? TIMER_TCR_UNF : 0); case OFFSET_TCPR: - if (s->feat & TIMER_FEAT_CAPT) + if (s->feat & TIMER_FEAT_CAPT) { return s->tcpr; - /* fall through */ - default: - hw_error("sh_timer_read: Bad offset %x\n", (int)offset); - return 0; + } } + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + return 0; } -static void sh_timer_write(void *opaque, hwaddr offset, - uint32_t value) +static void sh_timer_write(void *opaque, hwaddr offset, uint32_t value) { - sh_timer_state *s = (sh_timer_state *)opaque; + SHTimerState *s = opaque; int freq; switch (offset >> 2) { @@ -104,19 +102,30 @@ static void sh_timer_write(void *opaque, hwaddr offset, case OFFSET_TCR: ptimer_transaction_begin(s->timer); if (s->enabled) { - /* Pause the timer if it is running. This may cause some - inaccuracy dure to rounding, but avoids a whole lot of other - messyness. */ + /* + * Pause the timer if it is running. This may cause some inaccuracy + * due to rounding, but avoids a whole lot of other messiness + */ ptimer_stop(s->timer); } freq = s->freq; /* ??? Need to recalculate expiry time after changing divisor. */ switch (value & TIMER_TCR_TPSC) { - case 0: freq >>= 2; break; - case 1: freq >>= 4; break; - case 2: freq >>= 6; break; - case 3: freq >>= 8; break; - case 4: freq >>= 10; break; + case 0: + freq >>= 2; + break; + case 1: + freq >>= 4; + break; + case 2: + freq >>= 6; + break; + case 3: + freq >>= 8; + break; + case 4: + freq >>= 10; + break; case 6: case 7: if (s->feat & TIMER_FEAT_EXTCLK) { @@ -124,7 +133,8 @@ static void sh_timer_write(void *opaque, hwaddr offset, } /* fallthrough */ default: - hw_error("sh_timer_write: Reserved TPSC value\n"); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Reserved TPSC value\n", __func__); } switch ((value & TIMER_TCR_CKEG) >> 3) { case 0: @@ -137,7 +147,8 @@ static void sh_timer_write(void *opaque, hwaddr offset, } /* fallthrough */ default: - hw_error("sh_timer_write: Reserved CKEG value\n"); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Reserved CKEG value\n", __func__); } switch ((value & TIMER_TCR_ICPE) >> 6) { case 0: @@ -149,7 +160,8 @@ static void sh_timer_write(void *opaque, hwaddr offset, } /* fallthrough */ default: - hw_error("sh_timer_write: Reserved ICPE value\n"); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Reserved ICPE value\n", __func__); } if ((value & TIMER_TCR_UNF) == 0) { s->int_level = 0; @@ -158,13 +170,15 @@ static void sh_timer_write(void *opaque, hwaddr offset, value &= ~TIMER_TCR_UNF; if ((value & TIMER_TCR_ICPF) && (!(s->feat & TIMER_FEAT_CAPT))) { - hw_error("sh_timer_write: Reserved ICPF value\n"); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Reserved ICPF value\n", __func__); } value &= ~TIMER_TCR_ICPF; /* capture not supported */ if (value & TIMER_TCR_RESERVED) { - hw_error("sh_timer_write: Reserved TCR bits set\n"); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Reserved TCR bits set\n", __func__); } s->tcr = value; ptimer_set_limit(s->timer, s->tcor, 0); @@ -182,19 +196,17 @@ static void sh_timer_write(void *opaque, hwaddr offset, } /* fallthrough */ default: - hw_error("sh_timer_write: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset); } sh_timer_update(s); } static void sh_timer_start_stop(void *opaque, int enable) { - sh_timer_state *s = (sh_timer_state *)opaque; - -#ifdef DEBUG_TIMER - printf("sh_timer_start_stop %d (%d)\n", enable, s->enabled); -#endif + SHTimerState *s = opaque; + trace_sh_timer_start_stop(enable, s->enabled); ptimer_transaction_begin(s->timer); if (s->enabled && !enable) { ptimer_stop(s->timer); @@ -204,24 +216,20 @@ static void sh_timer_start_stop(void *opaque, int enable) } ptimer_transaction_commit(s->timer); s->enabled = !!enable; - -#ifdef DEBUG_TIMER - printf("sh_timer_start_stop done %d\n", s->enabled); -#endif } static void sh_timer_tick(void *opaque) { - sh_timer_state *s = (sh_timer_state *)opaque; + SHTimerState *s = opaque; s->int_level = s->enabled; sh_timer_update(s); } static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq) { - sh_timer_state *s; + SHTimerState *s; - s = (sh_timer_state *)g_malloc0(sizeof(sh_timer_state)); + s = g_malloc0(sizeof(*s)); s->freq = freq; s->feat = feat; s->tcor = 0xffffffff; @@ -252,50 +260,49 @@ typedef struct { int feat; } tmu012_state; -static uint64_t tmu012_read(void *opaque, hwaddr offset, - unsigned size) +static uint64_t tmu012_read(void *opaque, hwaddr offset, unsigned size) { - tmu012_state *s = (tmu012_state *)opaque; - -#ifdef DEBUG_TIMER - printf("tmu012_read 0x%lx\n", (unsigned long) offset); -#endif + tmu012_state *s = opaque; + trace_sh_timer_read(offset); if (offset >= 0x20) { if (!(s->feat & TMU012_FEAT_3CHAN)) { - hw_error("tmu012_write: Bad channel offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad channel offset 0x%" HWADDR_PRIx "\n", + __func__, offset); } return sh_timer_read(s->timer[2], offset - 0x20); } - if (offset >= 0x14) + if (offset >= 0x14) { return sh_timer_read(s->timer[1], offset - 0x14); - - if (offset >= 0x08) + } + if (offset >= 0x08) { return sh_timer_read(s->timer[0], offset - 0x08); - - if (offset == 4) + } + if (offset == 4) { return s->tstr; - - if ((s->feat & TMU012_FEAT_TOCR) && offset == 0) + } + if ((s->feat & TMU012_FEAT_TOCR) && offset == 0) { return s->tocr; + } - hw_error("tmu012_write: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset); return 0; } static void tmu012_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - tmu012_state *s = (tmu012_state *)opaque; - -#ifdef DEBUG_TIMER - printf("tmu012_write 0x%lx 0x%08x\n", (unsigned long) offset, value); -#endif + tmu012_state *s = opaque; + trace_sh_timer_write(offset, value); if (offset >= 0x20) { if (!(s->feat & TMU012_FEAT_3CHAN)) { - hw_error("tmu012_write: Bad channel offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad channel offset 0x%" HWADDR_PRIx "\n", + __func__, offset); } sh_timer_write(s->timer[2], offset - 0x20, value); return; @@ -318,7 +325,7 @@ static void tmu012_write(void *opaque, hwaddr offset, sh_timer_start_stop(s->timer[2], value & (1 << 2)); } else { if (value & (1 << 2)) { - hw_error("tmu012_write: Bad channel\n"); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad channel\n", __func__); } } @@ -337,15 +344,14 @@ static const MemoryRegionOps tmu012_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -void tmu012_init(MemoryRegion *sysmem, hwaddr base, - int feat, uint32_t freq, +void tmu012_init(MemoryRegion *sysmem, hwaddr base, int feat, uint32_t freq, qemu_irq ch0_irq, qemu_irq ch1_irq, qemu_irq ch2_irq0, qemu_irq ch2_irq1) { tmu012_state *s; int timer_feat = (feat & TMU012_FEAT_EXTCLK) ? TIMER_FEAT_EXTCLK : 0; - s = (tmu012_state *)g_malloc0(sizeof(tmu012_state)); + s = g_malloc0(sizeof(*s)); s->feat = feat; s->timer[0] = sh_timer_init(freq, timer_feat, ch0_irq); s->timer[1] = sh_timer_init(freq, timer_feat, ch1_irq); @@ -354,15 +360,14 @@ void tmu012_init(MemoryRegion *sysmem, hwaddr base, ch2_irq0); /* ch2_irq1 not supported */ } - memory_region_init_io(&s->iomem, NULL, &tmu012_ops, s, - "timer", 0x100000000ULL); + memory_region_init_io(&s->iomem, NULL, &tmu012_ops, s, "timer", 0x30); memory_region_init_alias(&s->iomem_p4, NULL, "timer-p4", - &s->iomem, 0, 0x1000); + &s->iomem, 0, memory_region_size(&s->iomem)); memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4); memory_region_init_alias(&s->iomem_a7, NULL, "timer-a7", - &s->iomem, 0, 0x1000); + &s->iomem, 0, memory_region_size(&s->iomem)); memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7); /* ??? Save/restore. */ } diff --git a/hw/timer/trace-events b/hw/timer/trace-events index d0edcd2a80..3eccef8385 100644 --- a/hw/timer/trace-events +++ b/hw/timer/trace-events @@ -94,3 +94,8 @@ sifive_pwm_set_alarm(uint64_t alarm, uint64_t now) "Setting alarm to: 0x%" PRIx6 sifive_pwm_interrupt(int num) "Interrupt %d" sifive_pwm_read(uint64_t offset) "Read at address: 0x%" PRIx64 sifive_pwm_write(uint64_t data, uint64_t offset) "Write 0x%" PRIx64 " at address: 0x%" PRIx64 + +# sh_timer.c +sh_timer_start_stop(int enable, int current) "%d (%d)" +sh_timer_read(uint64_t offset) "tmu012_read 0x%" PRIx64 +sh_timer_write(uint64_t offset, uint64_t value) "tmu012_write 0x%" PRIx64 " 0x%08" PRIx64 diff --git a/hw/vfio/common.c b/hw/vfio/common.c index a784b219e6..dd387b0d39 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -893,6 +893,13 @@ static void vfio_listener_region_add(MemoryListener *listener, llend = int128_and(llend, int128_exts64(qemu_real_host_page_mask)); if (int128_ge(int128_make64(iova), llend)) { + if (memory_region_is_ram_device(section->mr)) { + trace_vfio_listener_region_add_no_dma_map( + memory_region_name(section->mr), + section->offset_within_address_space, + int128_getlo(section->size), + qemu_real_host_page_size); + } return; } end = int128_get64(int128_sub(llend, int128_one())); diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 5cdf1d4298..7b45353ce2 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -2453,7 +2453,12 @@ static int vfio_pci_load_config(VFIODevice *vbasedev, QEMUFile *f) { VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev); PCIDevice *pdev = &vdev->pdev; - int ret; + pcibus_t old_addr[PCI_NUM_REGIONS - 1]; + int bar, ret; + + for (bar = 0; bar < PCI_ROM_SLOT; bar++) { + old_addr[bar] = pdev->io_regions[bar].addr; + } ret = vmstate_load_state(f, &vmstate_vfio_pci_config, vdev, 1); if (ret) { @@ -2463,6 +2468,18 @@ static int vfio_pci_load_config(VFIODevice *vbasedev, QEMUFile *f) vfio_pci_write_config(pdev, PCI_COMMAND, pci_get_word(pdev->config + PCI_COMMAND), 2); + for (bar = 0; bar < PCI_ROM_SLOT; bar++) { + /* + * The address may not be changed in some scenarios + * (e.g. the VF driver isn't loaded in VM). + */ + if (old_addr[bar] != pdev->io_regions[bar].addr && + vdev->bars[bar].region.size > 0 && + vdev->bars[bar].region.size < qemu_real_host_page_size) { + vfio_sub_page_bar_update_mapping(pdev, bar); + } + } + if (msi_enabled(pdev)) { vfio_msi_enable(vdev); } else if (msix_enabled(pdev)) { diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index df91e454b2..d5a578142b 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -228,6 +228,38 @@ static int virtio_mem_for_each_plugged_section(const VirtIOMEM *vmem, return ret; } +static int virtio_mem_for_each_unplugged_section(const VirtIOMEM *vmem, + MemoryRegionSection *s, + void *arg, + virtio_mem_section_cb cb) +{ + unsigned long first_bit, last_bit; + uint64_t offset, size; + int ret = 0; + + first_bit = s->offset_within_region / vmem->bitmap_size; + first_bit = find_next_zero_bit(vmem->bitmap, vmem->bitmap_size, first_bit); + while (first_bit < vmem->bitmap_size) { + MemoryRegionSection tmp = *s; + + offset = first_bit * vmem->block_size; + last_bit = find_next_bit(vmem->bitmap, vmem->bitmap_size, + first_bit + 1) - 1; + size = (last_bit - first_bit + 1) * vmem->block_size; + + if (!virito_mem_intersect_memory_section(&tmp, offset, size)) { + break; + } + ret = cb(&tmp, arg); + if (ret) { + break; + } + first_bit = find_next_zero_bit(vmem->bitmap, vmem->bitmap_size, + last_bit + 2); + } + return ret; +} + static int virtio_mem_notify_populate_cb(MemoryRegionSection *s, void *arg) { RamDiscardListener *rdl = arg; @@ -744,7 +776,6 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp) host_memory_backend_set_mapped(vmem->memdev, true); vmstate_register_ram(&vmem->memdev->mr, DEVICE(vmem)); qemu_register_reset(virtio_mem_system_reset, vmem); - precopy_add_notifier(&vmem->precopy_notifier); /* * Set ourselves as RamDiscardManager before the plug handler maps the @@ -764,7 +795,6 @@ static void virtio_mem_device_unrealize(DeviceState *dev) * found via an address space anymore. Unset ourselves. */ memory_region_set_ram_discard_manager(&vmem->memdev->mr, NULL); - precopy_remove_notifier(&vmem->precopy_notifier); qemu_unregister_reset(virtio_mem_system_reset, vmem); vmstate_unregister_ram(&vmem->memdev->mr, DEVICE(vmem)); host_memory_backend_set_mapped(vmem->memdev, false); @@ -1057,43 +1087,11 @@ static void virtio_mem_set_block_size(Object *obj, Visitor *v, const char *name, vmem->block_size = value; } -static int virtio_mem_precopy_exclude_range_cb(const VirtIOMEM *vmem, void *arg, - uint64_t offset, uint64_t size) -{ - void * const host = qemu_ram_get_host_addr(vmem->memdev->mr.ram_block); - - qemu_guest_free_page_hint(host + offset, size); - return 0; -} - -static void virtio_mem_precopy_exclude_unplugged(VirtIOMEM *vmem) -{ - virtio_mem_for_each_unplugged_range(vmem, NULL, - virtio_mem_precopy_exclude_range_cb); -} - -static int virtio_mem_precopy_notify(NotifierWithReturn *n, void *data) -{ - VirtIOMEM *vmem = container_of(n, VirtIOMEM, precopy_notifier); - PrecopyNotifyData *pnd = data; - - switch (pnd->reason) { - case PRECOPY_NOTIFY_AFTER_BITMAP_SYNC: - virtio_mem_precopy_exclude_unplugged(vmem); - break; - default: - break; - } - - return 0; -} - static void virtio_mem_instance_init(Object *obj) { VirtIOMEM *vmem = VIRTIO_MEM(obj); notifier_list_init(&vmem->size_change_notifiers); - vmem->precopy_notifier.notify = virtio_mem_precopy_notify; QLIST_INIT(&vmem->rdl_list); object_property_add(obj, VIRTIO_MEM_SIZE_PROP, "size", virtio_mem_get_size, @@ -1170,6 +1168,31 @@ static int virtio_mem_rdm_replay_populated(const RamDiscardManager *rdm, virtio_mem_rdm_replay_populated_cb); } +static int virtio_mem_rdm_replay_discarded_cb(MemoryRegionSection *s, + void *arg) +{ + struct VirtIOMEMReplayData *data = arg; + + ((ReplayRamDiscard)data->fn)(s, data->opaque); + return 0; +} + +static void virtio_mem_rdm_replay_discarded(const RamDiscardManager *rdm, + MemoryRegionSection *s, + ReplayRamDiscard replay_fn, + void *opaque) +{ + const VirtIOMEM *vmem = VIRTIO_MEM(rdm); + struct VirtIOMEMReplayData data = { + .fn = replay_fn, + .opaque = opaque, + }; + + g_assert(s->mr == &vmem->memdev->mr); + virtio_mem_for_each_unplugged_section(vmem, s, &data, + virtio_mem_rdm_replay_discarded_cb); +} + static void virtio_mem_rdm_register_listener(RamDiscardManager *rdm, RamDiscardListener *rdl, MemoryRegionSection *s) @@ -1234,6 +1257,7 @@ static void virtio_mem_class_init(ObjectClass *klass, void *data) rdmc->get_min_granularity = virtio_mem_rdm_get_min_granularity; rdmc->is_populated = virtio_mem_rdm_is_populated; rdmc->replay_populated = virtio_mem_rdm_replay_populated; + rdmc->replay_discarded = virtio_mem_rdm_replay_discarded; rdmc->register_listener = virtio_mem_rdm_register_listener; rdmc->unregister_listener = virtio_mem_rdm_unregister_listener; } diff --git a/include/exec/memory.h b/include/exec/memory.h index a185b6dcb8..20f1b27377 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -61,7 +61,17 @@ static inline void fuzz_dma_read_cb(size_t addr, } #endif -extern bool global_dirty_log; +/* Possible bits for global_dirty_log_{start|stop} */ + +/* Dirty tracking enabled because migration is running */ +#define GLOBAL_DIRTY_MIGRATION (1U << 0) + +/* Dirty tracking enabled because measuring dirty rate */ +#define GLOBAL_DIRTY_DIRTY_RATE (1U << 1) + +#define GLOBAL_DIRTY_MASK (0x3) + +extern unsigned int global_dirty_tracking; typedef struct MemoryRegionOps MemoryRegionOps; @@ -540,6 +550,7 @@ static inline void ram_discard_listener_init(RamDiscardListener *rdl, } typedef int (*ReplayRamPopulate)(MemoryRegionSection *section, void *opaque); +typedef void (*ReplayRamDiscard)(MemoryRegionSection *section, void *opaque); /* * RamDiscardManagerClass: @@ -629,6 +640,21 @@ struct RamDiscardManagerClass { ReplayRamPopulate replay_fn, void *opaque); /** + * @replay_discarded: + * + * Call the #ReplayRamDiscard callback for all discarded parts within the + * #MemoryRegionSection via the #RamDiscardManager. + * + * @rdm: the #RamDiscardManager + * @section: the #MemoryRegionSection + * @replay_fn: the #ReplayRamDiscard callback + * @opaque: pointer to forward to the callback + */ + void (*replay_discarded)(const RamDiscardManager *rdm, + MemoryRegionSection *section, + ReplayRamDiscard replay_fn, void *opaque); + + /** * @register_listener: * * Register a #RamDiscardListener for the given #MemoryRegionSection and @@ -672,6 +698,11 @@ int ram_discard_manager_replay_populated(const RamDiscardManager *rdm, ReplayRamPopulate replay_fn, void *opaque); +void ram_discard_manager_replay_discarded(const RamDiscardManager *rdm, + MemoryRegionSection *section, + ReplayRamDiscard replay_fn, + void *opaque); + void ram_discard_manager_register_listener(RamDiscardManager *rdm, RamDiscardListener *rdl, MemoryRegionSection *section); @@ -2388,13 +2419,17 @@ void memory_listener_unregister(MemoryListener *listener); /** * memory_global_dirty_log_start: begin dirty logging for all regions + * + * @flags: purpose of starting dirty log, migration or dirty rate */ -void memory_global_dirty_log_start(void); +void memory_global_dirty_log_start(unsigned int flags); /** * memory_global_dirty_log_stop: end dirty logging for all regions + * + * @flags: purpose of stopping dirty log, migration or dirty rate */ -void memory_global_dirty_log_stop(void); +void memory_global_dirty_log_stop(unsigned int flags); void mtree_info(bool flatview, bool dispatch_tree, bool owner, bool disabled); diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index 551876bed0..64fb936c7c 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -26,6 +26,8 @@ #include "exec/ramlist.h" #include "exec/ramblock.h" +extern uint64_t total_dirty_pages; + /** * clear_bmap_size: calculate clear bitmap size * @@ -369,10 +371,14 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap, qatomic_or(&blocks[DIRTY_MEMORY_VGA][idx][offset], temp); - if (global_dirty_log) { + if (global_dirty_tracking) { qatomic_or( &blocks[DIRTY_MEMORY_MIGRATION][idx][offset], temp); + if (unlikely( + global_dirty_tracking & GLOBAL_DIRTY_DIRTY_RATE)) { + total_dirty_pages += ctpopl(temp); + } } if (tcg_enabled()) { @@ -392,7 +398,7 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap, } else { uint8_t clients = tcg_enabled() ? DIRTY_CLIENTS_ALL : DIRTY_CLIENTS_NOCODE; - if (!global_dirty_log) { + if (!global_dirty_tracking) { clients &= ~(1 << DIRTY_MEMORY_MIGRATION); } @@ -403,6 +409,9 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap, for (i = 0; i < len; i++) { if (bitmap[i] != 0) { c = leul_to_cpu(bitmap[i]); + if (unlikely(global_dirty_tracking & GLOBAL_DIRTY_DIRTY_RATE)) { + total_dirty_pages += ctpopl(c); + } do { j = ctzl(c); c &= ~(1ul << j); diff --git a/include/hw/boards.h b/include/hw/boards.h index 5adbcbb99b..9c1c190104 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -34,6 +34,7 @@ HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine); void machine_set_cpu_numa_node(MachineState *machine, const CpuInstanceProperties *props, Error **errp); +void smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp); /** * machine_class_allow_dynamic_sysbus_dev: Add type to list of valid devices @@ -52,6 +53,21 @@ void machine_set_cpu_numa_node(MachineState *machine, void machine_class_allow_dynamic_sysbus_dev(MachineClass *mc, const char *type); /** + * device_type_is_dynamic_sysbus: Check if type is an allowed sysbus device + * type for the machine class. + * @mc: Machine class + * @type: type to check (should be a subtype of TYPE_SYS_BUS_DEVICE) + * + * Returns: true if @type is a type in the machine's list of + * dynamically pluggable sysbus devices; otherwise false. + * + * Check if the QOM type @type is in the list of allowed sysbus device + * types (see machine_class_allowed_dynamic_sysbus_dev()). + * Note that if @type has a parent type in the list, it is allowed too. + */ +bool device_type_is_dynamic_sysbus(MachineClass *mc, const char *type); + +/** * device_is_dynamic_sysbus: test whether device is a dynamic sysbus device * @mc: Machine class * @dev: device to check @@ -301,7 +317,6 @@ typedef struct CpuTopology { struct MachineState { /*< private >*/ Object parent_obj; - Notifier sysbus_notifier; /*< public >*/ diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 1a10497af3..e948e81f1a 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -381,6 +381,7 @@ struct CPUState { struct kvm_run *kvm_run; struct kvm_dirty_gfn *kvm_dirty_gfns; uint32_t kvm_fetch_index; + uint64_t dirty_pages; /* Used for events with 'vcpu' and *without* the 'disabled' properties */ DECLARE_BITMAP(trace_dstate_delayed, CPU_TRACE_DSTATE_MAX_EVENTS); diff --git a/include/hw/sh4/sh.h b/include/hw/sh4/sh.h index becb596979..ec716cdd45 100644 --- a/include/hw/sh4/sh.h +++ b/include/hw/sh4/sh.h @@ -44,25 +44,18 @@ typedef struct { uint16_t portbmask_trigger; /* Return 0 if no action was taken */ int (*port_change_cb) (uint16_t porta, uint16_t portb, - uint16_t * periph_pdtra, - uint16_t * periph_portdira, - uint16_t * periph_pdtrb, - uint16_t * periph_portdirb); + uint16_t *periph_pdtra, + uint16_t *periph_portdira, + uint16_t *periph_pdtrb, + uint16_t *periph_portdirb); } sh7750_io_device; int sh7750_register_io_device(struct SH7750State *s, - sh7750_io_device * device); + sh7750_io_device *device); /* sh_serial.c */ +#define TYPE_SH_SERIAL "sh-serial" #define SH_SERIAL_FEAT_SCIF (1 << 0) -void sh_serial_init(MemoryRegion *sysmem, - hwaddr base, int feat, - uint32_t freq, Chardev *chr, - qemu_irq eri_source, - qemu_irq rxi_source, - qemu_irq txi_source, - qemu_irq tei_source, - qemu_irq bri_source); /* sh7750.c */ qemu_irq sh7750_irl(struct SH7750State *s); diff --git a/include/hw/sh4/sh_intc.h b/include/hw/sh4/sh_intc.h index 65f3425057..f62d5c5e13 100644 --- a/include/hw/sh4/sh_intc.h +++ b/include/hw/sh4/sh_intc.h @@ -58,7 +58,7 @@ struct intc_desc { }; int sh_intc_get_pending_vector(struct intc_desc *desc, int imask); -struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id); + void sh_intc_toggle_source(struct intc_source *source, int enable_adj, int assert_adj); diff --git a/include/hw/virtio/virtio-mem.h b/include/hw/virtio/virtio-mem.h index 9a6e348fa2..a5dd6a493b 100644 --- a/include/hw/virtio/virtio-mem.h +++ b/include/hw/virtio/virtio-mem.h @@ -65,9 +65,6 @@ struct VirtIOMEM { /* notifiers to notify when "size" changes */ NotifierList size_change_notifiers; - /* don't migrate unplugged memory */ - NotifierWithReturn precopy_notifier; - /* listeners to notify on plug/unplug activity. */ QLIST_HEAD(, RamDiscardListener) rdl_list; }; diff --git a/include/migration/blocker.h b/include/migration/blocker.h index acd27018e9..9cebe2ba06 100644 --- a/include/migration/blocker.h +++ b/include/migration/blocker.h @@ -26,6 +26,22 @@ int migrate_add_blocker(Error *reason, Error **errp); /** + * @migrate_add_blocker_internal - prevent migration from proceeding without + * only-migrate implications + * + * @reason - an error to be returned whenever migration is attempted + * + * @errp - [out] The reason (if any) we cannot block migration right now. + * + * @returns - 0 on success, -EBUSY on failure, with errp set. + * + * Some of the migration blockers can be temporary (e.g., for a few seconds), + * so it shouldn't need to conflict with "-only-migratable". For those cases, + * we can call this function rather than @migrate_add_blocker(). + */ +int migrate_add_blocker_internal(Error *reason, Error **errp); + +/** * @migrate_del_blocker - remove a blocking error from migration * * @reason - the error blocking migration diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index a1ab1ee12d..7b22aeb6ae 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -547,4 +547,5 @@ bool kvm_cpu_check_are_resettable(void); bool kvm_arch_cpu_check_are_resettable(void); +bool kvm_dirty_ring_enabled(void); #endif diff --git a/meson.build b/meson.build index 90e3e85f20..bc918fbe58 100644 --- a/meson.build +++ b/meson.build @@ -2363,6 +2363,7 @@ bsd_user_ss = ss.source_set() chardev_ss = ss.source_set() common_ss = ss.source_set() crypto_ss = ss.source_set() +hwcore_ss = ss.source_set() io_ss = ss.source_set() linux_user_ss = ss.source_set() qmp_ss = ss.source_set() @@ -2457,6 +2458,7 @@ if have_system 'hw/s390x', 'hw/scsi', 'hw/sd', + 'hw/sh4', 'hw/sparc', 'hw/sparc64', 'hw/ssi', @@ -2803,7 +2805,8 @@ libchardev = static_library('chardev', chardev_ss.sources() + genh, chardev = declare_dependency(link_whole: libchardev) -libhwcore = static_library('hwcore', sources: hwcore_files + genh, +hwcore_ss = hwcore_ss.apply(config_host, strict: false) +libhwcore = static_library('hwcore', sources: hwcore_ss.sources() + genh, name_suffix: 'fa', build_by_default: false) hwcore = declare_dependency(link_whole: libhwcore) diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c index 320c56ba2c..d65e744af9 100644 --- a/migration/dirtyrate.c +++ b/migration/dirtyrate.c @@ -15,7 +15,9 @@ #include "qapi/error.h" #include "cpu.h" #include "exec/ramblock.h" +#include "exec/ram_addr.h" #include "qemu/rcu_queue.h" +#include "qemu/main-loop.h" #include "qapi/qapi-commands-migration.h" #include "ram.h" #include "trace.h" @@ -23,9 +25,26 @@ #include "monitor/hmp.h" #include "monitor/monitor.h" #include "qapi/qmp/qdict.h" +#include "sysemu/kvm.h" +#include "sysemu/runstate.h" +#include "exec/memory.h" + +/* + * total_dirty_pages is procted by BQL and is used + * to stat dirty pages during the period of two + * memory_global_dirty_log_sync + */ +uint64_t total_dirty_pages; + +typedef struct DirtyPageRecord { + uint64_t start_pages; + uint64_t end_pages; +} DirtyPageRecord; static int CalculatingState = DIRTY_RATE_STATUS_UNSTARTED; static struct DirtyRateStat DirtyStat; +static DirtyRateMeasureMode dirtyrate_mode = + DIRTY_RATE_MEASURE_MODE_PAGE_SAMPLING; static int64_t set_sample_page_period(int64_t msec, int64_t initial_time) { @@ -70,51 +89,94 @@ static int dirtyrate_set_state(int *state, int old_state, int new_state) static struct DirtyRateInfo *query_dirty_rate_info(void) { + int i; int64_t dirty_rate = DirtyStat.dirty_rate; struct DirtyRateInfo *info = g_malloc0(sizeof(DirtyRateInfo)); - - if (qatomic_read(&CalculatingState) == DIRTY_RATE_STATUS_MEASURED) { - info->has_dirty_rate = true; - info->dirty_rate = dirty_rate; - } + DirtyRateVcpuList *head = NULL, **tail = &head; info->status = CalculatingState; info->start_time = DirtyStat.start_time; info->calc_time = DirtyStat.calc_time; info->sample_pages = DirtyStat.sample_pages; + info->mode = dirtyrate_mode; + + if (qatomic_read(&CalculatingState) == DIRTY_RATE_STATUS_MEASURED) { + info->has_dirty_rate = true; + info->dirty_rate = dirty_rate; + + if (dirtyrate_mode == DIRTY_RATE_MEASURE_MODE_DIRTY_RING) { + /* + * set sample_pages with 0 to indicate page sampling + * isn't enabled + **/ + info->sample_pages = 0; + info->has_vcpu_dirty_rate = true; + for (i = 0; i < DirtyStat.dirty_ring.nvcpu; i++) { + DirtyRateVcpu *rate = g_malloc0(sizeof(DirtyRateVcpu)); + rate->id = DirtyStat.dirty_ring.rates[i].id; + rate->dirty_rate = DirtyStat.dirty_ring.rates[i].dirty_rate; + QAPI_LIST_APPEND(tail, rate); + } + info->vcpu_dirty_rate = head; + } + + if (dirtyrate_mode == DIRTY_RATE_MEASURE_MODE_DIRTY_BITMAP) { + info->sample_pages = 0; + } + } trace_query_dirty_rate_info(DirtyRateStatus_str(CalculatingState)); return info; } -static void init_dirtyrate_stat(int64_t start_time, int64_t calc_time, - uint64_t sample_pages) +static void init_dirtyrate_stat(int64_t start_time, + struct DirtyRateConfig config) { - DirtyStat.total_dirty_samples = 0; - DirtyStat.total_sample_count = 0; - DirtyStat.total_block_mem_MB = 0; DirtyStat.dirty_rate = -1; DirtyStat.start_time = start_time; - DirtyStat.calc_time = calc_time; - DirtyStat.sample_pages = sample_pages; + DirtyStat.calc_time = config.sample_period_seconds; + DirtyStat.sample_pages = config.sample_pages_per_gigabytes; + + switch (config.mode) { + case DIRTY_RATE_MEASURE_MODE_PAGE_SAMPLING: + DirtyStat.page_sampling.total_dirty_samples = 0; + DirtyStat.page_sampling.total_sample_count = 0; + DirtyStat.page_sampling.total_block_mem_MB = 0; + break; + case DIRTY_RATE_MEASURE_MODE_DIRTY_RING: + DirtyStat.dirty_ring.nvcpu = -1; + DirtyStat.dirty_ring.rates = NULL; + break; + default: + break; + } +} + +static void cleanup_dirtyrate_stat(struct DirtyRateConfig config) +{ + /* last calc-dirty-rate qmp use dirty ring mode */ + if (dirtyrate_mode == DIRTY_RATE_MEASURE_MODE_DIRTY_RING) { + free(DirtyStat.dirty_ring.rates); + DirtyStat.dirty_ring.rates = NULL; + } } static void update_dirtyrate_stat(struct RamblockDirtyInfo *info) { - DirtyStat.total_dirty_samples += info->sample_dirty_count; - DirtyStat.total_sample_count += info->sample_pages_count; + DirtyStat.page_sampling.total_dirty_samples += info->sample_dirty_count; + DirtyStat.page_sampling.total_sample_count += info->sample_pages_count; /* size of total pages in MB */ - DirtyStat.total_block_mem_MB += (info->ramblock_pages * - TARGET_PAGE_SIZE) >> 20; + DirtyStat.page_sampling.total_block_mem_MB += (info->ramblock_pages * + TARGET_PAGE_SIZE) >> 20; } static void update_dirtyrate(uint64_t msec) { uint64_t dirtyrate; - uint64_t total_dirty_samples = DirtyStat.total_dirty_samples; - uint64_t total_sample_count = DirtyStat.total_sample_count; - uint64_t total_block_mem_MB = DirtyStat.total_block_mem_MB; + uint64_t total_dirty_samples = DirtyStat.page_sampling.total_dirty_samples; + uint64_t total_sample_count = DirtyStat.page_sampling.total_sample_count; + uint64_t total_block_mem_MB = DirtyStat.page_sampling.total_block_mem_MB; dirtyrate = total_dirty_samples * total_block_mem_MB * 1000 / (total_sample_count * msec); @@ -327,21 +389,183 @@ static bool compare_page_hash_info(struct RamblockDirtyInfo *info, update_dirtyrate_stat(block_dinfo); } - if (DirtyStat.total_sample_count == 0) { + if (DirtyStat.page_sampling.total_sample_count == 0) { return false; } return true; } -static void calculate_dirtyrate(struct DirtyRateConfig config) +static inline void record_dirtypages(DirtyPageRecord *dirty_pages, + CPUState *cpu, bool start) +{ + if (start) { + dirty_pages[cpu->cpu_index].start_pages = cpu->dirty_pages; + } else { + dirty_pages[cpu->cpu_index].end_pages = cpu->dirty_pages; + } +} + +static void dirtyrate_global_dirty_log_start(void) +{ + qemu_mutex_lock_iothread(); + memory_global_dirty_log_start(GLOBAL_DIRTY_DIRTY_RATE); + qemu_mutex_unlock_iothread(); +} + +static void dirtyrate_global_dirty_log_stop(void) +{ + qemu_mutex_lock_iothread(); + memory_global_dirty_log_sync(); + memory_global_dirty_log_stop(GLOBAL_DIRTY_DIRTY_RATE); + qemu_mutex_unlock_iothread(); +} + +static int64_t do_calculate_dirtyrate_vcpu(DirtyPageRecord dirty_pages) +{ + uint64_t memory_size_MB; + int64_t time_s; + uint64_t increased_dirty_pages = + dirty_pages.end_pages - dirty_pages.start_pages; + + memory_size_MB = (increased_dirty_pages * TARGET_PAGE_SIZE) >> 20; + time_s = DirtyStat.calc_time; + + return memory_size_MB / time_s; +} + +static inline void record_dirtypages_bitmap(DirtyPageRecord *dirty_pages, + bool start) +{ + if (start) { + dirty_pages->start_pages = total_dirty_pages; + } else { + dirty_pages->end_pages = total_dirty_pages; + } +} + +static void do_calculate_dirtyrate_bitmap(DirtyPageRecord dirty_pages) +{ + DirtyStat.dirty_rate = do_calculate_dirtyrate_vcpu(dirty_pages); +} + +static inline void dirtyrate_manual_reset_protect(void) +{ + RAMBlock *block = NULL; + + WITH_RCU_READ_LOCK_GUARD() { + RAMBLOCK_FOREACH_MIGRATABLE(block) { + memory_region_clear_dirty_bitmap(block->mr, 0, + block->used_length); + } + } +} + +static void calculate_dirtyrate_dirty_bitmap(struct DirtyRateConfig config) +{ + int64_t msec = 0; + int64_t start_time; + DirtyPageRecord dirty_pages; + + qemu_mutex_lock_iothread(); + memory_global_dirty_log_start(GLOBAL_DIRTY_DIRTY_RATE); + + /* + * 1'round of log sync may return all 1 bits with + * KVM_DIRTY_LOG_INITIALLY_SET enable + * skip it unconditionally and start dirty tracking + * from 2'round of log sync + */ + memory_global_dirty_log_sync(); + + /* + * reset page protect manually and unconditionally. + * this make sure kvm dirty log be cleared if + * KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE cap is enabled. + */ + dirtyrate_manual_reset_protect(); + qemu_mutex_unlock_iothread(); + + record_dirtypages_bitmap(&dirty_pages, true); + + start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); + DirtyStat.start_time = start_time / 1000; + + msec = config.sample_period_seconds * 1000; + msec = set_sample_page_period(msec, start_time); + DirtyStat.calc_time = msec / 1000; + + /* + * dirtyrate_global_dirty_log_stop do two things. + * 1. fetch dirty bitmap from kvm + * 2. stop dirty tracking + */ + dirtyrate_global_dirty_log_stop(); + + record_dirtypages_bitmap(&dirty_pages, false); + + do_calculate_dirtyrate_bitmap(dirty_pages); +} + +static void calculate_dirtyrate_dirty_ring(struct DirtyRateConfig config) +{ + CPUState *cpu; + int64_t msec = 0; + int64_t start_time; + uint64_t dirtyrate = 0; + uint64_t dirtyrate_sum = 0; + DirtyPageRecord *dirty_pages; + int nvcpu = 0; + int i = 0; + + CPU_FOREACH(cpu) { + nvcpu++; + } + + dirty_pages = malloc(sizeof(*dirty_pages) * nvcpu); + + DirtyStat.dirty_ring.nvcpu = nvcpu; + DirtyStat.dirty_ring.rates = malloc(sizeof(DirtyRateVcpu) * nvcpu); + + dirtyrate_global_dirty_log_start(); + + CPU_FOREACH(cpu) { + record_dirtypages(dirty_pages, cpu, true); + } + + start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); + DirtyStat.start_time = start_time / 1000; + + msec = config.sample_period_seconds * 1000; + msec = set_sample_page_period(msec, start_time); + DirtyStat.calc_time = msec / 1000; + + dirtyrate_global_dirty_log_stop(); + + CPU_FOREACH(cpu) { + record_dirtypages(dirty_pages, cpu, false); + } + + for (i = 0; i < DirtyStat.dirty_ring.nvcpu; i++) { + dirtyrate = do_calculate_dirtyrate_vcpu(dirty_pages[i]); + trace_dirtyrate_do_calculate_vcpu(i, dirtyrate); + + DirtyStat.dirty_ring.rates[i].id = i; + DirtyStat.dirty_ring.rates[i].dirty_rate = dirtyrate; + dirtyrate_sum += dirtyrate; + } + + DirtyStat.dirty_rate = dirtyrate_sum; + free(dirty_pages); +} + +static void calculate_dirtyrate_sample_vm(struct DirtyRateConfig config) { struct RamblockDirtyInfo *block_dinfo = NULL; int block_count = 0; int64_t msec = 0; int64_t initial_time; - rcu_register_thread(); rcu_read_lock(); initial_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); if (!record_ramblock_hash_info(&block_dinfo, config, &block_count)) { @@ -364,16 +588,26 @@ static void calculate_dirtyrate(struct DirtyRateConfig config) out: rcu_read_unlock(); free_ramblock_dirty_info(block_dinfo, block_count); - rcu_unregister_thread(); +} + +static void calculate_dirtyrate(struct DirtyRateConfig config) +{ + if (config.mode == DIRTY_RATE_MEASURE_MODE_DIRTY_BITMAP) { + calculate_dirtyrate_dirty_bitmap(config); + } else if (config.mode == DIRTY_RATE_MEASURE_MODE_DIRTY_RING) { + calculate_dirtyrate_dirty_ring(config); + } else { + calculate_dirtyrate_sample_vm(config); + } + + trace_dirtyrate_calculate(DirtyStat.dirty_rate); } void *get_dirtyrate_thread(void *arg) { struct DirtyRateConfig config = *(struct DirtyRateConfig *)arg; int ret; - int64_t start_time; - int64_t calc_time; - uint64_t sample_pages; + rcu_register_thread(); ret = dirtyrate_set_state(&CalculatingState, DIRTY_RATE_STATUS_UNSTARTED, DIRTY_RATE_STATUS_MEASURING); @@ -382,11 +616,6 @@ void *get_dirtyrate_thread(void *arg) return NULL; } - start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) / 1000; - calc_time = config.sample_period_seconds; - sample_pages = config.sample_pages_per_gigabytes; - init_dirtyrate_stat(start_time, calc_time, sample_pages); - calculate_dirtyrate(config); ret = dirtyrate_set_state(&CalculatingState, DIRTY_RATE_STATUS_MEASURING, @@ -394,15 +623,22 @@ void *get_dirtyrate_thread(void *arg) if (ret == -1) { error_report("change dirtyrate state failed."); } + + rcu_unregister_thread(); return NULL; } -void qmp_calc_dirty_rate(int64_t calc_time, bool has_sample_pages, - int64_t sample_pages, Error **errp) +void qmp_calc_dirty_rate(int64_t calc_time, + bool has_sample_pages, + int64_t sample_pages, + bool has_mode, + DirtyRateMeasureMode mode, + Error **errp) { static struct DirtyRateConfig config; QemuThread thread; int ret; + int64_t start_time; /* * If the dirty rate is already being measured, don't attempt to start. @@ -419,6 +655,15 @@ void qmp_calc_dirty_rate(int64_t calc_time, bool has_sample_pages, return; } + if (!has_mode) { + mode = DIRTY_RATE_MEASURE_MODE_PAGE_SAMPLING; + } + + if (has_sample_pages && mode == DIRTY_RATE_MEASURE_MODE_DIRTY_RING) { + error_setg(errp, "either sample-pages or dirty-ring can be specified."); + return; + } + if (has_sample_pages) { if (!is_sample_pages_valid(sample_pages)) { error_setg(errp, "sample-pages is out of range[%d, %d].", @@ -431,6 +676,19 @@ void qmp_calc_dirty_rate(int64_t calc_time, bool has_sample_pages, } /* + * dirty ring mode only works when kvm dirty ring is enabled. + * on the contrary, dirty bitmap mode is not. + */ + if (((mode == DIRTY_RATE_MEASURE_MODE_DIRTY_RING) && + !kvm_dirty_ring_enabled()) || + ((mode == DIRTY_RATE_MEASURE_MODE_DIRTY_BITMAP) && + kvm_dirty_ring_enabled())) { + error_setg(errp, "mode %s is not enabled, use other method instead.", + DirtyRateMeasureMode_str(mode)); + return; + } + + /* * Init calculation state as unstarted. */ ret = dirtyrate_set_state(&CalculatingState, CalculatingState, @@ -442,6 +700,19 @@ void qmp_calc_dirty_rate(int64_t calc_time, bool has_sample_pages, config.sample_period_seconds = calc_time; config.sample_pages_per_gigabytes = sample_pages; + config.mode = mode; + + cleanup_dirtyrate_stat(config); + + /* + * update dirty rate mode so that we can figure out what mode has + * been used in last calculation + **/ + dirtyrate_mode = mode; + + start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) / 1000; + init_dirtyrate_stat(start_time, config); + qemu_thread_create(&thread, "get_dirtyrate", get_dirtyrate_thread, (void *)&config, QEMU_THREAD_DETACHED); } @@ -463,12 +734,24 @@ void hmp_info_dirty_rate(Monitor *mon, const QDict *qdict) info->sample_pages); monitor_printf(mon, "Period: %"PRIi64" (sec)\n", info->calc_time); + monitor_printf(mon, "Mode: %s\n", + DirtyRateMeasureMode_str(info->mode)); monitor_printf(mon, "Dirty rate: "); if (info->has_dirty_rate) { monitor_printf(mon, "%"PRIi64" (MB/s)\n", info->dirty_rate); + if (info->has_vcpu_dirty_rate) { + DirtyRateVcpuList *rate, *head = info->vcpu_dirty_rate; + for (rate = head; rate != NULL; rate = rate->next) { + monitor_printf(mon, "vcpu[%"PRIi64"], Dirty rate: %"PRIi64 + " (MB/s)\n", rate->value->id, + rate->value->dirty_rate); + } + } } else { monitor_printf(mon, "(not ready)\n"); } + + qapi_free_DirtyRateVcpuList(info->vcpu_dirty_rate); g_free(info); } @@ -477,6 +760,9 @@ void hmp_calc_dirty_rate(Monitor *mon, const QDict *qdict) int64_t sec = qdict_get_try_int(qdict, "second", 0); int64_t sample_pages = qdict_get_try_int(qdict, "sample_pages_per_GB", -1); bool has_sample_pages = (sample_pages != -1); + bool dirty_ring = qdict_get_try_bool(qdict, "dirty_ring", false); + bool dirty_bitmap = qdict_get_try_bool(qdict, "dirty_bitmap", false); + DirtyRateMeasureMode mode = DIRTY_RATE_MEASURE_MODE_PAGE_SAMPLING; Error *err = NULL; if (!sec) { @@ -484,7 +770,20 @@ void hmp_calc_dirty_rate(Monitor *mon, const QDict *qdict) return; } - qmp_calc_dirty_rate(sec, has_sample_pages, sample_pages, &err); + if (dirty_ring && dirty_bitmap) { + monitor_printf(mon, "Either dirty ring or dirty bitmap " + "can be specified!\n"); + return; + } + + if (dirty_bitmap) { + mode = DIRTY_RATE_MEASURE_MODE_DIRTY_BITMAP; + } else if (dirty_ring) { + mode = DIRTY_RATE_MEASURE_MODE_DIRTY_RING; + } + + qmp_calc_dirty_rate(sec, has_sample_pages, sample_pages, true, + mode, &err); if (err) { hmp_handle_error(mon, err); return; diff --git a/migration/dirtyrate.h b/migration/dirtyrate.h index e1fd29089e..69d4c5b865 100644 --- a/migration/dirtyrate.h +++ b/migration/dirtyrate.h @@ -43,6 +43,7 @@ struct DirtyRateConfig { uint64_t sample_pages_per_gigabytes; /* sample pages per GB */ int64_t sample_period_seconds; /* time duration between two sampling */ + DirtyRateMeasureMode mode; /* mode of dirtyrate measurement */ }; /* @@ -58,17 +59,29 @@ struct RamblockDirtyInfo { uint32_t *hash_result; /* array of hash result for sampled pages */ }; +typedef struct SampleVMStat { + uint64_t total_dirty_samples; /* total dirty sampled page */ + uint64_t total_sample_count; /* total sampled pages */ + uint64_t total_block_mem_MB; /* size of total sampled pages in MB */ +} SampleVMStat; + +typedef struct VcpuStat { + int nvcpu; /* number of vcpu */ + DirtyRateVcpu *rates; /* array of dirty rate for each vcpu */ +} VcpuStat; + /* * Store calculation statistics for each measure. */ struct DirtyRateStat { - uint64_t total_dirty_samples; /* total dirty sampled page */ - uint64_t total_sample_count; /* total sampled pages */ - uint64_t total_block_mem_MB; /* size of total sampled pages in MB */ int64_t dirty_rate; /* dirty rate in MB/s */ int64_t start_time; /* calculation start time in units of second */ int64_t calc_time; /* time duration of two sampling in units of second */ uint64_t sample_pages; /* sample pages per GB */ + union { + SampleVMStat page_sampling; + VcpuStat dirty_ring; + }; }; void *get_dirtyrate_thread(void *arg); diff --git a/migration/migration.c b/migration/migration.c index 9172686b89..53b9a8af96 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -391,7 +391,7 @@ int migrate_send_rp_message_req_pages(MigrationIncomingState *mis, int migrate_send_rp_req_pages(MigrationIncomingState *mis, RAMBlock *rb, ram_addr_t start, uint64_t haddr) { - void *aligned = (void *)(uintptr_t)(haddr & (-qemu_ram_pagesize(rb))); + void *aligned = (void *)(uintptr_t)ROUND_DOWN(haddr, qemu_ram_pagesize(rb)); bool received = false; WITH_QEMU_LOCK_GUARD(&mis->page_request_mutex) { @@ -2049,6 +2049,20 @@ void migrate_init(MigrationState *s) s->threshold_size = 0; } +int migrate_add_blocker_internal(Error *reason, Error **errp) +{ + /* Snapshots are similar to migrations, so check RUN_STATE_SAVE_VM too. */ + if (runstate_check(RUN_STATE_SAVE_VM) || !migration_is_idle()) { + error_propagate_prepend(errp, error_copy(reason), + "disallowing migration blocker " + "(migration/snapshot in progress) for: "); + return -EBUSY; + } + + migration_blockers = g_slist_prepend(migration_blockers, reason); + return 0; +} + int migrate_add_blocker(Error *reason, Error **errp) { if (only_migratable) { @@ -2058,15 +2072,7 @@ int migrate_add_blocker(Error *reason, Error **errp) return -EACCES; } - if (migration_is_idle()) { - migration_blockers = g_slist_prepend(migration_blockers, reason); - return 0; - } - - error_propagate_prepend(errp, error_copy(reason), - "disallowing migration blocker " - "(migration in progress) for: "); - return -EBUSY; + return migrate_add_blocker_internal(reason, errp); } void migrate_del_blocker(Error *reason) @@ -2631,8 +2637,8 @@ static void migrate_handle_rp_req_pages(MigrationState *ms, const char* rbname, * Since we currently insist on matching page sizes, just sanity check * we're being asked for whole host pages. */ - if (start & (our_host_ps - 1) || - (len & (our_host_ps - 1))) { + if (!QEMU_IS_ALIGNED(start, our_host_ps) || + !QEMU_IS_ALIGNED(len, our_host_ps)) { error_report("%s: Misaligned page request, start: " RAM_ADDR_FMT " len: %zd", __func__, start, len); mark_source_rp_bad(ms); diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index 2e9697bdd2..e721f69d0f 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -402,7 +402,7 @@ bool postcopy_ram_supported_by_host(MigrationIncomingState *mis) strerror(errno)); goto out; } - g_assert(((size_t)testarea & (pagesize - 1)) == 0); + g_assert(QEMU_PTR_IS_ALIGNED(testarea, pagesize)); reg_struct.range.start = (uintptr_t)testarea; reg_struct.range.len = pagesize; @@ -660,7 +660,7 @@ int postcopy_wake_shared(struct PostCopyFD *pcfd, struct uffdio_range range; int ret; trace_postcopy_wake_shared(client_addr, qemu_ram_get_idstr(rb)); - range.start = client_addr & ~(pagesize - 1); + range.start = ROUND_DOWN(client_addr, pagesize); range.len = pagesize; ret = ioctl(pcfd->fd, UFFDIO_WAKE, &range); if (ret) { @@ -671,6 +671,29 @@ int postcopy_wake_shared(struct PostCopyFD *pcfd, return ret; } +static int postcopy_request_page(MigrationIncomingState *mis, RAMBlock *rb, + ram_addr_t start, uint64_t haddr) +{ + void *aligned = (void *)(uintptr_t)ROUND_DOWN(haddr, qemu_ram_pagesize(rb)); + + /* + * Discarded pages (via RamDiscardManager) are never migrated. On unlikely + * access, place a zeropage, which will also set the relevant bits in the + * recv_bitmap accordingly, so we won't try placing a zeropage twice. + * + * Checking a single bit is sufficient to handle pagesize > TPS as either + * all relevant bits are set or not. + */ + assert(QEMU_IS_ALIGNED(start, qemu_ram_pagesize(rb))); + if (ramblock_page_is_discarded(rb, start)) { + bool received = ramblock_recv_bitmap_test_byte_offset(rb, start); + + return received ? 0 : postcopy_place_page_zero(mis, aligned, rb); + } + + return migrate_send_rp_req_pages(mis, rb, start, haddr); +} + /* * Callback from shared fault handlers to ask for a page, * the page must be specified by a RAMBlock and an offset in that rb @@ -679,8 +702,7 @@ int postcopy_wake_shared(struct PostCopyFD *pcfd, int postcopy_request_shared_page(struct PostCopyFD *pcfd, RAMBlock *rb, uint64_t client_addr, uint64_t rb_offset) { - size_t pagesize = qemu_ram_pagesize(rb); - uint64_t aligned_rbo = rb_offset & ~(pagesize - 1); + uint64_t aligned_rbo = ROUND_DOWN(rb_offset, qemu_ram_pagesize(rb)); MigrationIncomingState *mis = migration_incoming_get_current(); trace_postcopy_request_shared_page(pcfd->idstr, qemu_ram_get_idstr(rb), @@ -690,7 +712,7 @@ int postcopy_request_shared_page(struct PostCopyFD *pcfd, RAMBlock *rb, qemu_ram_get_idstr(rb), rb_offset); return postcopy_wake_shared(pcfd, client_addr, rb); } - migrate_send_rp_req_pages(mis, rb, aligned_rbo, client_addr); + postcopy_request_page(mis, rb, aligned_rbo, client_addr); return 0; } @@ -970,7 +992,7 @@ static void *postcopy_ram_fault_thread(void *opaque) break; } - rb_offset &= ~(qemu_ram_pagesize(rb) - 1); + rb_offset = ROUND_DOWN(rb_offset, qemu_ram_pagesize(rb)); trace_postcopy_ram_fault_thread_request(msg.arg.pagefault.address, qemu_ram_get_idstr(rb), rb_offset, @@ -984,8 +1006,8 @@ retry: * Send the request to the source - we want to request one * of our host page sizes (which is >= TPS) */ - ret = migrate_send_rp_req_pages(mis, rb, rb_offset, - msg.arg.pagefault.address); + ret = postcopy_request_page(mis, rb, rb_offset, + msg.arg.pagefault.address); if (ret) { /* May be network failure, try to wait for recovery */ if (ret == -EIO && postcopy_pause_fault_thread(mis)) { @@ -993,7 +1015,7 @@ retry: goto retry; } else { /* This is a unavoidable fault */ - error_report("%s: migrate_send_rp_req_pages() get %d", + error_report("%s: postcopy_request_page() get %d", __func__, ret); break; } diff --git a/migration/ram.c b/migration/ram.c index bb908822d5..680a5158aa 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -811,7 +811,7 @@ static void migration_clear_memory_region_dirty_bitmap(RAMBlock *rb, assert(shift >= 6); size = 1ULL << (TARGET_PAGE_BITS + shift); - start = (((ram_addr_t)page) << TARGET_PAGE_BITS) & (-size); + start = QEMU_ALIGN_DOWN((ram_addr_t)page << TARGET_PAGE_BITS, size); trace_migration_bitmap_clear_dirty(rb->idstr, start, size, page); memory_region_clear_dirty_bitmap(rb->mr, start, size); } @@ -858,6 +858,81 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs, return ret; } +static void dirty_bitmap_clear_section(MemoryRegionSection *section, + void *opaque) +{ + const hwaddr offset = section->offset_within_region; + const hwaddr size = int128_get64(section->size); + const unsigned long start = offset >> TARGET_PAGE_BITS; + const unsigned long npages = size >> TARGET_PAGE_BITS; + RAMBlock *rb = section->mr->ram_block; + uint64_t *cleared_bits = opaque; + + /* + * We don't grab ram_state->bitmap_mutex because we expect to run + * only when starting migration or during postcopy recovery where + * we don't have concurrent access. + */ + if (!migration_in_postcopy() && !migrate_background_snapshot()) { + migration_clear_memory_region_dirty_bitmap_range(rb, start, npages); + } + *cleared_bits += bitmap_count_one_with_offset(rb->bmap, start, npages); + bitmap_clear(rb->bmap, start, npages); +} + +/* + * Exclude all dirty pages from migration that fall into a discarded range as + * managed by a RamDiscardManager responsible for the mapped memory region of + * the RAMBlock. Clear the corresponding bits in the dirty bitmaps. + * + * Discarded pages ("logically unplugged") have undefined content and must + * not get migrated, because even reading these pages for migration might + * result in undesired behavior. + * + * Returns the number of cleared bits in the RAMBlock dirty bitmap. + * + * Note: The result is only stable while migrating (precopy/postcopy). + */ +static uint64_t ramblock_dirty_bitmap_clear_discarded_pages(RAMBlock *rb) +{ + uint64_t cleared_bits = 0; + + if (rb->mr && rb->bmap && memory_region_has_ram_discard_manager(rb->mr)) { + RamDiscardManager *rdm = memory_region_get_ram_discard_manager(rb->mr); + MemoryRegionSection section = { + .mr = rb->mr, + .offset_within_region = 0, + .size = int128_make64(qemu_ram_get_used_length(rb)), + }; + + ram_discard_manager_replay_discarded(rdm, §ion, + dirty_bitmap_clear_section, + &cleared_bits); + } + return cleared_bits; +} + +/* + * Check if a host-page aligned page falls into a discarded range as managed by + * a RamDiscardManager responsible for the mapped memory region of the RAMBlock. + * + * Note: The result is only stable while migrating (precopy/postcopy). + */ +bool ramblock_page_is_discarded(RAMBlock *rb, ram_addr_t start) +{ + if (rb->mr && memory_region_has_ram_discard_manager(rb->mr)) { + RamDiscardManager *rdm = memory_region_get_ram_discard_manager(rb->mr); + MemoryRegionSection section = { + .mr = rb->mr, + .offset_within_region = start, + .size = int128_make64(qemu_ram_pagesize(rb)), + }; + + return !ram_discard_manager_is_populated(rdm, §ion); + } + return false; +} + /* Called with RCU critical section */ static void ramblock_sync_dirty_bitmap(RAMState *rs, RAMBlock *rb) { @@ -1564,25 +1639,68 @@ out: return ret; } +static inline void populate_read_range(RAMBlock *block, ram_addr_t offset, + ram_addr_t size) +{ + /* + * We read one byte of each page; this will preallocate page tables if + * required and populate the shared zeropage on MAP_PRIVATE anonymous memory + * where no page was populated yet. This might require adaption when + * supporting other mappings, like shmem. + */ + for (; offset < size; offset += block->page_size) { + char tmp = *((char *)block->host + offset); + + /* Don't optimize the read out */ + asm volatile("" : "+r" (tmp)); + } +} + +static inline int populate_read_section(MemoryRegionSection *section, + void *opaque) +{ + const hwaddr size = int128_get64(section->size); + hwaddr offset = section->offset_within_region; + RAMBlock *block = section->mr->ram_block; + + populate_read_range(block, offset, size); + return 0; +} + /* - * ram_block_populate_pages: populate memory in the RAM block by reading - * an integer from the beginning of each page. + * ram_block_populate_read: preallocate page tables and populate pages in the + * RAM block by reading a byte of each page. * * Since it's solely used for userfault_fd WP feature, here we just * hardcode page size to qemu_real_host_page_size. * * @block: RAM block to populate */ -static void ram_block_populate_pages(RAMBlock *block) +static void ram_block_populate_read(RAMBlock *rb) { - char *ptr = (char *) block->host; - - for (ram_addr_t offset = 0; offset < block->used_length; - offset += qemu_real_host_page_size) { - char tmp = *(ptr + offset); - - /* Don't optimize the read out */ - asm volatile("" : "+r" (tmp)); + /* + * Skip populating all pages that fall into a discarded range as managed by + * a RamDiscardManager responsible for the mapped memory region of the + * RAMBlock. Such discarded ("logically unplugged") parts of a RAMBlock + * must not get populated automatically. We don't have to track + * modifications via userfaultfd WP reliably, because these pages will + * not be part of the migration stream either way -- see + * ramblock_dirty_bitmap_exclude_discarded_pages(). + * + * Note: The result is only stable while migrating (precopy/postcopy). + */ + if (rb->mr && memory_region_has_ram_discard_manager(rb->mr)) { + RamDiscardManager *rdm = memory_region_get_ram_discard_manager(rb->mr); + MemoryRegionSection section = { + .mr = rb->mr, + .offset_within_region = 0, + .size = rb->mr->size, + }; + + ram_discard_manager_replay_populated(rdm, §ion, + populate_read_section, NULL); + } else { + populate_read_range(rb, 0, rb->used_length); } } @@ -1609,7 +1727,7 @@ void ram_write_tracking_prepare(void) * UFFDIO_WRITEPROTECT_MODE_WP mode setting would silently skip * pages with pte_none() entries in page table. */ - ram_block_populate_pages(block); + ram_block_populate_read(block); } } @@ -2216,7 +2334,14 @@ static void ram_save_cleanup(void *opaque) /* caller have hold iothread lock or is in a bh, so there is * no writing race against the migration bitmap */ - memory_global_dirty_log_stop(); + if (global_dirty_tracking & GLOBAL_DIRTY_MIGRATION) { + /* + * do not stop dirty log without starting it, since + * memory_global_dirty_log_stop will assert that + * memory_global_dirty_log_start/stop used in pairs + */ + memory_global_dirty_log_stop(GLOBAL_DIRTY_MIGRATION); + } } RAMBLOCK_FOREACH_NOT_IGNORED(block) { @@ -2668,6 +2793,19 @@ static void ram_list_init_bitmaps(void) } } +static void migration_bitmap_clear_discarded_pages(RAMState *rs) +{ + unsigned long pages; + RAMBlock *rb; + + RCU_READ_LOCK_GUARD(); + + RAMBLOCK_FOREACH_NOT_IGNORED(rb) { + pages = ramblock_dirty_bitmap_clear_discarded_pages(rb); + rs->migration_dirty_pages -= pages; + } +} + static void ram_init_bitmaps(RAMState *rs) { /* For memory_global_dirty_log_start below. */ @@ -2678,12 +2816,18 @@ static void ram_init_bitmaps(RAMState *rs) ram_list_init_bitmaps(); /* We don't use dirty log with background snapshots */ if (!migrate_background_snapshot()) { - memory_global_dirty_log_start(); + memory_global_dirty_log_start(GLOBAL_DIRTY_MIGRATION); migration_bitmap_sync_precopy(rs); } } qemu_mutex_unlock_ramlist(); qemu_mutex_unlock_iothread(); + + /* + * After an eventual first bitmap sync, fixup the initial bitmap + * containing all 1s to exclude any discarded pages from migration. + */ + migration_bitmap_clear_discarded_pages(rs); } static int ram_init_all(RAMState **rsp) @@ -3434,7 +3578,7 @@ void colo_incoming_start_dirty_log(void) /* Discard this dirty bitmap record */ bitmap_zero(block->bmap, block->max_length >> TARGET_PAGE_BITS); } - memory_global_dirty_log_start(); + memory_global_dirty_log_start(GLOBAL_DIRTY_MIGRATION); } ram_state->migration_dirty_pages = 0; qemu_mutex_unlock_ramlist(); @@ -3446,7 +3590,7 @@ void colo_release_ram_cache(void) { RAMBlock *block; - memory_global_dirty_log_stop(); + memory_global_dirty_log_stop(GLOBAL_DIRTY_MIGRATION); RAMBLOCK_FOREACH_NOT_IGNORED(block) { g_free(block->bmap); block->bmap = NULL; @@ -4112,6 +4256,10 @@ int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *block) */ bitmap_complement(block->bmap, block->bmap, nbits); + /* Clear dirty bits of discarded ranges that we don't want to migrate. */ + ramblock_dirty_bitmap_clear_discarded_pages(block); + + /* We'll recalculate migration_dirty_pages in ram_state_resume_prepare(). */ trace_ram_dirty_bitmap_reload_complete(block->idstr); /* diff --git a/migration/ram.h b/migration/ram.h index 4833e9fd5b..dda1988f3d 100644 --- a/migration/ram.h +++ b/migration/ram.h @@ -72,6 +72,7 @@ void ramblock_recv_bitmap_set_range(RAMBlock *rb, void *host_addr, size_t nr); int64_t ramblock_recv_bitmap_send(QEMUFile *file, const char *block_name); int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *rb); +bool ramblock_page_is_discarded(RAMBlock *rb, ram_addr_t start); /* ram cache */ int colo_init_ram_cache(void); diff --git a/migration/rdma.c b/migration/rdma.c index 2a3c7889b9..f5d3bbe7e9 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -358,9 +358,11 @@ typedef struct RDMAContext { struct ibv_context *verbs; struct rdma_event_channel *channel; struct ibv_qp *qp; /* queue pair */ - struct ibv_comp_channel *comp_channel; /* completion channel */ + struct ibv_comp_channel *recv_comp_channel; /* recv completion channel */ + struct ibv_comp_channel *send_comp_channel; /* send completion channel */ struct ibv_pd *pd; /* protection domain */ - struct ibv_cq *cq; /* completion queue */ + struct ibv_cq *recv_cq; /* recvieve completion queue */ + struct ibv_cq *send_cq; /* send completion queue */ /* * If a previous write failed (perhaps because of a failed @@ -1059,21 +1061,34 @@ static int qemu_rdma_alloc_pd_cq(RDMAContext *rdma) return -1; } - /* create completion channel */ - rdma->comp_channel = ibv_create_comp_channel(rdma->verbs); - if (!rdma->comp_channel) { - error_report("failed to allocate completion channel"); + /* create receive completion channel */ + rdma->recv_comp_channel = ibv_create_comp_channel(rdma->verbs); + if (!rdma->recv_comp_channel) { + error_report("failed to allocate receive completion channel"); goto err_alloc_pd_cq; } /* - * Completion queue can be filled by both read and write work requests, - * so must reflect the sum of both possible queue sizes. + * Completion queue can be filled by read work requests. */ - rdma->cq = ibv_create_cq(rdma->verbs, (RDMA_SIGNALED_SEND_MAX * 3), - NULL, rdma->comp_channel, 0); - if (!rdma->cq) { - error_report("failed to allocate completion queue"); + rdma->recv_cq = ibv_create_cq(rdma->verbs, (RDMA_SIGNALED_SEND_MAX * 3), + NULL, rdma->recv_comp_channel, 0); + if (!rdma->recv_cq) { + error_report("failed to allocate receive completion queue"); + goto err_alloc_pd_cq; + } + + /* create send completion channel */ + rdma->send_comp_channel = ibv_create_comp_channel(rdma->verbs); + if (!rdma->send_comp_channel) { + error_report("failed to allocate send completion channel"); + goto err_alloc_pd_cq; + } + + rdma->send_cq = ibv_create_cq(rdma->verbs, (RDMA_SIGNALED_SEND_MAX * 3), + NULL, rdma->send_comp_channel, 0); + if (!rdma->send_cq) { + error_report("failed to allocate send completion queue"); goto err_alloc_pd_cq; } @@ -1083,11 +1098,19 @@ err_alloc_pd_cq: if (rdma->pd) { ibv_dealloc_pd(rdma->pd); } - if (rdma->comp_channel) { - ibv_destroy_comp_channel(rdma->comp_channel); + if (rdma->recv_comp_channel) { + ibv_destroy_comp_channel(rdma->recv_comp_channel); + } + if (rdma->send_comp_channel) { + ibv_destroy_comp_channel(rdma->send_comp_channel); + } + if (rdma->recv_cq) { + ibv_destroy_cq(rdma->recv_cq); + rdma->recv_cq = NULL; } rdma->pd = NULL; - rdma->comp_channel = NULL; + rdma->recv_comp_channel = NULL; + rdma->send_comp_channel = NULL; return -1; } @@ -1104,8 +1127,8 @@ static int qemu_rdma_alloc_qp(RDMAContext *rdma) attr.cap.max_recv_wr = 3; attr.cap.max_send_sge = 1; attr.cap.max_recv_sge = 1; - attr.send_cq = rdma->cq; - attr.recv_cq = rdma->cq; + attr.send_cq = rdma->send_cq; + attr.recv_cq = rdma->recv_cq; attr.qp_type = IBV_QPT_RC; ret = rdma_create_qp(rdma->cm_id, rdma->pd, &attr); @@ -1496,14 +1519,14 @@ static void qemu_rdma_signal_unregister(RDMAContext *rdma, uint64_t index, * (of any kind) has completed. * Return the work request ID that completed. */ -static uint64_t qemu_rdma_poll(RDMAContext *rdma, uint64_t *wr_id_out, - uint32_t *byte_len) +static uint64_t qemu_rdma_poll(RDMAContext *rdma, struct ibv_cq *cq, + uint64_t *wr_id_out, uint32_t *byte_len) { int ret; struct ibv_wc wc; uint64_t wr_id; - ret = ibv_poll_cq(rdma->cq, 1, &wc); + ret = ibv_poll_cq(cq, 1, &wc); if (!ret) { *wr_id_out = RDMA_WRID_NONE; @@ -1575,7 +1598,8 @@ static uint64_t qemu_rdma_poll(RDMAContext *rdma, uint64_t *wr_id_out, /* Wait for activity on the completion channel. * Returns 0 on success, none-0 on error. */ -static int qemu_rdma_wait_comp_channel(RDMAContext *rdma) +static int qemu_rdma_wait_comp_channel(RDMAContext *rdma, + struct ibv_comp_channel *comp_channel) { struct rdma_cm_event *cm_event; int ret = -1; @@ -1586,7 +1610,7 @@ static int qemu_rdma_wait_comp_channel(RDMAContext *rdma) */ if (rdma->migration_started_on_destination && migration_incoming_get_current()->state == MIGRATION_STATUS_ACTIVE) { - yield_until_fd_readable(rdma->comp_channel->fd); + yield_until_fd_readable(comp_channel->fd); } else { /* This is the source side, we're in a separate thread * or destination prior to migration_fd_process_incoming() @@ -1597,7 +1621,7 @@ static int qemu_rdma_wait_comp_channel(RDMAContext *rdma) */ while (!rdma->error_state && !rdma->received_error) { GPollFD pfds[2]; - pfds[0].fd = rdma->comp_channel->fd; + pfds[0].fd = comp_channel->fd; pfds[0].events = G_IO_IN | G_IO_HUP | G_IO_ERR; pfds[0].revents = 0; @@ -1655,6 +1679,17 @@ static int qemu_rdma_wait_comp_channel(RDMAContext *rdma) return rdma->error_state; } +static struct ibv_comp_channel *to_channel(RDMAContext *rdma, int wrid) +{ + return wrid < RDMA_WRID_RECV_CONTROL ? rdma->send_comp_channel : + rdma->recv_comp_channel; +} + +static struct ibv_cq *to_cq(RDMAContext *rdma, int wrid) +{ + return wrid < RDMA_WRID_RECV_CONTROL ? rdma->send_cq : rdma->recv_cq; +} + /* * Block until the next work request has completed. * @@ -1675,13 +1710,15 @@ static int qemu_rdma_block_for_wrid(RDMAContext *rdma, int wrid_requested, struct ibv_cq *cq; void *cq_ctx; uint64_t wr_id = RDMA_WRID_NONE, wr_id_in; + struct ibv_comp_channel *ch = to_channel(rdma, wrid_requested); + struct ibv_cq *poll_cq = to_cq(rdma, wrid_requested); - if (ibv_req_notify_cq(rdma->cq, 0)) { + if (ibv_req_notify_cq(poll_cq, 0)) { return -1; } /* poll cq first */ while (wr_id != wrid_requested) { - ret = qemu_rdma_poll(rdma, &wr_id_in, byte_len); + ret = qemu_rdma_poll(rdma, poll_cq, &wr_id_in, byte_len); if (ret < 0) { return ret; } @@ -1702,12 +1739,12 @@ static int qemu_rdma_block_for_wrid(RDMAContext *rdma, int wrid_requested, } while (1) { - ret = qemu_rdma_wait_comp_channel(rdma); + ret = qemu_rdma_wait_comp_channel(rdma, ch); if (ret) { goto err_block_for_wrid; } - ret = ibv_get_cq_event(rdma->comp_channel, &cq, &cq_ctx); + ret = ibv_get_cq_event(ch, &cq, &cq_ctx); if (ret) { perror("ibv_get_cq_event"); goto err_block_for_wrid; @@ -1721,7 +1758,7 @@ static int qemu_rdma_block_for_wrid(RDMAContext *rdma, int wrid_requested, } while (wr_id != wrid_requested) { - ret = qemu_rdma_poll(rdma, &wr_id_in, byte_len); + ret = qemu_rdma_poll(rdma, poll_cq, &wr_id_in, byte_len); if (ret < 0) { goto err_block_for_wrid; } @@ -2437,13 +2474,21 @@ static void qemu_rdma_cleanup(RDMAContext *rdma) rdma_destroy_qp(rdma->cm_id); rdma->qp = NULL; } - if (rdma->cq) { - ibv_destroy_cq(rdma->cq); - rdma->cq = NULL; + if (rdma->recv_cq) { + ibv_destroy_cq(rdma->recv_cq); + rdma->recv_cq = NULL; + } + if (rdma->send_cq) { + ibv_destroy_cq(rdma->send_cq); + rdma->send_cq = NULL; + } + if (rdma->recv_comp_channel) { + ibv_destroy_comp_channel(rdma->recv_comp_channel); + rdma->recv_comp_channel = NULL; } - if (rdma->comp_channel) { - ibv_destroy_comp_channel(rdma->comp_channel); - rdma->comp_channel = NULL; + if (rdma->send_comp_channel) { + ibv_destroy_comp_channel(rdma->send_comp_channel); + rdma->send_comp_channel = NULL; } if (rdma->pd) { ibv_dealloc_pd(rdma->pd); @@ -3115,10 +3160,14 @@ static void qio_channel_rdma_set_aio_fd_handler(QIOChannel *ioc, { QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc); if (io_read) { - aio_set_fd_handler(ctx, rioc->rdmain->comp_channel->fd, + aio_set_fd_handler(ctx, rioc->rdmain->recv_comp_channel->fd, + false, io_read, io_write, NULL, opaque); + aio_set_fd_handler(ctx, rioc->rdmain->send_comp_channel->fd, false, io_read, io_write, NULL, opaque); } else { - aio_set_fd_handler(ctx, rioc->rdmaout->comp_channel->fd, + aio_set_fd_handler(ctx, rioc->rdmaout->recv_comp_channel->fd, + false, io_read, io_write, NULL, opaque); + aio_set_fd_handler(ctx, rioc->rdmaout->send_comp_channel->fd, false, io_read, io_write, NULL, opaque); } } @@ -3332,7 +3381,22 @@ static size_t qemu_rdma_save_page(QEMUFile *f, void *opaque, */ while (1) { uint64_t wr_id, wr_id_in; - int ret = qemu_rdma_poll(rdma, &wr_id_in, NULL); + int ret = qemu_rdma_poll(rdma, rdma->recv_cq, &wr_id_in, NULL); + if (ret < 0) { + error_report("rdma migration: polling error! %d", ret); + goto err; + } + + wr_id = wr_id_in & RDMA_WRID_TYPE_MASK; + + if (wr_id == RDMA_WRID_NONE) { + break; + } + } + + while (1) { + uint64_t wr_id, wr_id_in; + int ret = qemu_rdma_poll(rdma, rdma->send_cq, &wr_id_in, NULL); if (ret < 0) { error_report("rdma migration: polling error! %d", ret); goto err; diff --git a/migration/trace-events b/migration/trace-events index a8ae163707..b48d873b8a 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -333,6 +333,8 @@ get_ramblock_vfn_hash(const char *idstr, uint64_t vfn, uint32_t crc) "ramblock n calc_page_dirty_rate(const char *idstr, uint32_t new_crc, uint32_t old_crc) "ramblock name: %s, new crc: %" PRIu32 ", old crc: %" PRIu32 skip_sample_ramblock(const char *idstr, uint64_t ramblock_size) "ramblock name: %s, ramblock size: %" PRIu64 find_page_matched(const char *idstr) "ramblock %s addr or size changed" +dirtyrate_calculate(int64_t dirtyrate) "dirty rate: %" PRIi64 " MB/s" +dirtyrate_do_calculate_vcpu(int idx, uint64_t rate) "vcpu[%d]: %"PRIu64 " MB/s" # block.c migration_block_init_shared(const char *blk_device_name) "Start migration for %s with shared base image" diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc Binary files differindex 91a73db9a3..67f32a8602 100644 --- a/pc-bios/openbios-ppc +++ b/pc-bios/openbios-ppc diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 Binary files differindex a5b7389191..376b01c10b 100644 --- a/pc-bios/openbios-sparc32 +++ b/pc-bios/openbios-sparc32 diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 Binary files differindex f7a501efc6..bbd746fde9 100644 --- a/pc-bios/openbios-sparc64 +++ b/pc-bios/openbios-sparc64 diff --git a/python/qemu/aqmp/__init__.py b/python/qemu/aqmp/__init__.py index d1b0e4dc3d..880d5b6fa7 100644 --- a/python/qemu/aqmp/__init__.py +++ b/python/qemu/aqmp/__init__.py @@ -22,7 +22,6 @@ managing QMP events. # the COPYING file in the top-level directory. import logging -import warnings from .error import AQMPError from .events import EventListener @@ -31,17 +30,6 @@ from .protocol import ConnectError, Runstate, StateError from .qmp_client import ExecInterruptedError, ExecuteError, QMPClient -_WMSG = """ - -The Asynchronous QMP library is currently in development and its API -should be considered highly fluid and subject to change. It should -not be used by any other scripts checked into the QEMU tree. - -Proceed with caution! -""" - -warnings.warn(_WMSG, FutureWarning) - # Suppress logging unless an application engages it. logging.getLogger('qemu.aqmp').addHandler(logging.NullHandler()) diff --git a/python/qemu/aqmp/legacy.py b/python/qemu/aqmp/legacy.py new file mode 100644 index 0000000000..9e7b9fb80b --- /dev/null +++ b/python/qemu/aqmp/legacy.py @@ -0,0 +1,138 @@ +""" +Sync QMP Wrapper + +This class pretends to be qemu.qmp.QEMUMonitorProtocol. +""" + +import asyncio +from typing import ( + Awaitable, + List, + Optional, + TypeVar, + Union, +) + +import qemu.qmp +from qemu.qmp import QMPMessage, QMPReturnValue, SocketAddrT + +from .qmp_client import QMPClient + + +# pylint: disable=missing-docstring + + +class QEMUMonitorProtocol(qemu.qmp.QEMUMonitorProtocol): + def __init__(self, address: SocketAddrT, + server: bool = False, + nickname: Optional[str] = None): + + # pylint: disable=super-init-not-called + self._aqmp = QMPClient(nickname) + self._aloop = asyncio.get_event_loop() + self._address = address + self._timeout: Optional[float] = None + + _T = TypeVar('_T') + + def _sync( + self, future: Awaitable[_T], timeout: Optional[float] = None + ) -> _T: + return self._aloop.run_until_complete( + asyncio.wait_for(future, timeout=timeout) + ) + + def _get_greeting(self) -> Optional[QMPMessage]: + if self._aqmp.greeting is not None: + # pylint: disable=protected-access + return self._aqmp.greeting._asdict() + return None + + # __enter__ and __exit__ need no changes + # parse_address needs no changes + + def connect(self, negotiate: bool = True) -> Optional[QMPMessage]: + self._aqmp.await_greeting = negotiate + self._aqmp.negotiate = negotiate + + self._sync( + self._aqmp.connect(self._address) + ) + return self._get_greeting() + + def accept(self, timeout: Optional[float] = 15.0) -> QMPMessage: + self._aqmp.await_greeting = True + self._aqmp.negotiate = True + + self._sync( + self._aqmp.accept(self._address), + timeout + ) + + ret = self._get_greeting() + assert ret is not None + return ret + + def cmd_obj(self, qmp_cmd: QMPMessage) -> QMPMessage: + return dict( + self._sync( + # pylint: disable=protected-access + + # _raw() isn't a public API, because turning off + # automatic ID assignment is discouraged. For + # compatibility with iotests *only*, do it anyway. + self._aqmp._raw(qmp_cmd, assign_id=False), + self._timeout + ) + ) + + # Default impl of cmd() delegates to cmd_obj + + def command(self, cmd: str, **kwds: object) -> QMPReturnValue: + return self._sync( + self._aqmp.execute(cmd, kwds), + self._timeout + ) + + def pull_event(self, + wait: Union[bool, float] = False) -> Optional[QMPMessage]: + if not wait: + # wait is False/0: "do not wait, do not except." + if self._aqmp.events.empty(): + return None + + # If wait is 'True', wait forever. If wait is False/0, the events + # queue must not be empty; but it still needs some real amount + # of time to complete. + timeout = None + if wait and isinstance(wait, float): + timeout = wait + + return dict( + self._sync( + self._aqmp.events.get(), + timeout + ) + ) + + def get_events(self, wait: Union[bool, float] = False) -> List[QMPMessage]: + events = [dict(x) for x in self._aqmp.events.clear()] + if events: + return events + + event = self.pull_event(wait) + return [event] if event is not None else [] + + def clear_events(self) -> None: + self._aqmp.events.clear() + + def close(self) -> None: + self._sync( + self._aqmp.disconnect() + ) + + def settimeout(self, timeout: Optional[float]) -> None: + self._timeout = timeout + + def send_fd_scm(self, fd: int) -> None: + self._aqmp.send_fd_scm(fd) diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py index 056d340e35..a487c39745 100644 --- a/python/qemu/machine/machine.py +++ b/python/qemu/machine/machine.py @@ -41,7 +41,6 @@ from typing import ( ) from qemu.qmp import ( # pylint: disable=import-error - QEMUMonitorProtocol, QMPMessage, QMPReturnValue, SocketAddrT, @@ -50,6 +49,12 @@ from qemu.qmp import ( # pylint: disable=import-error from . import console_socket +if os.environ.get('QEMU_PYTHON_LEGACY_QMP'): + from qemu.qmp import QEMUMonitorProtocol +else: + from qemu.aqmp.legacy import QEMUMonitorProtocol + + LOG = logging.getLogger(__name__) @@ -170,6 +175,7 @@ class QEMUMachine: self._console_socket: Optional[socket.socket] = None self._remove_files: List[str] = [] self._user_killed = False + self._quit_issued = False def __enter__(self: _T) -> _T: return self @@ -341,9 +347,15 @@ class QEMUMachine: # Comprehensive reset for the failed launch case: self._early_cleanup() - if self._qmp_connection: - self._qmp.close() - self._qmp_connection = None + try: + self._close_qmp_connection() + except Exception as err: # pylint: disable=broad-except + LOG.warning( + "Exception closing QMP connection: %s", + str(err) if str(err) else type(err).__name__ + ) + finally: + assert self._qmp_connection is None self._close_qemu_log_file() @@ -368,6 +380,7 @@ class QEMUMachine: command = '' LOG.warning(msg, -int(exitcode), command) + self._quit_issued = False self._user_killed = False self._launched = False @@ -418,6 +431,31 @@ class QEMUMachine: close_fds=False) self._post_launch() + def _close_qmp_connection(self) -> None: + """ + Close the underlying QMP connection, if any. + + Dutifully report errors that occurred while closing, but assume + that any error encountered indicates an abnormal termination + process and not a failure to close. + """ + if self._qmp_connection is None: + return + + try: + self._qmp.close() + except EOFError: + # EOF can occur as an Exception here when using the Async + # QMP backend. It indicates that the server closed the + # stream. If we successfully issued 'quit' at any point, + # then this was expected. If the remote went away without + # our permission, it's worth reporting that as an abnormal + # shutdown case. + if not (self._user_killed or self._quit_issued): + raise + finally: + self._qmp_connection = None + def _early_cleanup(self) -> None: """ Perform any cleanup that needs to happen before the VM exits. @@ -443,15 +481,13 @@ class QEMUMachine: self._subp.kill() self._subp.wait(timeout=60) - def _soft_shutdown(self, timeout: Optional[int], - has_quit: bool = False) -> None: + def _soft_shutdown(self, timeout: Optional[int]) -> None: """ Perform early cleanup, attempt to gracefully shut down the VM, and wait for it to terminate. :param timeout: Timeout in seconds for graceful shutdown. A value of None is an infinite wait. - :param has_quit: When True, don't attempt to issue 'quit' QMP command :raise ConnectionReset: On QMP communication errors :raise subprocess.TimeoutExpired: When timeout is exceeded waiting for @@ -460,21 +496,24 @@ class QEMUMachine: self._early_cleanup() if self._qmp_connection: - if not has_quit: - # Might raise ConnectionReset - self._qmp.cmd('quit') + try: + if not self._quit_issued: + # May raise ExecInterruptedError or StateError if the + # connection dies or has *already* died. + self.qmp('quit') + finally: + # Regardless, we want to quiesce the connection. + self._close_qmp_connection() # May raise subprocess.TimeoutExpired self._subp.wait(timeout=timeout) - def _do_shutdown(self, timeout: Optional[int], - has_quit: bool = False) -> None: + def _do_shutdown(self, timeout: Optional[int]) -> None: """ Attempt to shutdown the VM gracefully; fallback to a hard shutdown. :param timeout: Timeout in seconds for graceful shutdown. A value of None is an infinite wait. - :param has_quit: When True, don't attempt to issue 'quit' QMP command :raise AbnormalShutdown: When the VM could not be shut down gracefully. The inner exception will likely be ConnectionReset or @@ -482,13 +521,13 @@ class QEMUMachine: may result in its own exceptions, likely subprocess.TimeoutExpired. """ try: - self._soft_shutdown(timeout, has_quit) + self._soft_shutdown(timeout) except Exception as exc: self._hard_shutdown() raise AbnormalShutdown("Could not perform graceful shutdown") \ from exc - def shutdown(self, has_quit: bool = False, + def shutdown(self, hard: bool = False, timeout: Optional[int] = 30) -> None: """ @@ -498,7 +537,6 @@ class QEMUMachine: If the VM has not yet been launched, or shutdown(), wait(), or kill() have already been called, this method does nothing. - :param has_quit: When true, do not attempt to issue 'quit' QMP command. :param hard: When true, do not attempt graceful shutdown, and suppress the SIGKILL warning log message. :param timeout: Optional timeout in seconds for graceful shutdown. @@ -512,7 +550,7 @@ class QEMUMachine: self._user_killed = True self._hard_shutdown() else: - self._do_shutdown(timeout, has_quit) + self._do_shutdown(timeout) finally: self._post_shutdown() @@ -529,7 +567,8 @@ class QEMUMachine: :param timeout: Optional timeout in seconds. Default 30 seconds. A value of `None` is an infinite wait. """ - self.shutdown(has_quit=True, timeout=timeout) + self._quit_issued = True + self.shutdown(timeout=timeout) def set_qmp_monitor(self, enabled: bool = True) -> None: """ @@ -574,7 +613,10 @@ class QEMUMachine: conv_keys = True qmp_args = self._qmp_args(conv_keys, args) - return self._qmp.cmd(cmd, args=qmp_args) + ret = self._qmp.cmd(cmd, args=qmp_args) + if cmd == 'quit' and 'error' not in ret and 'return' in ret: + self._quit_issued = True + return ret def command(self, cmd: str, conv_keys: bool = True, @@ -585,7 +627,10 @@ class QEMUMachine: On failure raise an exception. """ qmp_args = self._qmp_args(conv_keys, args) - return self._qmp.command(cmd, **qmp_args) + ret = self._qmp.command(cmd, **qmp_args) + if cmd == 'quit': + self._quit_issued = True + return ret def get_qmp_event(self, wait: bool = False) -> Optional[QMPMessage]: """ diff --git a/python/tests/iotests-mypy.sh b/python/tests/iotests-mypy.sh new file mode 100755 index 0000000000..ee76470819 --- /dev/null +++ b/python/tests/iotests-mypy.sh @@ -0,0 +1,4 @@ +#!/bin/sh -e + +cd ../tests/qemu-iotests/ +python3 -m linters --mypy diff --git a/python/tests/iotests-pylint.sh b/python/tests/iotests-pylint.sh new file mode 100755 index 0000000000..4cae03424b --- /dev/null +++ b/python/tests/iotests-pylint.sh @@ -0,0 +1,4 @@ +#!/bin/sh -e + +cd ../tests/qemu-iotests/ +python3 -m linters --pylint diff --git a/qapi/migration.json b/qapi/migration.json index 9aa8bc5759..87146ceea2 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -1732,6 +1732,21 @@ 'data': { 'device-id': 'str' } } ## +# @DirtyRateVcpu: +# +# Dirty rate of vcpu. +# +# @id: vcpu index. +# +# @dirty-rate: dirty rate. +# +# Since: 6.1 +# +## +{ 'struct': 'DirtyRateVcpu', + 'data': { 'id': 'int', 'dirty-rate': 'int64' } } + +## # @DirtyRateStatus: # # An enumeration of dirtyrate status. @@ -1749,6 +1764,23 @@ 'data': [ 'unstarted', 'measuring', 'measured'] } ## +# @DirtyRateMeasureMode: +# +# An enumeration of mode of measuring dirtyrate. +# +# @page-sampling: calculate dirtyrate by sampling pages. +# +# @dirty-ring: calculate dirtyrate by dirty ring. +# +# @dirty-bitmap: calculate dirtyrate by dirty bitmap. +# +# Since: 6.1 +# +## +{ 'enum': 'DirtyRateMeasureMode', + 'data': ['page-sampling', 'dirty-ring', 'dirty-bitmap'] } + +## # @DirtyRateInfo: # # Information about current dirty page rate of vm. @@ -1766,6 +1798,12 @@ # @sample-pages: page count per GB for sample dirty pages # the default value is 512 (since 6.1) # +# @mode: mode containing method of calculate dirtyrate includes +# 'page-sampling' and 'dirty-ring' (Since 6.1) +# +# @vcpu-dirty-rate: dirtyrate for each vcpu if dirty-ring +# mode specified (Since 6.1) +# # Since: 5.2 # ## @@ -1774,7 +1812,9 @@ 'status': 'DirtyRateStatus', 'start-time': 'int64', 'calc-time': 'int64', - 'sample-pages': 'uint64'} } + 'sample-pages': 'uint64', + 'mode': 'DirtyRateMeasureMode', + '*vcpu-dirty-rate': [ 'DirtyRateVcpu' ] } } ## # @calc-dirty-rate: @@ -1786,6 +1826,9 @@ # @sample-pages: page count per GB for sample dirty pages # the default value is 512 (since 6.1) # +# @mode: mechanism of calculating dirtyrate includes +# 'page-sampling' and 'dirty-ring' (Since 6.1) +# # Since: 5.2 # # Example: @@ -1794,7 +1837,8 @@ # ## { 'command': 'calc-dirty-rate', 'data': {'calc-time': 'int64', - '*sample-pages': 'int'} } + '*sample-pages': 'int', + '*mode': 'DirtyRateMeasureMode'} } ## # @query-dirty-rate: diff --git a/roms/openbios b/roms/openbios -Subproject d657b653186c0fd6e062cab133497415c2a5a5b +Subproject b9062deaaea7269369eaa46260d75edcaf276af diff --git a/scripts/simplebench/bench_block_job.py b/scripts/simplebench/bench_block_job.py index 4f03c12169..a403c35b08 100755 --- a/scripts/simplebench/bench_block_job.py +++ b/scripts/simplebench/bench_block_job.py @@ -28,6 +28,7 @@ import json sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) from qemu.machine import QEMUMachine from qemu.qmp import QMPConnectError +from qemu.aqmp import ConnectError def bench_block_job(cmd, cmd_args, qemu_args): @@ -49,7 +50,7 @@ def bench_block_job(cmd, cmd_args, qemu_args): vm.launch() except OSError as e: return {'error': 'popen failed: ' + str(e)} - except (QMPConnectError, socket.timeout): + except (QMPConnectError, ConnectError, socket.timeout): return {'error': 'qemu failed: ' + str(vm.get_log())} try: diff --git a/softmmu/memory.c b/softmmu/memory.c index e5826faa0c..7340e19ff5 100644 --- a/softmmu/memory.c +++ b/softmmu/memory.c @@ -39,7 +39,7 @@ static unsigned memory_region_transaction_depth; static bool memory_region_update_pending; static bool ioeventfd_update_pending; -bool global_dirty_log; +unsigned int global_dirty_tracking; static QTAILQ_HEAD(, MemoryListener) memory_listeners = QTAILQ_HEAD_INITIALIZER(memory_listeners); @@ -1821,7 +1821,7 @@ uint8_t memory_region_get_dirty_log_mask(MemoryRegion *mr) uint8_t mask = mr->dirty_log_mask; RAMBlock *rb = mr->ram_block; - if (global_dirty_log && ((rb && qemu_ram_is_migratable(rb)) || + if (global_dirty_tracking && ((rb && qemu_ram_is_migratable(rb)) || memory_region_is_iommu(mr))) { mask |= (1 << DIRTY_MEMORY_MIGRATION); } @@ -2081,6 +2081,17 @@ int ram_discard_manager_replay_populated(const RamDiscardManager *rdm, return rdmc->replay_populated(rdm, section, replay_fn, opaque); } +void ram_discard_manager_replay_discarded(const RamDiscardManager *rdm, + MemoryRegionSection *section, + ReplayRamDiscard replay_fn, + void *opaque) +{ + RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm); + + g_assert(rdmc->replay_discarded); + rdmc->replay_discarded(rdm, section, replay_fn, opaque); +} + void ram_discard_manager_register_listener(RamDiscardManager *rdm, RamDiscardListener *rdl, MemoryRegionSection *section) @@ -2760,14 +2771,18 @@ void memory_global_after_dirty_log_sync(void) static VMChangeStateEntry *vmstate_change; -void memory_global_dirty_log_start(void) +void memory_global_dirty_log_start(unsigned int flags) { if (vmstate_change) { qemu_del_vm_change_state_handler(vmstate_change); vmstate_change = NULL; } - global_dirty_log = true; + assert(flags && !(flags & (~GLOBAL_DIRTY_MASK))); + assert(!(global_dirty_tracking & flags)); + global_dirty_tracking |= flags; + + trace_global_dirty_changed(global_dirty_tracking); MEMORY_LISTENER_CALL_GLOBAL(log_global_start, Forward); @@ -2777,9 +2792,13 @@ void memory_global_dirty_log_start(void) memory_region_transaction_commit(); } -static void memory_global_dirty_log_do_stop(void) +static void memory_global_dirty_log_do_stop(unsigned int flags) { - global_dirty_log = false; + assert(flags && !(flags & (~GLOBAL_DIRTY_MASK))); + assert((global_dirty_tracking & flags) == flags); + global_dirty_tracking &= ~flags; + + trace_global_dirty_changed(global_dirty_tracking); /* Refresh DIRTY_MEMORY_MIGRATION bit. */ memory_region_transaction_begin(); @@ -2792,8 +2811,9 @@ static void memory_global_dirty_log_do_stop(void) static void memory_vm_change_state_handler(void *opaque, bool running, RunState state) { + unsigned int flags = (unsigned int)(uintptr_t)opaque; if (running) { - memory_global_dirty_log_do_stop(); + memory_global_dirty_log_do_stop(flags); if (vmstate_change) { qemu_del_vm_change_state_handler(vmstate_change); @@ -2802,18 +2822,19 @@ static void memory_vm_change_state_handler(void *opaque, bool running, } } -void memory_global_dirty_log_stop(void) +void memory_global_dirty_log_stop(unsigned int flags) { if (!runstate_is_running()) { if (vmstate_change) { return; } vmstate_change = qemu_add_vm_change_state_handler( - memory_vm_change_state_handler, NULL); + memory_vm_change_state_handler, + (void *)(uintptr_t)flags); return; } - memory_global_dirty_log_do_stop(); + memory_global_dirty_log_do_stop(flags); } static void listener_add_address_space(MemoryListener *listener, @@ -2825,7 +2846,7 @@ static void listener_add_address_space(MemoryListener *listener, if (listener->begin) { listener->begin(listener); } - if (global_dirty_log) { + if (global_dirty_tracking) { if (listener->log_global_start) { listener->log_global_start(listener); } diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c index 4851de51a5..e49d9773d2 100644 --- a/softmmu/qdev-monitor.c +++ b/softmmu/qdev-monitor.c @@ -42,6 +42,7 @@ #include "qemu/cutils.h" #include "hw/qdev-properties.h" #include "hw/clock.h" +#include "hw/boards.h" /* * Aliases were a bad idea from the start. Let's keep them @@ -254,6 +255,16 @@ static DeviceClass *qdev_get_device_class(const char **driver, Error **errp) return NULL; } + if (object_class_dynamic_cast(oc, TYPE_SYS_BUS_DEVICE)) { + /* sysbus devices need to be allowed by the machine */ + MachineClass *mc = MACHINE_CLASS(object_get_class(qdev_get_machine())); + if (!device_type_is_dynamic_sysbus(mc, *driver)) { + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver", + "a dynamic sysbus device type for the machine"); + return NULL; + } + } + return dc; } diff --git a/softmmu/trace-events b/softmmu/trace-events index bf1469990e..9c88887b3c 100644 --- a/softmmu/trace-events +++ b/softmmu/trace-events @@ -19,6 +19,7 @@ memory_region_sync_dirty(const char *mr, const char *listener, int global) "mr ' flatview_new(void *view, void *root) "%p (root %p)" flatview_destroy(void *view, void *root) "%p (root %p)" flatview_destroy_rcu(void *view, void *root) "%p (root %p)" +global_dirty_changed(unsigned int bitmask) "bitmask 0x%"PRIx32 # softmmu.c vm_stop_flush_all(int ret) "ret %d" diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 index f3677de9df..6af5ab9e76 100755 --- a/tests/qemu-iotests/040 +++ b/tests/qemu-iotests/040 @@ -92,10 +92,9 @@ class TestSingleDrive(ImageCommitTestCase): self.vm.add_device('virtio-scsi') self.vm.add_device("scsi-hd,id=scsi0,drive=drive0") self.vm.launch() - self.has_quit = False def tearDown(self): - self.vm.shutdown(has_quit=self.has_quit) + self.vm.shutdown() os.remove(test_img) os.remove(mid_img) os.remove(backing_img) @@ -127,8 +126,6 @@ class TestSingleDrive(ImageCommitTestCase): result = self.vm.qmp('quit') self.assert_qmp(result, 'return', {}) - self.has_quit = True - # Same as above, but this time we add the filter after starting the job @iotests.skip_if_unsupported(['throttle']) def test_commit_plus_filter_and_quit(self): @@ -147,8 +144,6 @@ class TestSingleDrive(ImageCommitTestCase): result = self.vm.qmp('quit') self.assert_qmp(result, 'return', {}) - self.has_quit = True - def test_device_not_found(self): result = self.vm.qmp('block-commit', device='nonexistent', top='%s' % mid_img) self.assert_qmp(result, 'error/class', 'DeviceNotFound') diff --git a/tests/qemu-iotests/218 b/tests/qemu-iotests/218 index 325d8244fb..4922b4d3b6 100755 --- a/tests/qemu-iotests/218 +++ b/tests/qemu-iotests/218 @@ -187,4 +187,4 @@ with iotests.VM() as vm, \ log(vm.qmp('quit')) with iotests.Timeout(5, 'Timeout waiting for VM to quit'): - vm.shutdown(has_quit=True) + vm.shutdown() diff --git a/tests/qemu-iotests/255 b/tests/qemu-iotests/255 index c43aa9c67a..3d6d0e80cb 100755 --- a/tests/qemu-iotests/255 +++ b/tests/qemu-iotests/255 @@ -123,4 +123,4 @@ with iotests.FilePath('src.qcow2') as src_path, \ vm.qmp_log('block-job-cancel', device='job0') vm.qmp_log('quit') - vm.shutdown(has_quit=True) + vm.shutdown() diff --git a/tests/qemu-iotests/297 b/tests/qemu-iotests/297 index 91ec34d952..ee78a62735 100755 --- a/tests/qemu-iotests/297 +++ b/tests/qemu-iotests/297 @@ -17,89 +17,66 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import os -import re -import shutil import subprocess import sys +from typing import List import iotests +import linters -# TODO: Empty this list! -SKIP_FILES = ( - '030', '040', '041', '044', '045', '055', '056', '057', '065', '093', - '096', '118', '124', '132', '136', '139', '147', '148', '149', - '151', '152', '155', '163', '165', '194', '196', '202', - '203', '205', '206', '207', '208', '210', '211', '212', '213', '216', - '218', '219', '224', '228', '234', '235', '236', '237', '238', - '240', '242', '245', '246', '248', '255', '256', '257', '258', '260', - '262', '264', '266', '274', '277', '280', '281', '295', '296', '298', - '299', '302', '303', '304', '307', - 'nbd-fault-injector.py', 'qcow2.py', 'qcow2_format.py', 'qed.py' -) +# Looking for something? +# +# List of files to exclude from linting: linters.py +# mypy configuration: mypy.ini +# pylint configuration: pylintrc -def is_python_file(filename): - if not os.path.isfile(filename): +def check_linter(linter: str) -> bool: + try: + linters.run_linter(linter, ['--version'], suppress_output=True) + except subprocess.CalledProcessError: + iotests.case_notrun(f"'{linter}' not found") return False + return True - if filename.endswith('.py'): - return True - with open(filename, encoding='utf-8') as f: - try: - first_line = f.readline() - return re.match('^#!.*python', first_line) is not None - except UnicodeDecodeError: # Ignore binary files - return False +def test_pylint(files: List[str]) -> None: + print('=== pylint ===') + sys.stdout.flush() + if not check_linter('pylint'): + return -def run_linters(): - named_tests = [f'tests/{entry}' for entry in os.listdir('tests')] - check_tests = set(os.listdir('.') + named_tests) - set(SKIP_FILES) - files = [filename for filename in check_tests if is_python_file(filename)] + linters.run_linter('pylint', files) - iotests.logger.debug('Files to be checked:') - iotests.logger.debug(', '.join(sorted(files))) - print('=== pylint ===') +def test_mypy(files: List[str]) -> None: + print('=== mypy ===') sys.stdout.flush() - # Todo notes are fine, but fixme's or xxx's should probably just be - # fixed (in tests, at least) + if not check_linter('mypy'): + return + env = os.environ.copy() - subprocess.run(('pylint-3', '--score=n', '--notes=FIXME,XXX', *files), - env=env, check=False) + env['MYPYPATH'] = env['PYTHONPATH'] - print('=== mypy ===') - sys.stdout.flush() + linters.run_linter('mypy', files, env=env, suppress_output=True) - env['MYPYPATH'] = env['PYTHONPATH'] - p = subprocess.run(('mypy', - '--warn-unused-configs', - '--disallow-subclassing-any', - '--disallow-any-generics', - '--disallow-incomplete-defs', - '--disallow-untyped-decorators', - '--no-implicit-optional', - '--warn-redundant-casts', - '--warn-unused-ignores', - '--no-implicit-reexport', - '--namespace-packages', - '--scripts-are-modules', - *files), - env=env, - check=False, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - universal_newlines=True) - - if p.returncode != 0: - print(p.stdout) - - -for linter in ('pylint-3', 'mypy'): - if shutil.which(linter) is None: - iotests.notrun(f'{linter} not found') - -iotests.script_main(run_linters) + +def main() -> None: + files = linters.get_test_files() + + iotests.logger.debug('Files to be checked:') + iotests.logger.debug(', '.join(sorted(files))) + + for test in (test_pylint, test_mypy): + try: + test(files) + except subprocess.CalledProcessError as exc: + # Linter failure will be caught by diffing the IO. + if exc.output: + print(exc.output) + + +iotests.script_main(main) diff --git a/tests/qemu-iotests/300 b/tests/qemu-iotests/300 index 10f9f2a8da..dbd28384ec 100755 --- a/tests/qemu-iotests/300 +++ b/tests/qemu-iotests/300 @@ -24,8 +24,6 @@ import random import re from typing import Dict, List, Optional -from qemu.machine import machine - import iotests @@ -461,12 +459,11 @@ class TestBlockBitmapMappingErrors(TestDirtyBitmapMigration): f"'{self.src_node_name}': Name is longer than 255 bytes", log) - # Expect abnormal shutdown of the destination VM because of - # the failed migration - try: - self.vm_b.shutdown() - except machine.AbnormalShutdown: - pass + # Destination VM will terminate w/ error of its own accord + # due to the failed migration. + self.vm_b.wait() + rc = self.vm_b.exitcode() + assert rc is not None and rc > 0 def test_aliased_bitmap_name_too_long(self) -> None: # Longer than the maximum for bitmap names diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index e5fff6ddcf..e2f9d873ad 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -30,7 +30,7 @@ import struct import subprocess import sys import time -from typing import (Any, Callable, Dict, Iterable, +from typing import (Any, Callable, Dict, Iterable, Iterator, List, Optional, Sequence, TextIO, Tuple, Type, TypeVar) import unittest @@ -114,6 +114,24 @@ luks_default_key_secret_opt = 'key-secret=keysec0' sample_img_dir = os.environ['SAMPLE_IMG_DIR'] +@contextmanager +def change_log_level( + logger_name: str, level: int = logging.CRITICAL) -> Iterator[None]: + """ + Utility function for temporarily changing the log level of a logger. + + This can be used to silence errors that are expected or uninteresting. + """ + _logger = logging.getLogger(logger_name) + current_level = _logger.level + _logger.setLevel(level) + + try: + yield + finally: + _logger.setLevel(current_level) + + def unarchive_sample_image(sample, fname): sample_fname = os.path.join(sample_img_dir, sample + '.bz2') with bz2.open(sample_fname) as f_in, open(fname, 'wb') as f_out: diff --git a/tests/qemu-iotests/linters.py b/tests/qemu-iotests/linters.py new file mode 100644 index 0000000000..65c4c4e827 --- /dev/null +++ b/tests/qemu-iotests/linters.py @@ -0,0 +1,105 @@ +# Copyright (C) 2020 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import re +import subprocess +import sys +from typing import List, Mapping, Optional + + +# TODO: Empty this list! +SKIP_FILES = ( + '030', '040', '041', '044', '045', '055', '056', '057', '065', '093', + '096', '118', '124', '132', '136', '139', '147', '148', '149', + '151', '152', '155', '163', '165', '194', '196', '202', + '203', '205', '206', '207', '208', '210', '211', '212', '213', '216', + '218', '219', '224', '228', '234', '235', '236', '237', '238', + '240', '242', '245', '246', '248', '255', '256', '257', '258', '260', + '262', '264', '266', '274', '277', '280', '281', '295', '296', '298', + '299', '302', '303', '304', '307', + 'nbd-fault-injector.py', 'qcow2.py', 'qcow2_format.py', 'qed.py' +) + + +def is_python_file(filename): + if not os.path.isfile(filename): + return False + + if filename.endswith('.py'): + return True + + with open(filename, encoding='utf-8') as f: + try: + first_line = f.readline() + return re.match('^#!.*python', first_line) is not None + except UnicodeDecodeError: # Ignore binary files + return False + + +def get_test_files() -> List[str]: + named_tests = [f'tests/{entry}' for entry in os.listdir('tests')] + check_tests = set(os.listdir('.') + named_tests) - set(SKIP_FILES) + return list(filter(is_python_file, check_tests)) + + +def run_linter( + tool: str, + args: List[str], + env: Optional[Mapping[str, str]] = None, + suppress_output: bool = False, +) -> None: + """ + Run a python-based linting tool. + + :param suppress_output: If True, suppress all stdout/stderr output. + :raise CalledProcessError: If the linter process exits with failure. + """ + subprocess.run( + ('python3', '-m', tool, *args), + env=env, + check=True, + stdout=subprocess.PIPE if suppress_output else None, + stderr=subprocess.STDOUT if suppress_output else None, + universal_newlines=True, + ) + + +def main() -> None: + """ + Used by the Python CI system as an entry point to run these linters. + """ + def show_usage() -> None: + print(f"Usage: {sys.argv[0]} < --mypy | --pylint >", file=sys.stderr) + sys.exit(1) + + if len(sys.argv) != 2: + show_usage() + + files = get_test_files() + + if sys.argv[1] == '--pylint': + run_linter('pylint', files) + elif sys.argv[1] == '--mypy': + # mypy bug #9852; disable incremental checking as a workaround. + args = ['--no-incremental'] + files + run_linter('mypy', args) + else: + print(f"Unrecognized argument: '{sys.argv[1]}'", file=sys.stderr) + show_usage() + + +if __name__ == '__main__': + main() diff --git a/tests/qemu-iotests/mypy.ini b/tests/qemu-iotests/mypy.ini new file mode 100644 index 0000000000..4c0339f558 --- /dev/null +++ b/tests/qemu-iotests/mypy.ini @@ -0,0 +1,12 @@ +[mypy] +disallow_any_generics = True +disallow_incomplete_defs = True +disallow_subclassing_any = True +disallow_untyped_decorators = True +implicit_reexport = False +namespace_packages = True +no_implicit_optional = True +scripts_are_modules = True +warn_redundant_casts = True +warn_unused_configs = True +warn_unused_ignores = True diff --git a/tests/qemu-iotests/pylintrc b/tests/qemu-iotests/pylintrc index 8cb4e1d6a6..32ab77b8bb 100644 --- a/tests/qemu-iotests/pylintrc +++ b/tests/qemu-iotests/pylintrc @@ -31,6 +31,22 @@ disable=invalid-name, too-many-statements, consider-using-f-string, + +[REPORTS] + +# Activate the evaluation score. +score=no + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +# TODO notes are fine, but FIXMEs or XXXs should probably just be +# fixed (in tests, at least). +notes=FIXME, + XXX, + + [FORMAT] # Maximum number of characters on a single line. diff --git a/tests/qemu-iotests/tests/mirror-top-perms b/tests/qemu-iotests/tests/mirror-top-perms index 3d475aa3a5..0a51a613f3 100755 --- a/tests/qemu-iotests/tests/mirror-top-perms +++ b/tests/qemu-iotests/tests/mirror-top-perms @@ -21,11 +21,12 @@ import os -from qemu import qmp +from qemu.aqmp import ConnectError from qemu.machine import machine +from qemu.qmp import QMPConnectError import iotests -from iotests import qemu_img +from iotests import change_log_level, qemu_img image_size = 1 * 1024 * 1024 @@ -99,10 +100,14 @@ class TestMirrorTopPerms(iotests.QMPTestCase): self.vm_b.add_blockdev(f'file,node-name=drive0,filename={source}') self.vm_b.add_device('virtio-blk,drive=drive0,share-rw=on') try: - self.vm_b.launch() - print('ERROR: VM B launched successfully, this should not have ' - 'happened') - except qmp.QMPConnectError: + # Silence AQMP errors temporarily. + # TODO: Remove this and just allow the errors to be logged when + # AQMP fully replaces QMP. + with change_log_level('qemu.aqmp'): + self.vm_b.launch() + print('ERROR: VM B launched successfully, ' + 'this should not have happened') + except (QMPConnectError, ConnectError): assert 'Is another process using the image' in self.vm_b.get_log() result = self.vm.qmp('block-job-cancel', diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 5ac2d9e943..acac3622ed 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -46,6 +46,7 @@ tests = { 'test-uuid': [], 'ptimer-test': ['ptimer-test-stubs.c', meson.project_source_root() / 'hw/core/ptimer.c'], 'test-qapi-util': [], + 'test-smp-parse': [qom, meson.project_source_root() / 'hw/core/machine-smp.c'], } if have_system or have_tools diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c new file mode 100644 index 0000000000..cbe0c99049 --- /dev/null +++ b/tests/unit/test-smp-parse.c @@ -0,0 +1,594 @@ +/* + * SMP parsing unit-tests + * + * Copyright (c) 2021 Huawei Technologies Co., Ltd + * + * Authors: + * Yanan Wang <wangyanan55@huawei.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qom/object.h" +#include "qemu/module.h" +#include "qapi/error.h" + +#include "hw/boards.h" + +#define T true +#define F false + +#define MIN_CPUS 1 /* set the min CPUs supported by the machine as 1 */ +#define MAX_CPUS 512 /* set the max CPUs supported by the machine as 512 */ + +/* + * Used to define the generic 3-level CPU topology hierarchy + * -sockets/cores/threads + */ +#define SMP_CONFIG_GENERIC(ha, a, hb, b, hc, c, hd, d, he, e) \ + { \ + .has_cpus = ha, .cpus = a, \ + .has_sockets = hb, .sockets = b, \ + .has_cores = hc, .cores = c, \ + .has_threads = hd, .threads = d, \ + .has_maxcpus = he, .maxcpus = e, \ + } + +#define CPU_TOPOLOGY_GENERIC(a, b, c, d, e) \ + { \ + .cpus = a, \ + .sockets = b, \ + .cores = c, \ + .threads = d, \ + .max_cpus = e, \ + } + +/* + * Currently a 4-level topology hierarchy is supported on PC machines + * -sockets/dies/cores/threads + */ +#define SMP_CONFIG_WITH_DIES(ha, a, hb, b, hc, c, hd, d, he, e, hf, f) \ + { \ + .has_cpus = ha, .cpus = a, \ + .has_sockets = hb, .sockets = b, \ + .has_dies = hc, .dies = c, \ + .has_cores = hd, .cores = d, \ + .has_threads = he, .threads = e, \ + .has_maxcpus = hf, .maxcpus = f, \ + } + +/** + * @config - the given SMP configuration + * @expect_prefer_sockets - the expected parsing result for the + * valid configuration, when sockets are preferred over cores + * @expect_prefer_cores - the expected parsing result for the + * valid configuration, when cores are preferred over sockets + * @expect_error - the expected error report when the given + * configuration is invalid + */ +typedef struct SMPTestData { + SMPConfiguration config; + CpuTopology expect_prefer_sockets; + CpuTopology expect_prefer_cores; + const char *expect_error; +} SMPTestData; + +/* Type info of the tested machine */ +static const TypeInfo smp_machine_info = { + .name = TYPE_MACHINE, + .parent = TYPE_OBJECT, + .class_size = sizeof(MachineClass), + .instance_size = sizeof(MachineState), +}; + +/* + * List all the possible valid sub-collections of the generic 5 + * topology parameters (i.e. cpus/maxcpus/sockets/cores/threads), + * then test the automatic calculation algorithm of the missing + * values in the parser. + */ +static struct SMPTestData data_generic_valid[] = { + { + /* config: no configuration provided + * expect: cpus=1,sockets=1,cores=1,threads=1,maxcpus=1 */ + .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, F, 0, F, 0), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(1, 1, 1, 1, 1), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(1, 1, 1, 1, 1), + }, { + /* config: -smp 8 + * prefer_sockets: cpus=8,sockets=8,cores=1,threads=1,maxcpus=8 + * prefer_cores: cpus=8,sockets=1,cores=8,threads=1,maxcpus=8 */ + .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, F, 0, F, 0), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 8, 1, 1, 8), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 8, 1, 8), + }, { + /* config: -smp sockets=2 + * expect: cpus=2,sockets=2,cores=1,threads=1,maxcpus=2 */ + .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, F, 0, F, 0), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(2, 2, 1, 1, 2), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(2, 2, 1, 1, 2), + }, { + /* config: -smp cores=4 + * expect: cpus=4,sockets=1,cores=4,threads=1,maxcpus=4 */ + .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, F, 0, F, 0), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(4, 1, 4, 1, 4), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(4, 1, 4, 1, 4), + }, { + /* config: -smp threads=2 + * expect: cpus=2,sockets=1,cores=1,threads=2,maxcpus=2 */ + .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, T, 2, F, 0), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(2, 1, 1, 2, 2), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(2, 1, 1, 2, 2), + }, { + /* config: -smp maxcpus=16 + * prefer_sockets: cpus=16,sockets=16,cores=1,threads=1,maxcpus=16 + * prefer_cores: cpus=16,sockets=1,cores=16,threads=1,maxcpus=16 */ + .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, F, 0, T, 16), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 16, 1, 1, 16), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 1, 16, 1, 16), + }, { + /* config: -smp 8,sockets=2 + * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */ + .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, F, 0, F, 0), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), + }, { + /* config: -smp 8,cores=4 + * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */ + .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, F, 0, F, 0), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), + }, { + /* config: -smp 8,threads=2 + * prefer_sockets: cpus=8,sockets=4,cores=1,threads=2,maxcpus=8 + * prefer_cores: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */ + .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, T, 2, F, 0), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 4, 1, 2, 8), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8), + }, { + /* config: -smp 8,maxcpus=16 + * prefer_sockets: cpus=8,sockets=16,cores=1,threads=1,maxcpus=16 + * prefer_cores: cpus=8,sockets=1,cores=16,threads=1,maxcpus=16 */ + .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, F, 0, T, 16), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 16, 1, 1, 16), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 16, 1, 16), + }, { + /* config: -smp sockets=2,cores=4 + * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */ + .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, F, 0, F, 0), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), + }, { + /* config: -smp sockets=2,threads=2 + * expect: cpus=4,sockets=2,cores=1,threads=2,maxcpus=4 */ + .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, T, 2, F, 0), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(4, 2, 1, 2, 4), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(4, 2, 1, 2, 4), + }, { + /* config: -smp sockets=2,maxcpus=16 + * expect: cpus=16,sockets=2,cores=8,threads=1,maxcpus=16 */ + .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, F, 0, T, 16), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 8, 1, 16), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 8, 1, 16), + }, { + /* config: -smp cores=4,threads=2 + * expect: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */ + .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, T, 2, F, 0), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8), + }, { + /* config: -smp cores=4,maxcpus=16 + * expect: cpus=16,sockets=4,cores=4,threads=1,maxcpus=16 */ + .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, F, 0, T, 16), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 4, 4, 1, 16), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 4, 4, 1, 16), + }, { + /* config: -smp threads=2,maxcpus=16 + * prefer_sockets: cpus=16,sockets=8,cores=1,threads=2,maxcpus=16 + * prefer_cores: cpus=16,sockets=1,cores=8,threads=2,maxcpus=16 */ + .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, T, 2, T, 16), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 8, 1, 2, 16), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 1, 8, 2, 16), + }, { + /* config: -smp 8,sockets=2,cores=4 + * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */ + .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, F, 0, F, 0), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), + }, { + /* config: -smp 8,sockets=2,threads=2 + * expect: cpus=8,sockets=2,cores=2,threads=2,maxcpus=8 */ + .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, T, 2, F, 0), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8), + }, { + /* config: -smp 8,sockets=2,maxcpus=16 + * expect: cpus=8,sockets=2,cores=8,threads=1,maxcpus=16 */ + .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, F, 0, T, 16), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 8, 1, 16), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 8, 1, 16), + }, { + /* config: -smp 8,cores=4,threads=2 + * expect: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */ + .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, T, 2, F, 0), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8), + }, { + /* config: -smp 8,cores=4,maxcpus=16 + * expect: cpus=8,sockets=4,cores=4,threads=1,maxcpus=16 */ + .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, F, 0, T, 16), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 4, 4, 1, 16), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 4, 4, 1, 16), + }, { + /* config: -smp 8,threads=2,maxcpus=16 + * prefer_sockets: cpus=8,sockets=8,cores=1,threads=2,maxcpus=16 + * prefer_cores: cpus=8,sockets=1,cores=8,threads=2,maxcpus=16 */ + .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, T, 2, T, 16), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 8, 1, 2, 16), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 8, 2, 16), + }, { + /* config: -smp sockets=2,cores=4,threads=2 + * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */ + .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, T, 2, F, 0), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), + }, { + /* config: -smp sockets=2,cores=4,maxcpus=16 + * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */ + .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, F, 0, T, 16), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), + }, { + /* config: -smp sockets=2,threads=2,maxcpus=16 + * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */ + .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, T, 2, T, 16), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), + }, { + /* config: -smp cores=4,threads=2,maxcpus=16 + * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */ + .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, T, 2, T, 16), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), + }, { + /* config: -smp 8,sockets=2,cores=4,threads=1 + * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */ + .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 1, F, 0), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), + }, { + /* config: -smp 8,sockets=2,cores=4,maxcpus=16 + * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */ + .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, F, 0, T, 16), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), + }, { + /* config: -smp 8,sockets=2,threads=2,maxcpus=16 + * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */ + .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, T, 2, T, 16), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), + }, { + /* config: -smp 8,cores=4,threads=2,maxcpus=16 + * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */ + .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, T, 2, T, 16), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), + }, { + /* config: -smp sockets=2,cores=4,threads=2,maxcpus=16 + * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */ + .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, T, 2, T, 16), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), + }, { + /* config: -smp 8,sockets=2,cores=4,threads=2,maxcpus=16 + * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */ + .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 2, T, 16), + .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), + .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), + }, +}; + +static struct SMPTestData data_generic_invalid[] = { + { + /* config: -smp 2,dies=2 */ + .config = SMP_CONFIG_WITH_DIES(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0), + .expect_error = "dies not supported by this machine's CPU topology", + }, { + /* config: -smp 8,sockets=2,cores=4,threads=2,maxcpus=8 */ + .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 2, T, 8), + .expect_error = "Invalid CPU topology: " + "product of the hierarchy must match maxcpus: " + "sockets (2) * cores (4) * threads (2) " + "!= maxcpus (8)", + }, { + /* config: -smp 18,sockets=2,cores=4,threads=2,maxcpus=16 */ + .config = SMP_CONFIG_GENERIC(T, 18, T, 2, T, 4, T, 2, T, 16), + .expect_error = "Invalid CPU topology: " + "maxcpus must be equal to or greater than smp: " + "sockets (2) * cores (4) * threads (2) " + "== maxcpus (16) < smp_cpus (18)", + }, { + /* config: -smp 1 + * should tweak the supported min CPUs to 2 for testing */ + .config = SMP_CONFIG_GENERIC(T, 1, F, 0, F, 0, F, 0, F, 0), + .expect_error = "Invalid SMP CPUs 1. The min CPUs supported " + "by machine '(null)' is 2", + }, { + /* config: -smp 512 + * should tweak the supported max CPUs to 511 for testing */ + .config = SMP_CONFIG_GENERIC(T, 512, F, 0, F, 0, F, 0, F, 0), + .expect_error = "Invalid SMP CPUs 512. The max CPUs supported " + "by machine '(null)' is 511", + }, +}; + +static struct SMPTestData data_with_dies_invalid[] = { + { + /* config: -smp 16,sockets=2,dies=2,cores=4,threads=2,maxcpus=16 */ + .config = SMP_CONFIG_WITH_DIES(T, 16, T, 2, T, 2, T, 4, T, 2, T, 16), + .expect_error = "Invalid CPU topology: " + "product of the hierarchy must match maxcpus: " + "sockets (2) * dies (2) * cores (4) * threads (2) " + "!= maxcpus (16)", + }, { + /* config: -smp 34,sockets=2,dies=2,cores=4,threads=2,maxcpus=32 */ + .config = SMP_CONFIG_WITH_DIES(T, 34, T, 2, T, 2, T, 4, T, 2, T, 32), + .expect_error = "Invalid CPU topology: " + "maxcpus must be equal to or greater than smp: " + "sockets (2) * dies (2) * cores (4) * threads (2) " + "== maxcpus (32) < smp_cpus (34)", + }, +}; + +static char *smp_config_to_string(SMPConfiguration *config) +{ + return g_strdup_printf( + "(SMPConfiguration) {\n" + " .has_cpus = %5s, cpus = %" PRId64 ",\n" + " .has_sockets = %5s, sockets = %" PRId64 ",\n" + " .has_dies = %5s, dies = %" PRId64 ",\n" + " .has_cores = %5s, cores = %" PRId64 ",\n" + " .has_threads = %5s, threads = %" PRId64 ",\n" + " .has_maxcpus = %5s, maxcpus = %" PRId64 ",\n" + "}", + config->has_cpus ? "true" : "false", config->cpus, + config->has_sockets ? "true" : "false", config->sockets, + config->has_dies ? "true" : "false", config->dies, + config->has_cores ? "true" : "false", config->cores, + config->has_threads ? "true" : "false", config->threads, + config->has_maxcpus ? "true" : "false", config->maxcpus); +} + +static char *cpu_topology_to_string(CpuTopology *topo) +{ + return g_strdup_printf( + "(CpuTopology) {\n" + " .cpus = %u,\n" + " .sockets = %u,\n" + " .dies = %u,\n" + " .cores = %u,\n" + " .threads = %u,\n" + " .max_cpus = %u,\n" + "}", + topo->cpus, topo->sockets, topo->dies, + topo->cores, topo->threads, topo->max_cpus); +} + +static void check_parse(MachineState *ms, SMPConfiguration *config, + CpuTopology *expect_topo, const char *expect_err, + bool is_valid) +{ + g_autofree char *config_str = smp_config_to_string(config); + g_autofree char *expect_topo_str = cpu_topology_to_string(expect_topo); + g_autofree char *output_topo_str = NULL; + Error *err = NULL; + + /* call the generic parser smp_parse() */ + smp_parse(ms, config, &err); + + output_topo_str = cpu_topology_to_string(&ms->smp); + + /* when the configuration is supposed to be valid */ + if (is_valid) { + if ((err == NULL) && + (ms->smp.cpus == expect_topo->cpus) && + (ms->smp.sockets == expect_topo->sockets) && + (ms->smp.dies == expect_topo->dies) && + (ms->smp.cores == expect_topo->cores) && + (ms->smp.threads == expect_topo->threads) && + (ms->smp.max_cpus == expect_topo->max_cpus)) { + return; + } + + if (err != NULL) { + g_printerr("Test smp_parse failed!\n" + "Input configuration: %s\n" + "Should be valid: yes\n" + "Expected topology: %s\n\n" + "Result is valid: no\n" + "Output error report: %s\n", + config_str, expect_topo_str, error_get_pretty(err)); + goto end; + } + + g_printerr("Test smp_parse failed!\n" + "Input configuration: %s\n" + "Should be valid: yes\n" + "Expected topology: %s\n\n" + "Result is valid: yes\n" + "Output topology: %s\n", + config_str, expect_topo_str, output_topo_str); + goto end; + } + + /* when the configuration is supposed to be invalid */ + if (err != NULL) { + if (expect_err == NULL || + g_str_equal(expect_err, error_get_pretty(err))) { + error_free(err); + return; + } + + g_printerr("Test smp_parse failed!\n" + "Input configuration: %s\n" + "Should be valid: no\n" + "Expected error report: %s\n\n" + "Result is valid: no\n" + "Output error report: %s\n", + config_str, expect_err, error_get_pretty(err)); + goto end; + } + + g_printerr("Test smp_parse failed!\n" + "Input configuration: %s\n" + "Should be valid: no\n" + "Expected error report: %s\n\n" + "Result is valid: yes\n" + "Output topology: %s\n", + config_str, expect_err, output_topo_str); + +end: + if (err != NULL) { + error_free(err); + } + + abort(); +} + +static void smp_parse_test(MachineState *ms, SMPTestData *data, bool is_valid) +{ + MachineClass *mc = MACHINE_GET_CLASS(ms); + + mc->smp_props.prefer_sockets = true; + check_parse(ms, &data->config, &data->expect_prefer_sockets, + data->expect_error, is_valid); + + mc->smp_props.prefer_sockets = false; + check_parse(ms, &data->config, &data->expect_prefer_cores, + data->expect_error, is_valid); +} + +/* The parsed results of the unsupported parameters should be 1 */ +static void unsupported_params_init(MachineClass *mc, SMPTestData *data) +{ + if (!mc->smp_props.dies_supported) { + data->expect_prefer_sockets.dies = 1; + data->expect_prefer_cores.dies = 1; + } +} + +/* Reset the related machine properties before each sub-test */ +static void smp_machine_class_init(MachineClass *mc) +{ + mc->min_cpus = MIN_CPUS; + mc->max_cpus = MAX_CPUS; + + mc->smp_props.prefer_sockets = true; + mc->smp_props.dies_supported = false; +} + +static void test_generic(void) +{ + Object *obj = object_new(TYPE_MACHINE); + MachineState *ms = MACHINE(obj); + MachineClass *mc = MACHINE_GET_CLASS(obj); + SMPTestData *data = &(SMPTestData){{ }}; + int i; + + smp_machine_class_init(mc); + + for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { + *data = data_generic_valid[i]; + unsupported_params_init(mc, data); + + smp_parse_test(ms, data, true); + + /* Unsupported parameters can be provided with their values as 1 */ + data->config.has_dies = true; + data->config.dies = 1; + smp_parse_test(ms, data, true); + } + + /* Reset the supported min CPUs and max CPUs */ + mc->min_cpus = 2; + mc->max_cpus = 511; + + for (i = 0; i < ARRAY_SIZE(data_generic_invalid); i++) { + *data = data_generic_invalid[i]; + unsupported_params_init(mc, data); + + smp_parse_test(ms, data, false); + } + + object_unref(obj); +} + +static void test_with_dies(void) +{ + Object *obj = object_new(TYPE_MACHINE); + MachineState *ms = MACHINE(obj); + MachineClass *mc = MACHINE_GET_CLASS(obj); + SMPTestData *data = &(SMPTestData){{ }}; + unsigned int num_dies = 2; + int i; + + smp_machine_class_init(mc); + mc->smp_props.dies_supported = true; + + for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { + *data = data_generic_valid[i]; + unsupported_params_init(mc, data); + + /* when dies parameter is omitted, it will be set as 1 */ + data->expect_prefer_sockets.dies = 1; + data->expect_prefer_cores.dies = 1; + + smp_parse_test(ms, data, true); + + /* when dies parameter is specified */ + data->config.has_dies = true; + data->config.dies = num_dies; + if (data->config.has_cpus) { + data->config.cpus *= num_dies; + } + if (data->config.has_maxcpus) { + data->config.maxcpus *= num_dies; + } + + data->expect_prefer_sockets.dies = num_dies; + data->expect_prefer_sockets.cpus *= num_dies; + data->expect_prefer_sockets.max_cpus *= num_dies; + data->expect_prefer_cores.dies = num_dies; + data->expect_prefer_cores.cpus *= num_dies; + data->expect_prefer_cores.max_cpus *= num_dies; + + smp_parse_test(ms, data, true); + } + + for (i = 0; i < ARRAY_SIZE(data_with_dies_invalid); i++) { + *data = data_with_dies_invalid[i]; + unsupported_params_init(mc, data); + + smp_parse_test(ms, data, false); + } + + object_unref(obj); +} + +int main(int argc, char *argv[]) +{ + g_test_init(&argc, &argv, NULL); + + module_call_init(MODULE_INIT_QOM); + type_register_static(&smp_machine_info); + + g_test_add_func("/test-smp-parse/generic", test_generic); + g_test_add_func("/test-smp-parse/with_dies", test_with_dies); + + g_test_run(); + + return 0; +} |