All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Kiarie <davidkiarie4@gmail.com>
To: Jan Kiszka <jan.kiszka@web.de>
Cc: QEMU Developers <qemu-devel@nongnu.org>,
	Marcel Apfelbaum <marcel@redhat.com>,
	"Michael S. Tsirkin" <mst@redhat.com>,
	Peter Xu <peterx@redhat.com>,
	alex.williamson@redhat.com,
	Valentine Sinitsyn <valentine.sinitsyn@gmail.com>,
	Eduardo Habkost <ehabkost@redhat.com>
Subject: Re: [Qemu-devel] [V12 3/4] hw/i386: Introduce AMD IOMMU
Date: Mon, 4 Jul 2016 08:06:00 +0300	[thread overview]
Message-ID: <CABdVeABO79bNBm-RuO2zw5JpiVDoPLwOM6ssw=Ye9MdbAmz+qQ@mail.gmail.com> (raw)
In-Reply-To: <576AF3E2.4060108@web.de>

On Wed, Jun 22, 2016 at 11:24 PM, Jan Kiszka <jan.kiszka@web.de> wrote:
> On 2016-06-15 14:21, David Kiarie wrote:
>> +
>> +/* System Software might never read from some of this fields but anyways */
>
> No read-modify-write accesses observed in the field? And fields like
> AMDVI_MMIO_STATUS or AMDVI_MMIO_EXT_FEATURES sound a lot like they are
> rather about reading than writing. Misleading comment?

Yeah, misleading comment. AMDVI_MMIO_EXT_FEATURES is read only while
some AMDVI_MMIO_STATUS is r/w1c and yes, I'm enforcing that in the
code.

>
>> +static uint64_t amdvi_mmio_read(void *opaque, hwaddr addr, unsigned size)
>> +{
>> +    AMDVIState *s = opaque;
>> +
>> +    uint64_t val = -1;
>> +    if (addr + size > AMDVI_MMIO_SIZE) {
>> +        trace_amdvi_mmio_read("error: addr outside region: max ",
>> +                (uint64_t)AMDVI_MMIO_SIZE, addr, size);
>> +        return (uint64_t)-1;
>> +    }
>> +
>> +    if (size == 2) {
>> +        val = amdvi_readw(s, addr);
>> +    } else if (size == 4) {
>> +        val = amdvi_readl(s, addr);
>> +    } else if (size == 8) {
>> +        val = amdvi_readq(s, addr);
>> +    }
>> +
>> +    switch (addr & ~0x07) {
>> +    case AMDVI_MMIO_DEVICE_TABLE:
>> +        trace_amdvi_mmio_read("MMIO_DEVICE_TABLE", addr, size, addr & ~0x07);
>> +        break;
>> +
>> +    case AMDVI_MMIO_COMMAND_BASE:
>> +        trace_amdvi_mmio_read("MMIO_COMMAND_BASE", addr, size, addr & ~0x07);
>> +        break;
>> +
>> +    case AMDVI_MMIO_EVENT_BASE:
>> +        trace_amdvi_mmio_read("MMIO_EVENT_BASE", addr, size, addr & ~0x07);
>> +        break;
>> +
>> +    case AMDVI_MMIO_CONTROL:
>> +        trace_amdvi_mmio_read("MMIO_MMIO_CONTROL", addr, size, addr & ~0x07);
>> +        break;
>> +
>> +    case AMDVI_MMIO_EXCL_BASE:
>> +        trace_amdvi_mmio_read("MMIO_EXCL_BASE", addr, size, addr & ~0x07);
>> +        break;
>> +
>> +    case AMDVI_MMIO_EXCL_LIMIT:
>> +        trace_amdvi_mmio_read("MMIO_EXCL_LIMIT", addr, size, addr & ~0x07);
>> +        break;
>> +
>> +    case AMDVI_MMIO_COMMAND_HEAD:
>> +        trace_amdvi_mmio_read("MMIO_COMMAND_HEAD", addr, size, addr & ~0x07);
>> +        break;
>> +
>> +    case AMDVI_MMIO_COMMAND_TAIL:
>> +        trace_amdvi_mmio_read("MMIO_COMMAND_TAIL", addr, size, addr & ~0x07);
>> +        break;
>> +
>> +    case AMDVI_MMIO_EVENT_HEAD:
>> +        trace_amdvi_mmio_read("MMIO_EVENT_HEAD", addr, size, addr & ~0x07);
>> +        break;
>> +
>> +    case AMDVI_MMIO_EVENT_TAIL:
>> +        trace_amdvi_mmio_read("MMIO_EVENT_TAIL", addr, size, addr & ~0x07);
>> +        break;
>> +
>> +    case AMDVI_MMIO_STATUS:
>> +        trace_amdvi_mmio_read("MMIO_STATUS", addr, size, addr & ~0x07);
>> +        break;
>> +
>> +    case AMDVI_MMIO_EXT_FEATURES:
>> +        trace_amdvi_mmio_read("MMIO_EXT_FEATURES", addr, size, addr & ~0x07);
>> +        break;
>
> What about a lookup table for that name?

I can't find an obvious way to index a table given the register address.

>
>> +
>> +    default:
>> +        trace_amdvi_mmio_read("UNHANDLED READ", addr, size, addr & ~0x07);
>> +    }
>> +    return val;
>> +}
>> +
>> +static void amdvi_handle_control_write(AMDVIState *s)
>> +{
>> +    /*
>> +     * read whatever is already written in case
>> +     * software is writing in chucks less than 8 bytes
>> +     */
>> +    unsigned long control = amdvi_readq(s, AMDVI_MMIO_CONTROL);
>> +    s->enabled = !!(control & AMDVI_MMIO_CONTROL_AMDVIEN);
>> +
>> +    s->ats_enabled = !!(control & AMDVI_MMIO_CONTROL_HTTUNEN);
>> +    s->evtlog_enabled = s->enabled && !!(control &
>> +                        AMDVI_MMIO_CONTROL_EVENTLOGEN);
>> +
>> +    s->evtlog_intr = !!(control & AMDVI_MMIO_CONTROL_EVENTINTEN);
>> +    s->completion_wait_intr = !!(control & AMDVI_MMIO_CONTROL_COMWAITINTEN);
>> +    s->cmdbuf_enabled = s->enabled && !!(control &
>> +                        AMDVI_MMIO_CONTROL_CMDBUFLEN);
>> +
>> +    /* update the flags depending on the control register */
>> +    if (s->cmdbuf_enabled) {
>> +        amdvi_orq(s, AMDVI_MMIO_STATUS, AMDVI_MMIO_STATUS_CMDBUF_RUN);
>> +    } else {
>> +        amdvi_and_assignq(s, AMDVI_MMIO_STATUS, ~AMDVI_MMIO_STATUS_CMDBUF_RUN);
>> +    }
>> +    if (s->evtlog_enabled) {
>> +        amdvi_orq(s, AMDVI_MMIO_STATUS, AMDVI_MMIO_STATUS_EVT_RUN);
>> +    } else {
>> +        amdvi_and_assignq(s, AMDVI_MMIO_STATUS, ~AMDVI_MMIO_STATUS_EVT_RUN);
>> +    }
>> +
>> +    trace_amdvi_control_status(control);
>> +
>> +    amdvi_cmdbuf_run(s);
>> +}
>> +
>> +static inline void amdvi_handle_devtab_write(AMDVIState *s)
>> +
>> +{
>> +    uint64_t val = amdvi_readq(s, AMDVI_MMIO_DEVICE_TABLE);
>> +    s->devtab = (val & AMDVI_MMIO_DEVTAB_BASE_MASK);
>> +
>> +    /* set device table length */
>> +    s->devtab_len = ((val & AMDVI_MMIO_DEVTAB_SIZE_MASK) + 1 *
>> +                    (AMDVI_MMIO_DEVTAB_SIZE_UNIT /
>> +                     AMDVI_MMIO_DEVTAB_ENTRY_SIZE));
>> +}
>> +
>> +static inline void amdvi_handle_cmdhead_write(AMDVIState *s)
>> +{
>> +    s->cmdbuf_head = amdvi_readq(s, AMDVI_MMIO_COMMAND_HEAD)
>> +                     & AMDVI_MMIO_CMDBUF_HEAD_MASK;
>> +    amdvi_cmdbuf_run(s);
>> +}
>> +
>> +static inline void amdvi_handle_cmdbase_write(AMDVIState *s)
>> +{
>> +    s->cmdbuf = amdvi_readq(s, AMDVI_MMIO_COMMAND_BASE)
>> +                & AMDVI_MMIO_CMDBUF_BASE_MASK;
>> +    s->cmdbuf_len = 1UL << (s->mmior[AMDVI_MMIO_CMDBUF_SIZE_BYTE]
>> +                    & AMDVI_MMIO_CMDBUF_SIZE_MASK);
>> +    s->cmdbuf_head = s->cmdbuf_tail = 0;
>> +}
>> +
>> +static inline void amdvi_handle_cmdtail_write(AMDVIState *s)
>> +{
>> +    s->cmdbuf_tail = amdvi_readq(s, AMDVI_MMIO_COMMAND_TAIL)
>> +                     & AMDVI_MMIO_CMDBUF_TAIL_MASK;
>> +    amdvi_cmdbuf_run(s);
>> +}
>> +
>> +static inline void amdvi_handle_excllim_write(AMDVIState *s)
>> +{
>> +    uint64_t val = amdvi_readq(s, AMDVI_MMIO_EXCL_LIMIT);
>> +    s->excl_limit = (val & AMDVI_MMIO_EXCL_LIMIT_MASK) |
>> +                    AMDVI_MMIO_EXCL_LIMIT_LOW;
>> +}
>> +
>> +static inline void amdvi_handle_evtbase_write(AMDVIState *s)
>> +{
>> +    uint64_t val = amdvi_readq(s, AMDVI_MMIO_EVENT_BASE);
>> +    s->evtlog = val & AMDVI_MMIO_EVTLOG_BASE_MASK;
>> +    s->evtlog_len = 1UL << (*(uint64_t *)&s->mmior[AMDVI_MMIO_EVTLOG_SIZE_BYTE]
>> +                    & AMDVI_MMIO_EVTLOG_SIZE_MASK);
>> +}
>> +
>> +static inline void amdvi_handle_evttail_write(AMDVIState *s)
>> +{
>> +    uint64_t val = amdvi_readq(s, AMDVI_MMIO_EVENT_TAIL);
>> +    s->evtlog_tail = val & AMDVI_MMIO_EVTLOG_TAIL_MASK;
>> +}
>> +
>> +static inline void amdvi_handle_evthead_write(AMDVIState *s)
>> +{
>> +    uint64_t val = amdvi_readq(s, AMDVI_MMIO_EVENT_HEAD);
>> +    s->evtlog_head = val & AMDVI_MMIO_EVTLOG_HEAD_MASK;
>> +}
>> +
>> +static inline void amdvi_handle_pprbase_write(AMDVIState *s)
>> +{
>> +    uint64_t val = amdvi_readq(s, AMDVI_MMIO_PPR_BASE);
>> +    s->ppr_log = val & AMDVI_MMIO_PPRLOG_BASE_MASK;
>> +    s->pprlog_len = 1UL << (*(uint64_t *)&s->mmior[AMDVI_MMIO_PPRLOG_SIZE_BYTE]
>> +                    & AMDVI_MMIO_PPRLOG_SIZE_MASK);
>> +}
>> +
>> +static inline void amdvi_handle_pprhead_write(AMDVIState *s)
>> +{
>> +    uint64_t val = amdvi_readq(s, AMDVI_MMIO_PPR_HEAD);
>> +    s->pprlog_head = val & AMDVI_MMIO_PPRLOG_HEAD_MASK;
>> +}
>> +
>> +static inline void amdvi_handle_pprtail_write(AMDVIState *s)
>> +{
>> +    uint64_t val = amdvi_readq(s, AMDVI_MMIO_PPR_TAIL);
>> +    s->pprlog_tail = val & AMDVI_MMIO_PPRLOG_TAIL_MASK;
>> +}
>> +
>> +/* FIXME: something might go wrong if System Software writes in chunks
>> + * of one byte but linux writes in chunks of 4 bytes so currently it
>> + * works correctly with linux but will definitely be busted if software
>> + * reads/writes 8 bytes
>
> What does the spec tell us about non-dword accesses? If they aren't
> allowed, filter them out completely at the beginning.

Non-dword accesses are allowed. Spec 2.62

".... Accesses must be aligned to the size of the access and the size
in bytes must be a power
of two. Software may use accesses as small as one byte..... "

Linux uses dword accesses though but even in this case a change in the
order of access whereby the high part of the register is accessed
first then the lower accessed could cause a problem (??)

>
>> + */
>> +static void amdvi_mmio_write(void *opaque, hwaddr addr, uint64_t val,
>> +                             unsigned size)
>> +{
>> +    AMDVIState *s = opaque;
>> +    unsigned long offset = addr & 0x07;
>> +
>> +    if (addr + size > AMDVI_MMIO_SIZE) {
>> +        trace_amdvi_mmio_write("error: addr outside region: max ",
>> +                (uint64_t)AMDVI_MMIO_SIZE, size, val, offset);
>> +        return;
>> +    }
>> +
>> +    switch (addr & ~0x07) {
>> +    case AMDVI_MMIO_CONTROL:
>> +        trace_amdvi_mmio_write("MMIO_CONTROL", addr, size, val, offset);
>> +        if (size == 2) {
>> +            amdvi_writew(s, addr, val);
>> +        } else if (size == 4) {
>> +            amdvi_writel(s, addr,  val);
>> +        } else if (size == 8) {
>> +            amdvi_writeq(s, addr, val);
>> +        }
>
> This pattern repeats and screams for being factored out into a helper
> function.
>
>> +        amdvi_handle_control_write(s);
>> +        break;
>> +
>> +    case AMDVI_MMIO_DEVICE_TABLE:
>> +        trace_amdvi_mmio_write("MMIO_DEVICE_TABLE", addr, size, val, offset);
>> +        if (size == 2) {
>> +            amdvi_writew(s, addr, val);
>> +        } else if (size == 4) {
>> +            amdvi_writel(s, addr, val);
>> +        } else if (size == 8) {
>> +            amdvi_writeq(s, addr, val);
>> +        }
>> +
>> +       /*  set device table address
>> +        *   This also suffers from inability to tell whether software
>> +        *   is done writing
>> +        */
>> +
>> +        if (offset || (size == 8)) {
>> +            amdvi_handle_devtab_write(s);
>> +        }
>> +        break;
>> +
>> +    case AMDVI_MMIO_COMMAND_HEAD:
>> +        trace_amdvi_mmio_write("MMIO_COMMAND_HEAD", addr, size, val, offset);
>> +        if (size == 2) {
>> +            amdvi_writew(s, addr, val);
>> +        } else if (size == 4) {
>> +            amdvi_writel(s, addr, val);
>> +        } else if (size == 8) {
>> +            amdvi_writeq(s, addr, val);
>> +        }
>> +
>> +        amdvi_handle_cmdhead_write(s);
>> +        break;
>> +
>> +    case AMDVI_MMIO_COMMAND_BASE:
>> +        trace_amdvi_mmio_write("MMIO_COMMAND_BASE", addr, size, val, offset);
>> +        if (size == 2) {
>> +            amdvi_writew(s, addr, val);
>> +        } else if (size == 4) {
>> +            amdvi_writel(s, addr, val);
>> +        } else if (size == 8) {
>> +            amdvi_writeq(s, addr, val);
>> +        }
>> +
>> +        /* FIXME - make sure System Software has finished writing incase
>> +         * it writes in chucks less than 8 bytes in a robust way.As for
>> +         * now, this hacks works for the linux driver
>> +         */
>> +        if (offset || (size == 8)) {
>> +            amdvi_handle_cmdbase_write(s);
>> +        }
>> +        break;
>> +
>> +    case AMDVI_MMIO_COMMAND_TAIL:
>> +        trace_amdvi_mmio_write("MMIO_COMMAND_TAIL", addr, size, val, offset);
>> +        if (size == 2) {
>> +            amdvi_writew(s, addr, val);
>> +        } else if (size == 4) {
>> +            amdvi_writel(s, addr, val);
>> +        } else if (size == 8) {
>> +            amdvi_writeq(s, addr, val);
>> +        }
>> +        amdvi_handle_cmdtail_write(s);
>> +        break;
>> +
>> +    case AMDVI_MMIO_EVENT_BASE:
>> +        trace_amdvi_mmio_write("MMIO_EVENT_BASE", addr, size, val, offset);
>> +        if (size == 2) {
>> +            amdvi_writew(s, addr, val);
>> +        } else if (size == 4) {
>> +            amdvi_writel(s, addr, val);
>> +        } else if (size == 8) {
>> +            amdvi_writeq(s, addr, val);
>> +        }
>> +        amdvi_handle_evtbase_write(s);
>> +        break;
>> +
>> +    case AMDVI_MMIO_EVENT_HEAD:
>> +        trace_amdvi_mmio_write("MMIO_EVENT_HEAD", addr, size, val, offset);
>> +        if (size == 2) {
>> +            amdvi_writew(s, addr, val);
>> +        } else if (size == 4) {
>> +            amdvi_writel(s, addr, val);
>> +        } else if (size == 8) {
>> +            amdvi_writeq(s, addr, val);
>> +        }
>> +        amdvi_handle_evthead_write(s);
>> +        break;
>> +
>> +    case AMDVI_MMIO_EVENT_TAIL:
>> +        trace_amdvi_mmio_write("MMIO_EVENT_TAIL", addr, size, val, offset);
>> +        if (size == 2) {
>> +            amdvi_writew(s, addr, val);
>> +        } else if (size == 4) {
>> +            amdvi_writel(s, addr, val);
>> +        } else if (size == 8) {
>> +            amdvi_writeq(s, addr, val);
>> +        }
>> +        amdvi_handle_evttail_write(s);
>> +        break;
>> +
>> +    case AMDVI_MMIO_EXCL_LIMIT:
>> +        trace_amdvi_mmio_write("MMIO_EXCL_LIMIT", addr, size, val, offset);
>> +        if (size == 2) {
>> +            amdvi_writew(s, addr, val);
>> +        } else if (size == 4) {
>> +            amdvi_writel(s, addr, val);
>> +        } else if (size == 8) {
>> +            amdvi_writeq(s, addr, val);
>> +        }
>> +        amdvi_handle_excllim_write(s);
>> +        break;
>> +
>> +        /* PPR log base - unused for now */
>> +    case AMDVI_MMIO_PPR_BASE:
>> +        trace_amdvi_mmio_write("MMIO_PPR_BASE", addr, size, val, offset);
>> +        if (size == 2) {
>> +            amdvi_writew(s, addr, val);
>> +        } else if (size == 4) {
>> +            amdvi_writel(s, addr, val);
>> +        } else if (size == 8) {
>> +            amdvi_writeq(s, addr, val);
>> +        }
>> +        amdvi_handle_pprbase_write(s);
>> +        break;
>> +        /* PPR log head - also unused for now */
>> +    case AMDVI_MMIO_PPR_HEAD:
>> +        trace_amdvi_mmio_write("MMIO_PPR_HEAD", addr, size, val, offset);
>> +        if (size == 2) {
>> +            amdvi_writew(s, addr, val);
>> +        } else if (size == 4) {
>> +            amdvi_writel(s, addr, val);
>> +        } else if (size == 8) {
>> +            amdvi_writeq(s, addr, val);
>> +        }
>> +        amdvi_handle_pprhead_write(s);
>> +        break;
>> +        /* PPR log tail - unused for now */
>> +    case AMDVI_MMIO_PPR_TAIL:
>> +        trace_amdvi_mmio_write("MMIO_PPR_TAIL", addr, size, val, offset);
>> +        if (size == 2) {
>> +            amdvi_writew(s, addr, val);
>> +        } else if (size == 4) {
>> +            amdvi_writel(s, addr, val);
>> +        } else if (size == 8) {
>> +            amdvi_writeq(s, addr, val);
>> +        }
>> +        amdvi_handle_pprtail_write(s);
>> +        break;
>> +
>> +        /* ignore write to ext_features */
>> +    default:
>> +        trace_amdvi_mmio_write("UNHANDLED MMIO", addr, size, val, offset);
>> +    }
>> +
>> +}
>> +
>> +
>> +/* PCI SIG constants */
>> +#define PCI_BUS_MAX 256
>> +#define PCI_SLOT_MAX 32
>> +#define PCI_FUNC_MAX 8
>> +#define PCI_DEVFN_MAX 256
>
> Shouldn't those four go to the pci header?

The macros/defines in PCI header are picked from linux while some of
these are not picked from linux. I'v prefixed them with AMDVI_ though.

>
>> +
>> +/* IOTLB */
>> +#define AMDVI_IOTLB_MAX_SIZE 1024
>> +#define AMDVI_DEVID_SHIFT    36
>> +
>> +/* extended feature support */
>> +#define AMDVI_EXT_FEATURES (AMDVI_FEATURE_PREFETCH | AMDVI_FEATURE_PPR | \
>> +        AMDVI_FEATURE_IA | AMDVI_FEATURE_GT | AMDVI_FEATURE_GA | \
>> +        AMDVI_FEATURE_HE | AMDVI_GATS_MODE | AMDVI_HATS_MODE)
>> +
>> +
>> +    /* IOTLB */
>> +    GHashTable *iotlb;
>> +} AMDVIState;
>> +
>> +#endif
>>
>
> I didn't look for the AMDVi logic itself, and I still need to redo some
> test myself (but that may take a while). Except for the few remarks, the
> code looks for me like being in pretty good shape!
>
> Jan
>

  reply	other threads:[~2016-07-04  5:06 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-06-15 12:21 [Qemu-devel] [V12 0/4] AMD IOMMU David Kiarie
2016-06-15 12:21 ` [Qemu-devel] [V12 1/4] hw/pci: Prepare for " David Kiarie
2016-06-22 19:53   ` Jan Kiszka
2016-06-15 12:21 ` [Qemu-devel] [V12 2/4] trace-events: Add AMD IOMMU trace events David Kiarie
2016-06-15 12:21 ` [Qemu-devel] [V12 3/4] hw/i386: Introduce AMD IOMMU David Kiarie
2016-06-22 20:24   ` Jan Kiszka
2016-07-04  5:06     ` David Kiarie [this message]
2016-07-04  5:41       ` Jan Kiszka
2016-07-04  5:49         ` David Kiarie
2016-07-04  5:57           ` Jan Kiszka
2016-07-08  7:01         ` David Kiarie
2016-07-08  9:51           ` Jan Kiszka
2016-06-15 13:15 ` [Qemu-devel] [V12 0/4] " Jan Kiszka
2016-06-15 14:26 ` Eduardo Habkost
2016-06-15 17:07   ` David Kiarie
2016-06-15 17:13     ` Jan Kiszka
     [not found] ` <1465993312-18119-5-git-send-email-davidkiarie4@gmail.com>
2016-06-22 20:25   ` [Qemu-devel] [V12 4/4] hw/i386: AMD IOMMU IVRS table Jan Kiszka
2016-07-04 20:33   ` Michael S. Tsirkin
2016-07-08  7:05     ` David Kiarie

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='CABdVeABO79bNBm-RuO2zw5JpiVDoPLwOM6ssw=Ye9MdbAmz+qQ@mail.gmail.com' \
    --to=davidkiarie4@gmail.com \
    --cc=alex.williamson@redhat.com \
    --cc=ehabkost@redhat.com \
    --cc=jan.kiszka@web.de \
    --cc=marcel@redhat.com \
    --cc=mst@redhat.com \
    --cc=peterx@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=valentine.sinitsyn@gmail.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.