From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
To: Anthony Liguori <anthony@codemonkey.ws>
Cc: peter.maydell@linaro.org, qemu-devel@nongnu.org,
blauwirbel@gmail.com, kraxel@redhat.com,
edgar.iglesias@gmail.com, pbonzini@redhat.com
Subject: Re: [Qemu-devel] [PATCH v3 4/5] xilinx_devcfg: Zynq devcfg device model
Date: Sat, 1 Jun 2013 09:34:14 +1000 [thread overview]
Message-ID: <CAEgOgz6E8reOBra6CUOJw9-JR_=VC0fKhWA_5Ad6RSYRtTh12Q@mail.gmail.com> (raw)
In-Reply-To: <87ehcocl17.fsf@codemonkey.ws>
Hi Anthony,
On Fri, May 31, 2013 at 5:41 AM, Anthony Liguori <anthony@codemonkey.ws> wrote:
> Peter Crosthwaite <peter.crosthwaite@xilinx.com> writes:
[snip]
>>> }
>>>
>>
>> That's still possible using just the register API (Patch 2 content
>> only) and throwing away the memory API glue. I think its actually
>> quite similar to V1 of the patch series where I did not have the
>> callbacks, and use the switch-cases for register side-effects only.
>> This looks like the intention of your patch. Gerd made a push for the
>> callbacks in an earlier review and there was push to integrate to
>> Memory API . Is it reasonable to leave it up to the developer whether
>> they want to do full conversion (Patches 2 & 3) or half conversion
>> (Patch 2 only + your decode refactoring). V1 of this patch at:
>>
>> http://patchwork.ozlabs.org/patch/224534/
>>
>> heres the relevant snippet (comments from me inline):
>>
>> +static void xilinx_devcfg_write(void *opaque, hwaddr addr, uint64_t value,
>> + unsigned size)
>> +{
>> + XilinxDevcfg *s = opaque;
>> + int i;
>> + uint32_t aes_en;
>> + const char *prefix = "";
>> +
>> + /* FIXME: use tracing to avoid these gymnastics */
>> + if (XILINX_DEVCFG_ERR_DEBUG || qemu_get_log_flags() & LOG_GUEST_ERROR) {
>> + prefix = g_strdup_printf("%s:Addr %#08x",
>> + object_get_canonical_path(OBJECT(s)),
>> + (unsigned)addr);
>> + }
>> + addr >>= 2;
>>
>> This is the open coded decode logic but is trivial in this case.
>
> But this is invisible to the common layer.
>
> I think being able to have a common layer insight into "this value is
> being written to this device register" would be extremely useful.
>
> But my fear is that the current proposal will not work for a large set
> of devices.
>
> Let me provide another example (attached below) but highlighting the
> description:
>
>> static RegisterDecodeEntry decoder[] = {
>> /* addresses 0-1 must be open decoded due to latching */
>> { .addr = 2, .regno = UART_FCR, .flags = REG_WRITE },
>> { .addr = 2, .regno = UART_IIR, .flags = REG_READ },
The TRM im reading (for the Xilinx 16550 serial) has the read decoding
of FCR vs IIR dependent on LCR, so I think these two are open decoded
as well.
>> { .addr = 3, .regno = UART_LCR, .flags = REG_RW },
>> { .addr = 4, .regno = UART_MCR, .flags = REG_RW },
>> { .addr = 5, .regno = UART_LSR, .flags = REG_READ },
>> { .addr = 6, .regno = UART_MSR, .flags = REG_READ },
>> { .addr = 7, .regno = UART_SCR, .flags = REG_RW },
>> };
>>
>> static RegisterMapEntry regmap[] = {
>> DEFINE_REG_U8(SerialState, ier, UART_IER),
>> DEFINE_REG_U8(SerialState, iir, UART_IIR),
>> DEFINE_REG_U8(SerialState, lcr, UART_LCR),
>> DEFINE_REG_U8(SerialState, mcr, UART_MCR),
>> DEFINE_REG_U8(SerialState, lsr, UART_LSR),
>> DEFINE_REG_U8(SerialState, scr, UART_SCR),
>> DEFINE_REG_U8(SerialState, thr, UART_THR),
>> };
I like it, but can we merge the two to avoid the replicated lists?
Append the decode information to the existing RegisterMapEntry (or
other way round if you want to think of it like that). I know there is
not a 1:1 correlation between decode lines and storage, but register
API already supports no-storage entries for this very purpose - you
can describe a "register" with no storage and define only side effects
(currently implemented via post_foo callbacks). Then we dont need the
enum to perform mapping from decode to register (except for the open
decode case).
Perhaps its better to think of the RegisterAccessInfo array in the
patch as corresponding to decode lines, rather than storage, with
optional storage information appended
Will send rework shortly.
Regards,
Peter
>
> This is a clear separation between decode logic and load/store logic.
> They are very different things from a hardware point of view.
>
>
>> + assert(addr < R_MAX);
>> +
>> + if (s->lock && addr != R_UNLOCK) {
>> + qemu_log_mask(LOG_GUEST_ERROR, "%s:write to non-lock register while"
>> + " locked\n", prefix);
>> + return;
>> + }
>> +
>>
>> some pre write logic (I dropped it later as it was actually unimplemented).
>>
>> + uint32_write(&s->regs[addr], &xilinx_devcfg_regs_info[addr], value, prefix,
>> + XILINX_DEVCFG_ERR_DEBUG);
>> +
>>
>> this is the data-driven register_write() call under its old name.
>>
>> + /*side effects */
>> + switch (addr) {
>> + case R_CTRL:
>> + for (i = 0; i < ARRAY_SIZE(lock_ctrl_map); ++i) {
>> + if (s->regs[R_LOCK] & 1 << i) {
>> + value &= ~lock_ctrl_map[i];
>> + value |= lock_ctrl_map[i] & s->regs[R_CTRL];
>> + }
>> + }
>> + aes_en = extract32(value, PCFG_AES_EN_SHIFT, PCFG_AES_EN_LEN);
>> + if (aes_en != 0 && aes_en != 7) {
>> + qemu_log_mask(LOG_UNIMP, "%s: warning, aes-en bits inconsistent,"
>> + "unimplemeneted security reset should happen!\n",
>> + prefix);
>> + }
>> + break;
>> +
>> + case R_DMA_DST_LEN:
>> + /* TODO: implement command queue overflow check and interrupt */
>> + s->dma_command_fifo[s->dma_command_fifo_num].src_addr =
>> + s->regs[R_DMA_SRC_ADDR] & ~0x3UL;
>> + s->dma_command_fifo[s->dma_command_fifo_num].dest_addr =
>> + s->regs[R_DMA_DST_ADDR] & ~0x3UL;
>> + s->dma_command_fifo[s->dma_command_fifo_num].src_len =
>> + s->regs[R_DMA_SRC_LEN] << 2;
>> + s->dma_command_fifo[s->dma_command_fifo_num].dest_len =
>> + s->regs[R_DMA_DST_LEN] << 2;
>> + s->dma_command_fifo_num++;
>> + DB_PRINT("dma transfer started; %d total transfers pending\n",
>> + s->dma_command_fifo_num);
>> + xilinx_devcfg_dma_go(s);
>> + break;
>> +
>> + case R_UNLOCK:
>> + if (value == R_UNLOCK_MAGIC) {
>> + s->lock = 0;
>> + DB_PRINT("successful unlock\n");
>> + } else if (s->lock) {/* bad unlock attempt */
>> + qemu_log_mask(LOG_GUEST_ERROR, "%s:failed unlock\n", prefix);
>> + s->regs[R_CTRL] &= ~PCAP_PR;
>> + s->regs[R_CTRL] &= ~PCFG_AES_EN_MASK;
>> + }
>> + break;
>> + }
>>
>> And the post-write logic.
>>
>> + xilinx_devcfg_update_ixr(s);
>> +
>> + if (*prefix) {
>> + g_free((void *)prefix);
>> + }
>> +}
>> +
>>
>>> It makes it much easier to convert existing code. We can then leave
>>> most of the switch statements intact and just introduce register
>>> descriptions.
>>>
>>> I think splitting decode from data processing is useful too because it
>>> makes it easier to support latching.
>>>
>>> I think the current spin is probably over generalizing too. I don't
>>> think supporting ge0/ge1 makes a lot of sense from the start. Decisions
>>> aren't always that simple and it's weird to have sanity checking split
>>> across two places.
>>>
>>
>> My goal is to pretty much copy paste out the TRM for the clear GE
>> write. Some of my register fields in the TRM for this device say
>> things like "Reserved, always write as 1" which im trying to capture
>> in a data driven way without having to pollute my switch-cases with
>> this junk. It would be nice to autogenerate this as well.
>
> I think you're trying to solve too many problems at once.
>
> I don't think putting error messages in a register layout description is
> a good idea.
>
>
>>> BTW: I think it's also a good idea to model this as a QOM object so that
>>> device state can be access through the QOM tree.
>
> FWIW, I now think this is a bad idea :-)
>
> Here's the full example:
>
>
>
> Regards,
>
> Anthony Liguori
>
>>>
>>
>> Hmm ill have to think on this one.
>>
>> Regards,
>> Peter
>>
>>> Regards,
>>>
>>> Anthony Liguori
>>>
>>>> + },
>>>> + [R_LOCK] = { .name = "LOCK",
>>>> + .ro = ~ONES(5),
>>>> + .pre_write = r_lock_pre_write,
>>>> + },
>>>> + [R_CFG] = { .name = "CFG",
>>>> + .reset = 1 << RFIFO_TH_SHIFT | 1 << WFIFO_TH_SHIFT | 0x8,
>>>> + .ge1 = (RegisterAccessError[]) {
>>>> + { .mask = 0x7, .reason = "Reserved - do not modify" },
>>>> + {},
>>>> + },
>>>> + .ge0 = (RegisterAccessError[]) {
>>>> + { .mask = 0x8, .reason = "Reserved - do not modify" },
>>>> + {},
>>>> + },
>>>> + .ro = 0x00f | ~ONES(12),
>>>> + },
>>>> + [R_INT_STS] = { .name = "INT_STS",
>>>> + .w1c = ~R_INT_STS_RSVD,
>>>> + .reset = PSS_GTS_USR_B_INT | PSS_CFG_RESET_B_INT | WR_FIFO_LVL_INT,
>>>> + .ro = R_INT_STS_RSVD,
>>>> + .post_write = r_ixr_post_write,
>>>> + },
>>>> + [R_INT_MASK] = { .name = "INT_MASK",
>>>> + .reset = ~0,
>>>> + .ro = R_INT_STS_RSVD,
>>>> + .post_write = r_ixr_post_write,
>>>> + },
>>>> + [R_STATUS] = { .name = "STATUS",
>>>> + .reset = DMA_CMD_Q_E | PSS_GTS_USR_B | PSS_CFG_RESET_B,
>>>> + .ro = ~0,
>>>> + .ge1 = (RegisterAccessError[]) {
>>>> + {.mask = 0x1, .reason = "Reserved - do not modify" },
>>>> + {},
>>>> + },
>>>> + },
>>>> + [R_DMA_SRC_ADDR] = { .name = "DMA_SRC_ADDR" },
>>>> + [R_DMA_DST_ADDR] = { .name = "DMA_DST_ADDR" },
>>>> + [R_DMA_SRC_LEN] = { .name = "DMA_SRC_LEN", .ro = ~ONES(27) },
>>>> + [R_DMA_DST_LEN] = { .name = "DMA_DST_LEN",
>>>> + .ro = ~ONES(27),
>>>> + .post_write = r_dma_dst_len_post_write,
>>>> + },
>>>> + [R_ROM_SHADOW] = { .name = "ROM_SHADOW",
>>>> + .ge1 = (RegisterAccessError[]) {
>>>> + {.mask = ~0, .reason = "Reserved - do not modify" },
>>>> + {},
>>>> + },
>>>> + },
>>>> + [R_SW_ID] = { .name = "SW_ID" },
>>>> + [R_UNLOCK] = { .name = "UNLOCK",
>>>> + .post_write = r_unlock_post_write,
>>>> + },
>>>> + [R_MCTRL] = { .name = "MCTRL",
>>>> + /* Silicon 3.0 for version field, and the mysterious reserved bit 23 */
>>>> + .reset = 0x2 << PS_VERSION_SHIFT | 1 << 23,
>>>> + /* some reserved bits are rw while others are ro */
>>>> + .ro = ~INT_PCAP_LPBK,
>>>> + .ge1 = (RegisterAccessError[]) {
>>>> + { .mask = 0x00F00300, .reason = "Reserved - do not modify" },
>>>> + { .mask = 0x00000003, .reason = "Reserved - always write with 0" },
>>>> + {}
>>>> + },
>>>> + .ge0 = (RegisterAccessError[]) {
>>>> + { .mask = 1 << 23, .reason = "Reserved - always write with 1" },
>>>> + {}
>>>> + },
>>>> + },
>>>> + [R_MAX] = {}
>>>> +};
>>>> +
>>>> +static const MemoryRegionOps devcfg_reg_ops = {
>>>> + .read = register_read_memory_le,
>>>> + .write = register_write_memory_le,
>>>> + .endianness = DEVICE_LITTLE_ENDIAN,
>>>> + .valid = {
>>>> + .min_access_size = 4,
>>>> + .max_access_size = 4,
>>>> + }
>>>> +};
>>>> +
>>>> +static void xilinx_devcfg_realize(DeviceState *dev, Error **errp)
>>>> +{
>>>> + XilinxDevcfg *s = XILINX_DEVCFG(dev);
>>>> + const char *prefix = object_get_canonical_path(OBJECT(dev));
>>>> + int i;
>>>> +
>>>> + for (i = 0; i < R_MAX; ++i) {
>>>> + RegisterInfo *r = &s->regs_info[i];
>>>> +
>>>> + *r = (RegisterInfo) {
>>>> + .data = &s->regs[i],
>>>> + .data_size = sizeof(uint32_t),
>>>> + .access = &xilinx_devcfg_regs_info[i],
>>>> + .debug = XILINX_DEVCFG_ERR_DEBUG,
>>>> + .prefix = prefix,
>>>> + .opaque = s,
>>>> + };
>>>> + memory_region_init_io(&r->mem, &devcfg_reg_ops, r, "devcfg-regs", 4);
>>>> + memory_region_add_subregion(&s->iomem, i * 4, &r->mem);
>>>> + }
>>>> +}
>>>> +
>>>> +static void xilinx_devcfg_init(Object *obj)
>>>> +{
>>>> + SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
>>>> + XilinxDevcfg *s = XILINX_DEVCFG(obj);
>>>> +
>>>> + s->timer_bh = qemu_bh_new(xilinx_devcfg_dma_go, s);
>>>> + s->timer = ptimer_init(s->timer_bh);
>>>> +
>>>> + sysbus_init_irq(sbd, &s->irq);
>>>> +
>>>> + memory_region_init(&s->iomem, "devcfg", R_MAX*4);
>>>> + sysbus_init_mmio(sbd, &s->iomem);
>>>> +}
>>>> +
>>>> +static void xilinx_devcfg_class_init(ObjectClass *klass, void *data)
>>>> +{
>>>> + DeviceClass *dc = DEVICE_CLASS(klass);
>>>> +
>>>> + dc->reset = xilinx_devcfg_reset;
>>>> + dc->vmsd = &vmstate_xilinx_devcfg;
>>>> + dc->realize = xilinx_devcfg_realize;
>>>> +}
>>>> +
>>>> +static const TypeInfo xilinx_devcfg_info = {
>>>> + .name = TYPE_XILINX_DEVCFG,
>>>> + .parent = TYPE_SYS_BUS_DEVICE,
>>>> + .instance_size = sizeof(XilinxDevcfg),
>>>> + .instance_init = xilinx_devcfg_init,
>>>> + .class_init = xilinx_devcfg_class_init,
>>>> +};
>>>> +
>>>> +static void xilinx_devcfg_register_types(void)
>>>> +{
>>>> + type_register_static(&xilinx_devcfg_info);
>>>> +}
>>>> +
>>>> +type_init(xilinx_devcfg_register_types)
>>>> --
>>>> 1.8.3.rc1.44.gb387c77.dirty
>>>
>
next prev parent reply other threads:[~2013-05-31 23:34 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-05-24 5:46 [Qemu-devel] [PATCH v3 0/5] Data Driven device registers & Zynq DEVCFG peter.crosthwaite
2013-05-24 5:46 ` [Qemu-devel] [PATCH v3 1/5] bitops: Add ONES macro peter.crosthwaite
2013-05-24 5:47 ` [Qemu-devel] [PATCH v3 2/5] register: Add Register API peter.crosthwaite
2013-05-29 17:52 ` Edgar E. Iglesias
2013-05-24 5:48 ` [Qemu-devel] [PATCH v3 3/5] register: Add Memory API glue peter.crosthwaite
2013-05-24 5:49 ` [Qemu-devel] [PATCH v3 4/5] xilinx_devcfg: Zynq devcfg device model peter.crosthwaite
2013-05-29 8:51 ` Paolo Bonzini
2013-05-29 13:54 ` Peter Crosthwaite
2013-05-29 14:03 ` Paolo Bonzini
2013-05-29 17:04 ` Edgar E. Iglesias
2013-05-29 17:08 ` Paolo Bonzini
2013-05-30 7:15 ` Peter Crosthwaite
2013-05-30 13:08 ` Paolo Bonzini
2013-05-29 17:57 ` Anthony Liguori
2013-05-29 18:52 ` Anthony Liguori
2013-05-30 1:43 ` Peter Crosthwaite
2013-05-30 19:41 ` Anthony Liguori
2013-05-31 23:34 ` Peter Crosthwaite [this message]
2013-05-24 5:49 ` [Qemu-devel] [PATCH v3 5/5] xilinx_zynq: added devcfg to machine model peter.crosthwaite
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAEgOgz6E8reOBra6CUOJw9-JR_=VC0fKhWA_5Ad6RSYRtTh12Q@mail.gmail.com' \
--to=peter.crosthwaite@xilinx.com \
--cc=anthony@codemonkey.ws \
--cc=blauwirbel@gmail.com \
--cc=edgar.iglesias@gmail.com \
--cc=kraxel@redhat.com \
--cc=pbonzini@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).