diff mbox series

[v6,6/7] hw/cxl/events: Add injection of DRAM events

Message ID 20230519143043.30191-7-Jonathan.Cameron@huawei.com (mailing list archive)
State New, archived
Headers show
Series QEMU CXL Provide mock CXL events and irq support | expand

Commit Message

Jonathan Cameron May 19, 2023, 2:30 p.m. UTC
Defined in CXL r3.0 8.2.9.2.1.2 DRAM Event Record, this event
provides information related to DRAM devices.

Example injection command in QMP:

{ "execute": "cxl-inject-dram-event",
    "arguments": {
        "path": "/machine/peripheral/cxl-mem0",
        "log": "informational",
        "flags": 1,
        "physaddr": 1000,
        "descriptor": 3,
        "type": 3,
        "transaction-type": 192,
        "channel": 3,
        "rank": 17,
        "nibble-mask": 37421234,
        "bank-group": 7,
        "bank": 11,
        "row": 2,
        "column": 77,
        "correction-mask": [33, 44, 55,66]
    }}

Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 hw/mem/cxl_type3.c          | 116 ++++++++++++++++++++++++++++++++++++
 hw/mem/cxl_type3_stubs.c    |  13 ++++
 include/hw/cxl/cxl_events.h |  23 +++++++
 qapi/cxl.json               |  35 +++++++++++
 4 files changed, 187 insertions(+)

Comments

Philippe Mathieu-Daudé May 19, 2023, 3:34 p.m. UTC | #1
Hi Jonathan,

On 19/5/23 16:30, Jonathan Cameron wrote:
> Defined in CXL r3.0 8.2.9.2.1.2 DRAM Event Record, this event
> provides information related to DRAM devices.
> 
> Example injection command in QMP:
> 
> { "execute": "cxl-inject-dram-event",
>      "arguments": {
>          "path": "/machine/peripheral/cxl-mem0",
>          "log": "informational",
>          "flags": 1,
>          "physaddr": 1000,
>          "descriptor": 3,
>          "type": 3,
>          "transaction-type": 192,
>          "channel": 3,
>          "rank": 17,
>          "nibble-mask": 37421234,
>          "bank-group": 7,
>          "bank": 11,
>          "row": 2,
>          "column": 77,
>          "correction-mask": [33, 44, 55,66]
>      }}
> 
> Reviewed-by: Ira Weiny <ira.weiny@intel.com>
> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> ---
>   hw/mem/cxl_type3.c          | 116 ++++++++++++++++++++++++++++++++++++
>   hw/mem/cxl_type3_stubs.c    |  13 ++++
>   include/hw/cxl/cxl_events.h |  23 +++++++
>   qapi/cxl.json               |  35 +++++++++++
>   4 files changed, 187 insertions(+)


> diff --git a/qapi/cxl.json b/qapi/cxl.json
> index 7e1e6257ce..5e82097e76 100644
> --- a/qapi/cxl.json
> +++ b/qapi/cxl.json
> @@ -55,6 +55,41 @@
>               '*device': 'uint32', '*component-id': 'str'
>               }}
>   
> +##
> +# @cxl-inject-dram-event:
> +#
> +# Inject an event record for a DRAM Event (CXL r3.0 8.2.9.2.1.2)
> +# This event type is reported via one of the event logs specified via
> +# the log parameter.
> +#
> +# @path: CXL type 3 device canonical QOM path
> +# @log: Event Log to add the event to
> +# @flags: header flags
> +# @physaddr: Physical Address

Could this be a clearer description?

"Physical Address (relative to @path device)"

> +# @descriptor: Descriptor
> +# @type: Type
> +# @transaction-type: Transaction Type
> +# @channel: Channel
> +# @rank: Rank
> +# @nibble-mask: Identify one or more nibbles that the error affects

> +# @bank-group: Bank group
> +# @bank: Bank
> +# @row: Row
> +# @column: Column

Why do we need bank/raw/col if we have physaddr?

These are optional. Shouldn't we check they are valid
in qmp_cxl_inject_dram_event()? (No clue, just wondering
if there is some duplication here).

> +# @correction-mask: Bits within each nibble. Used in order of bits set
> +#                   in the nibble-mask.  Up to 4 nibbles may be covered.
> +#
> +# Since: 8.1
> +##
> +{ 'command': 'cxl-inject-dram-event',
> +  'data': { 'path': 'str', 'log': 'CxlEventLog', 'flags': 'uint8',
> +            'physaddr': 'uint64', 'descriptor': 'uint8',
> +            'type': 'uint8', 'transaction-type': 'uint8',
> +            '*channel': 'uint8', '*rank': 'uint8', '*nibble-mask': 'uint32',
> +            '*bank-group': 'uint8', '*bank': 'uint8', '*row': 'uint32',
> +            '*column': 'uint16', '*correction-mask': [ 'uint64' ]
> +           }}
> +
>   ##
>   # @cxl-inject-poison:
>   #
Jonathan Cameron May 19, 2023, 3:45 p.m. UTC | #2
On Fri, 19 May 2023 17:34:20 +0200
Philippe Mathieu-Daudé <philmd@linaro.org> wrote:

> Hi Jonathan,
> 
> On 19/5/23 16:30, Jonathan Cameron wrote:
> > Defined in CXL r3.0 8.2.9.2.1.2 DRAM Event Record, this event
> > provides information related to DRAM devices.
> > 
> > Example injection command in QMP:
> > 
> > { "execute": "cxl-inject-dram-event",
> >      "arguments": {
> >          "path": "/machine/peripheral/cxl-mem0",
> >          "log": "informational",
> >          "flags": 1,
> >          "physaddr": 1000,
> >          "descriptor": 3,
> >          "type": 3,
> >          "transaction-type": 192,
> >          "channel": 3,
> >          "rank": 17,
> >          "nibble-mask": 37421234,
> >          "bank-group": 7,
> >          "bank": 11,
> >          "row": 2,
> >          "column": 77,
> >          "correction-mask": [33, 44, 55,66]
> >      }}
> > 
> > Reviewed-by: Ira Weiny <ira.weiny@intel.com>
> > Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> > ---
> >   hw/mem/cxl_type3.c          | 116 ++++++++++++++++++++++++++++++++++++
> >   hw/mem/cxl_type3_stubs.c    |  13 ++++
> >   include/hw/cxl/cxl_events.h |  23 +++++++
> >   qapi/cxl.json               |  35 +++++++++++
> >   4 files changed, 187 insertions(+)  
> 
> 
> > diff --git a/qapi/cxl.json b/qapi/cxl.json
> > index 7e1e6257ce..5e82097e76 100644
> > --- a/qapi/cxl.json
> > +++ b/qapi/cxl.json
> > @@ -55,6 +55,41 @@
> >               '*device': 'uint32', '*component-id': 'str'
> >               }}
> >   
> > +##
> > +# @cxl-inject-dram-event:
> > +#
> > +# Inject an event record for a DRAM Event (CXL r3.0 8.2.9.2.1.2)
> > +# This event type is reported via one of the event logs specified via
> > +# the log parameter.
> > +#
> > +# @path: CXL type 3 device canonical QOM path
> > +# @log: Event Log to add the event to
> > +# @flags: header flags
> > +# @physaddr: Physical Address  
> 
> Could this be a clearer description?
> 
> "Physical Address (relative to @path device)"

Makes sense.

> 
> > +# @descriptor: Descriptor
> > +# @type: Type
> > +# @transaction-type: Transaction Type
> > +# @channel: Channel
> > +# @rank: Rank
> > +# @nibble-mask: Identify one or more nibbles that the error affects  
> 
> > +# @bank-group: Bank group
> > +# @bank: Bank
> > +# @row: Row
> > +# @column: Column  
> 
> Why do we need bank/raw/col if we have physaddr?

Yes we need them. We don't know the device geometry / internal interleaving
/ address hashing applied to smooth out access patterns etc.

I really don't want to put that level of complexity into the command
line for a device - so just left it to the test tools to squirt in
something valid.

> 
> These are optional. Shouldn't we check they are valid
> in qmp_cxl_inject_dram_event()? (No clue, just wondering
> if there is some duplication here).

Validation is really hard for these as depends on the above
device implementation complexity.  There is a note on trying to
strike the balance in the cover letter. I'm not sure I have it
right! They are optional in records coming from the device, so
we set validity flags for them in the device record.

Aim here is to be able to inject whatever might be seen on a real device
without having to have QEMU emulate a bunch of device internals
such as mappings to particular DRAM FRU, chip, column, row etc.


> 
> > +# @correction-mask: Bits within each nibble. Used in order of bits set
> > +#                   in the nibble-mask.  Up to 4 nibbles may be covered.
> > +#
> > +# Since: 8.1
> > +##
> > +{ 'command': 'cxl-inject-dram-event',
> > +  'data': { 'path': 'str', 'log': 'CxlEventLog', 'flags': 'uint8',
> > +            'physaddr': 'uint64', 'descriptor': 'uint8',
> > +            'type': 'uint8', 'transaction-type': 'uint8',
> > +            '*channel': 'uint8', '*rank': 'uint8', '*nibble-mask': 'uint32',
> > +            '*bank-group': 'uint8', '*bank': 'uint8', '*row': 'uint32',
> > +            '*column': 'uint16', '*correction-mask': [ 'uint64' ]
> > +           }}
> > +
> >   ##
> >   # @cxl-inject-poison:
> >   #  
>
Philippe Mathieu-Daudé May 19, 2023, 3:57 p.m. UTC | #3
On 19/5/23 17:45, Jonathan Cameron wrote:
> On Fri, 19 May 2023 17:34:20 +0200
> Philippe Mathieu-Daudé <philmd@linaro.org> wrote:
> 
>> Hi Jonathan,
>>
>> On 19/5/23 16:30, Jonathan Cameron wrote:
>>> Defined in CXL r3.0 8.2.9.2.1.2 DRAM Event Record, this event
>>> provides information related to DRAM devices.
>>>
>>> Example injection command in QMP:
>>>
>>> { "execute": "cxl-inject-dram-event",
>>>       "arguments": {
>>>           "path": "/machine/peripheral/cxl-mem0",
>>>           "log": "informational",
>>>           "flags": 1,
>>>           "physaddr": 1000,
>>>           "descriptor": 3,
>>>           "type": 3,
>>>           "transaction-type": 192,
>>>           "channel": 3,
>>>           "rank": 17,
>>>           "nibble-mask": 37421234,
>>>           "bank-group": 7,
>>>           "bank": 11,
>>>           "row": 2,
>>>           "column": 77,
>>>           "correction-mask": [33, 44, 55,66]
>>>       }}
>>>
>>> Reviewed-by: Ira Weiny <ira.weiny@intel.com>
>>> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
>>> ---
>>>    hw/mem/cxl_type3.c          | 116 ++++++++++++++++++++++++++++++++++++
>>>    hw/mem/cxl_type3_stubs.c    |  13 ++++
>>>    include/hw/cxl/cxl_events.h |  23 +++++++
>>>    qapi/cxl.json               |  35 +++++++++++
>>>    4 files changed, 187 insertions(+)
>>
>>
>>> diff --git a/qapi/cxl.json b/qapi/cxl.json
>>> index 7e1e6257ce..5e82097e76 100644
>>> --- a/qapi/cxl.json
>>> +++ b/qapi/cxl.json
>>> @@ -55,6 +55,41 @@
>>>                '*device': 'uint32', '*component-id': 'str'
>>>                }}
>>>    
>>> +##
>>> +# @cxl-inject-dram-event:
>>> +#
>>> +# Inject an event record for a DRAM Event (CXL r3.0 8.2.9.2.1.2)
>>> +# This event type is reported via one of the event logs specified via
>>> +# the log parameter.
>>> +#
>>> +# @path: CXL type 3 device canonical QOM path
>>> +# @log: Event Log to add the event to
>>> +# @flags: header flags
>>> +# @physaddr: Physical Address
>>
>> Could this be a clearer description?
>>
>> "Physical Address (relative to @path device)"
> 
> Makes sense.
> 
>>
>>> +# @descriptor: Descriptor
>>> +# @type: Type
>>> +# @transaction-type: Transaction Type
>>> +# @channel: Channel
>>> +# @rank: Rank
>>> +# @nibble-mask: Identify one or more nibbles that the error affects
>>
>>> +# @bank-group: Bank group
>>> +# @bank: Bank
>>> +# @row: Row
>>> +# @column: Column
>>
>> Why do we need bank/raw/col if we have physaddr?
> 
> Yes we need them. We don't know the device geometry / internal interleaving
> / address hashing applied to smooth out access patterns etc.
> 
> I really don't want to put that level of complexity into the command
> line for a device - so just left it to the test tools to squirt in
> something valid.
> 
>>
>> These are optional. Shouldn't we check they are valid
>> in qmp_cxl_inject_dram_event()? (No clue, just wondering
>> if there is some duplication here).
> 
> Validation is really hard for these as depends on the above
> device implementation complexity.  There is a note on trying to
> strike the balance in the cover letter. I'm not sure I have it
> right! They are optional in records coming from the device, so
> we set validity flags for them in the device record.
> 
> Aim here is to be able to inject whatever might be seen on a real device
> without having to have QEMU emulate a bunch of device internals
> such as mappings to particular DRAM FRU, chip, column, row etc.

I was expecting some check like:

   ROUND_DOWN(physaddr, 8) == bank * row * column * 8

But indeed this isn't really useful for your tests, since we want to
check sanity for values from the guest, not from human via QMP.
So FWIW overall LGTM.

> 
> 
>>
>>> +# @correction-mask: Bits within each nibble. Used in order of bits set
>>> +#                   in the nibble-mask.  Up to 4 nibbles may be covered.
>>> +#
>>> +# Since: 8.1
>>> +##
>>> +{ 'command': 'cxl-inject-dram-event',
>>> +  'data': { 'path': 'str', 'log': 'CxlEventLog', 'flags': 'uint8',
>>> +            'physaddr': 'uint64', 'descriptor': 'uint8',
>>> +            'type': 'uint8', 'transaction-type': 'uint8',
>>> +            '*channel': 'uint8', '*rank': 'uint8', '*nibble-mask': 'uint32',
>>> +            '*bank-group': 'uint8', '*bank': 'uint8', '*row': 'uint32',
>>> +            '*column': 'uint16', '*correction-mask': [ 'uint64' ]
>>> +           }}
>>> +
>>>    ##
>>>    # @cxl-inject-poison:
>>>    #
>>
>
Jonathan Cameron May 22, 2023, 2:57 p.m. UTC | #4
On Fri, 19 May 2023 17:57:31 +0200
Philippe Mathieu-Daudé <philmd@linaro.org> wrote:

> On 19/5/23 17:45, Jonathan Cameron wrote:
> > On Fri, 19 May 2023 17:34:20 +0200
> > Philippe Mathieu-Daudé <philmd@linaro.org> wrote:
> >   
> >> Hi Jonathan,
> >>
> >> On 19/5/23 16:30, Jonathan Cameron wrote:  
> >>> Defined in CXL r3.0 8.2.9.2.1.2 DRAM Event Record, this event
> >>> provides information related to DRAM devices.
> >>>
> >>> Example injection command in QMP:
> >>>
> >>> { "execute": "cxl-inject-dram-event",
> >>>       "arguments": {
> >>>           "path": "/machine/peripheral/cxl-mem0",
> >>>           "log": "informational",
> >>>           "flags": 1,
> >>>           "physaddr": 1000,
> >>>           "descriptor": 3,
> >>>           "type": 3,
> >>>           "transaction-type": 192,
> >>>           "channel": 3,
> >>>           "rank": 17,
> >>>           "nibble-mask": 37421234,
> >>>           "bank-group": 7,
> >>>           "bank": 11,
> >>>           "row": 2,
> >>>           "column": 77,
> >>>           "correction-mask": [33, 44, 55,66]
> >>>       }}
> >>>
> >>> Reviewed-by: Ira Weiny <ira.weiny@intel.com>
> >>> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> >>> ---
> >>>    hw/mem/cxl_type3.c          | 116 ++++++++++++++++++++++++++++++++++++
> >>>    hw/mem/cxl_type3_stubs.c    |  13 ++++
> >>>    include/hw/cxl/cxl_events.h |  23 +++++++
> >>>    qapi/cxl.json               |  35 +++++++++++
> >>>    4 files changed, 187 insertions(+)  
> >>
> >>  
> >>> diff --git a/qapi/cxl.json b/qapi/cxl.json
> >>> index 7e1e6257ce..5e82097e76 100644
> >>> --- a/qapi/cxl.json
> >>> +++ b/qapi/cxl.json
> >>> @@ -55,6 +55,41 @@
> >>>                '*device': 'uint32', '*component-id': 'str'
> >>>                }}
> >>>    
> >>> +##
> >>> +# @cxl-inject-dram-event:
> >>> +#
> >>> +# Inject an event record for a DRAM Event (CXL r3.0 8.2.9.2.1.2)
> >>> +# This event type is reported via one of the event logs specified via
> >>> +# the log parameter.
> >>> +#
> >>> +# @path: CXL type 3 device canonical QOM path
> >>> +# @log: Event Log to add the event to
> >>> +# @flags: header flags
> >>> +# @physaddr: Physical Address  
> >>
> >> Could this be a clearer description?
> >>
> >> "Physical Address (relative to @path device)"  
> > 
> > Makes sense.

This got changed to dpa to avoid some confusion with other uses of
address and DPA is tightly defined in the CXL specification.

> >   
> >>  
> >>> +# @descriptor: Descriptor
> >>> +# @type: Type
> >>> +# @transaction-type: Transaction Type
> >>> +# @channel: Channel
> >>> +# @rank: Rank
> >>> +# @nibble-mask: Identify one or more nibbles that the error affects  
> >>  
> >>> +# @bank-group: Bank group
> >>> +# @bank: Bank
> >>> +# @row: Row
> >>> +# @column: Column  
> >>
> >> Why do we need bank/raw/col if we have physaddr?  
> > 
> > Yes we need them. We don't know the device geometry / internal interleaving
> > / address hashing applied to smooth out access patterns etc.
> > 
> > I really don't want to put that level of complexity into the command
> > line for a device - so just left it to the test tools to squirt in
> > something valid.
> >   
> >>
> >> These are optional. Shouldn't we check they are valid
> >> in qmp_cxl_inject_dram_event()? (No clue, just wondering
> >> if there is some duplication here).  
> > 
> > Validation is really hard for these as depends on the above
> > device implementation complexity.  There is a note on trying to
> > strike the balance in the cover letter. I'm not sure I have it
> > right! They are optional in records coming from the device, so
> > we set validity flags for them in the device record.
> > 
> > Aim here is to be able to inject whatever might be seen on a real device
> > without having to have QEMU emulate a bunch of device internals
> > such as mappings to particular DRAM FRU, chip, column, row etc.  
> 
> I was expecting some check like:
> 
>    ROUND_DOWN(physaddr, 8) == bank * row * column * 8
> 
Got it.  That doesn't work unfortunately because there may well be a bunch
of interleaving and hashing inbetween.

> But indeed this isn't really useful for your tests, since we want to
> check sanity for values from the guest, not from human via QMP.
> So FWIW overall LGTM.

Great

Jonathan
> 
> > 
> >   
> >>  
> >>> +# @correction-mask: Bits within each nibble. Used in order of bits set
> >>> +#                   in the nibble-mask.  Up to 4 nibbles may be covered.
> >>> +#
> >>> +# Since: 8.1
> >>> +##
> >>> +{ 'command': 'cxl-inject-dram-event',
> >>> +  'data': { 'path': 'str', 'log': 'CxlEventLog', 'flags': 'uint8',
> >>> +            'physaddr': 'uint64', 'descriptor': 'uint8',
> >>> +            'type': 'uint8', 'transaction-type': 'uint8',
> >>> +            '*channel': 'uint8', '*rank': 'uint8', '*nibble-mask': 'uint32',
> >>> +            '*bank-group': 'uint8', '*bank': 'uint8', '*row': 'uint32',
> >>> +            '*column': 'uint16', '*correction-mask': [ 'uint64' ]
> >>> +           }}
> >>> +
> >>>    ##
> >>>    # @cxl-inject-poison:
> >>>    #  
> >>  
> >   
>
Ira Weiny May 23, 2023, 1:56 p.m. UTC | #5
Jonathan Cameron wrote:
> On Fri, 19 May 2023 17:34:20 +0200
> Philippe Mathieu-Daudé <philmd@linaro.org> wrote:
> 
> > Hi Jonathan,
> > 
> > On 19/5/23 16:30, Jonathan Cameron wrote:
> > > Defined in CXL r3.0 8.2.9.2.1.2 DRAM Event Record, this event
> > > provides information related to DRAM devices.
> > > 
> > > Example injection command in QMP:
> > > 
> > > { "execute": "cxl-inject-dram-event",
> > >      "arguments": {
> > >          "path": "/machine/peripheral/cxl-mem0",
> > >          "log": "informational",
> > >          "flags": 1,
> > >          "physaddr": 1000,
> > >          "descriptor": 3,
> > >          "type": 3,
> > >          "transaction-type": 192,
> > >          "channel": 3,
> > >          "rank": 17,
> > >          "nibble-mask": 37421234,
> > >          "bank-group": 7,
> > >          "bank": 11,
> > >          "row": 2,
> > >          "column": 77,
> > >          "correction-mask": [33, 44, 55,66]
> > >      }}
> > > 
> > > Reviewed-by: Ira Weiny <ira.weiny@intel.com>
> > > Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> > > ---
> > >   hw/mem/cxl_type3.c          | 116 ++++++++++++++++++++++++++++++++++++
> > >   hw/mem/cxl_type3_stubs.c    |  13 ++++
> > >   include/hw/cxl/cxl_events.h |  23 +++++++
> > >   qapi/cxl.json               |  35 +++++++++++
> > >   4 files changed, 187 insertions(+)  
> > 
> > 
> > > diff --git a/qapi/cxl.json b/qapi/cxl.json
> > > index 7e1e6257ce..5e82097e76 100644
> > > --- a/qapi/cxl.json
> > > +++ b/qapi/cxl.json
> > > @@ -55,6 +55,41 @@
> > >               '*device': 'uint32', '*component-id': 'str'
> > >               }}
> > >   
> > > +##
> > > +# @cxl-inject-dram-event:
> > > +#
> > > +# Inject an event record for a DRAM Event (CXL r3.0 8.2.9.2.1.2)
> > > +# This event type is reported via one of the event logs specified via
> > > +# the log parameter.
> > > +#
> > > +# @path: CXL type 3 device canonical QOM path
> > > +# @log: Event Log to add the event to
> > > +# @flags: header flags
> > > +# @physaddr: Physical Address  
> > 
> > Could this be a clearer description?
> > 
> > "Physical Address (relative to @path device)"
> 
> Makes sense.
> 
> > 
> > > +# @descriptor: Descriptor
> > > +# @type: Type
> > > +# @transaction-type: Transaction Type
> > > +# @channel: Channel
> > > +# @rank: Rank
> > > +# @nibble-mask: Identify one or more nibbles that the error affects  
> > 
> > > +# @bank-group: Bank group
> > > +# @bank: Bank
> > > +# @row: Row
> > > +# @column: Column  
> > 
> > Why do we need bank/raw/col if we have physaddr?
> 
> Yes we need them. We don't know the device geometry / internal interleaving
> / address hashing applied to smooth out access patterns etc.
> 
> I really don't want to put that level of complexity into the command
> line for a device - so just left it to the test tools to squirt in
> something valid.
> 

I agree.  I don't think anyone is trying to emulate their exact memory
device internals.  However, it does not prevent them from doing so with
additional device types and/or qemu flags to get that behavior.

Ira
diff mbox series

Patch

diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c
index d5fd3ccbc1..0353425b17 100644
--- a/hw/mem/cxl_type3.c
+++ b/hw/mem/cxl_type3.c
@@ -1196,6 +1196,11 @@  static const QemuUUID gen_media_uuid = {
                  0x85, 0xa9, 0x08, 0x8b, 0x16, 0x21, 0xeb, 0xa6),
 };
 
+static const QemuUUID dram_uuid = {
+    .data = UUID(0x601dcbb3, 0x9c06, 0x4eab, 0xb8, 0xaf,
+                 0x4e, 0x9b, 0xfb, 0x5c, 0x96, 0x24),
+};
+
 #define CXL_GMER_VALID_CHANNEL                          BIT(0)
 #define CXL_GMER_VALID_RANK                             BIT(1)
 #define CXL_GMER_VALID_DEVICE                           BIT(2)
@@ -1292,6 +1297,117 @@  void qmp_cxl_inject_gen_media_event(const char *path, CxlEventLog log,
     }
 }
 
+#define CXL_DRAM_VALID_CHANNEL                          BIT(0)
+#define CXL_DRAM_VALID_RANK                             BIT(1)
+#define CXL_DRAM_VALID_NIBBLE_MASK                      BIT(2)
+#define CXL_DRAM_VALID_BANK_GROUP                       BIT(3)
+#define CXL_DRAM_VALID_BANK                             BIT(4)
+#define CXL_DRAM_VALID_ROW                              BIT(5)
+#define CXL_DRAM_VALID_COLUMN                           BIT(6)
+#define CXL_DRAM_VALID_CORRECTION_MASK                  BIT(7)
+
+void qmp_cxl_inject_dram_event(const char *path, CxlEventLog log, uint8_t flags,
+                               uint64_t physaddr, uint8_t descriptor,
+                               uint8_t type, uint8_t transaction_type,
+                               bool has_channel, uint8_t channel,
+                               bool has_rank, uint8_t rank,
+                               bool has_nibble_mask, uint32_t nibble_mask,
+                               bool has_bank_group, uint8_t bank_group,
+                               bool has_bank, uint8_t bank,
+                               bool has_row, uint32_t row,
+                               bool has_column, uint16_t column,
+                               bool has_correction_mask, uint64List *correction_mask,
+                               Error **errp)
+{
+    Object *obj = object_resolve_path(path, NULL);
+    CXLEventDram dram;
+    CXLEventRecordHdr *hdr = &dram.hdr;
+    CXLDeviceState *cxlds;
+    CXLType3Dev *ct3d;
+    uint16_t valid_flags = 0;
+    uint8_t enc_log;
+    int rc;
+
+    if (!obj) {
+        error_setg(errp, "Unable to resolve path");
+        return;
+    }
+    if (!object_dynamic_cast(obj, TYPE_CXL_TYPE3)) {
+        error_setg(errp, "Path does not point to a CXL type 3 device");
+        return;
+    }
+    ct3d = CXL_TYPE3(obj);
+    cxlds = &ct3d->cxl_dstate;
+
+    rc = ct3d_qmp_cxl_event_log_enc(log);
+    if (rc < 0) {
+        error_setg(errp, "Unhandled error log type");
+        return;
+    }
+    enc_log = rc;
+
+    memset(&dram, 0, sizeof(dram));
+    cxl_assign_event_header(hdr, &dram_uuid, flags, sizeof(dram),
+                            cxl_device_get_timestamp(&ct3d->cxl_dstate));
+    stq_le_p(&dram.phys_addr, physaddr);
+    dram.descriptor = descriptor;
+    dram.type = type;
+    dram.transaction_type = transaction_type;
+
+    if (has_channel) {
+        dram.channel = channel;
+        valid_flags |= CXL_DRAM_VALID_CHANNEL;
+    }
+
+    if (has_rank) {
+        dram.rank = rank;
+        valid_flags |= CXL_DRAM_VALID_RANK;
+    }
+
+    if (has_nibble_mask) {
+        st24_le_p(dram.nibble_mask, nibble_mask);
+        valid_flags |= CXL_DRAM_VALID_NIBBLE_MASK;
+    }
+
+    if (has_bank_group) {
+        dram.bank_group = bank_group;
+        valid_flags |= CXL_DRAM_VALID_BANK_GROUP;
+    }
+
+    if (has_bank) {
+        dram.bank = bank;
+        valid_flags |= CXL_DRAM_VALID_BANK;
+    }
+
+    if (has_row) {
+        st24_le_p(dram.row, row);
+        valid_flags |= CXL_DRAM_VALID_ROW;
+    }
+
+    if (has_column) {
+        stw_le_p(&dram.column, column);
+        valid_flags |= CXL_DRAM_VALID_COLUMN;
+    }
+
+    if (has_correction_mask) {
+        int count = 0;
+        while (correction_mask && count < 4) {
+            stq_le_p(&dram.correction_mask[count],
+                     correction_mask->value);
+            count++;
+            correction_mask = correction_mask->next;
+        }
+        valid_flags |= CXL_DRAM_VALID_CORRECTION_MASK;
+    }
+
+    stw_le_p(&dram.validity_flags, valid_flags);
+
+    if (cxl_event_insert(cxlds, enc_log, (CXLEventRecordRaw *)&dram)) {
+        cxl_event_irq_assert(ct3d);
+    }
+    return;
+}
+
 static void ct3_class_init(ObjectClass *oc, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/mem/cxl_type3_stubs.c b/hw/mem/cxl_type3_stubs.c
index 55d19b0e03..235c171264 100644
--- a/hw/mem/cxl_type3_stubs.c
+++ b/hw/mem/cxl_type3_stubs.c
@@ -13,6 +13,19 @@  void qmp_cxl_inject_gen_media_event(const char *path, CxlEventLog log,
                                     const char *component_id,
                                     Error **errp) {}
 
+void qmp_cxl_inject_dram_event(const char *path, CxlEventLog log, uint8_t flags,
+                               uint64_t physaddr, uint8_t descriptor,
+                               uint8_t type, uint8_t transaction_type,
+                               bool has_channel, uint8_t channel,
+                               bool has_rank, uint8_t rank,
+                               bool has_nibble_mask, uint32_t nibble_mask,
+                               bool has_bank_group, uint8_t bank_group,
+                               bool has_bank, uint8_t bank,
+                               bool has_row, uint32_t row,
+                               bool has_column, uint16_t column,
+                               bool has_correction_mask, uint64List *correction_mask,
+                               Error **errp) {}
+
 void qmp_cxl_inject_poison(const char *path, uint64_t start, uint64_t length,
                            Error **errp)
 {
diff --git a/include/hw/cxl/cxl_events.h b/include/hw/cxl/cxl_events.h
index b189193f4c..a39e30d973 100644
--- a/include/hw/cxl/cxl_events.h
+++ b/include/hw/cxl/cxl_events.h
@@ -123,4 +123,27 @@  typedef struct CXLEventGenMedia {
     uint8_t reserved[CXL_EVENT_GEN_MED_RES_SIZE];
 } QEMU_PACKED CXLEventGenMedia;
 
+/*
+ * DRAM Event Record
+ * CXL Rev 3.0 Section 8.2.9.2.1.2: Table 8-44
+ * All fields little endian.
+ */
+typedef struct CXLEventDram {
+    CXLEventRecordHdr hdr;
+    uint64_t phys_addr;
+    uint8_t descriptor;
+    uint8_t type;
+    uint8_t transaction_type;
+    uint16_t validity_flags;
+    uint8_t channel;
+    uint8_t rank;
+    uint8_t nibble_mask[3];
+    uint8_t bank_group;
+    uint8_t bank;
+    uint8_t row[3];
+    uint16_t column;
+    uint64_t correction_mask[4];
+    uint8_t reserved[0x17];
+} QEMU_PACKED CXLEventDram;
+
 #endif /* CXL_EVENTS_H */
diff --git a/qapi/cxl.json b/qapi/cxl.json
index 7e1e6257ce..5e82097e76 100644
--- a/qapi/cxl.json
+++ b/qapi/cxl.json
@@ -55,6 +55,41 @@ 
             '*device': 'uint32', '*component-id': 'str'
             }}
 
+##
+# @cxl-inject-dram-event:
+#
+# Inject an event record for a DRAM Event (CXL r3.0 8.2.9.2.1.2)
+# This event type is reported via one of the event logs specified via
+# the log parameter.
+#
+# @path: CXL type 3 device canonical QOM path
+# @log: Event Log to add the event to
+# @flags: header flags
+# @physaddr: Physical Address
+# @descriptor: Descriptor
+# @type: Type
+# @transaction-type: Transaction Type
+# @channel: Channel
+# @rank: Rank
+# @nibble-mask: Identify one or more nibbles that the error affects
+# @bank-group: Bank group
+# @bank: Bank
+# @row: Row
+# @column: Column
+# @correction-mask: Bits within each nibble. Used in order of bits set
+#                   in the nibble-mask.  Up to 4 nibbles may be covered.
+#
+# Since: 8.1
+##
+{ 'command': 'cxl-inject-dram-event',
+  'data': { 'path': 'str', 'log': 'CxlEventLog', 'flags': 'uint8',
+            'physaddr': 'uint64', 'descriptor': 'uint8',
+            'type': 'uint8', 'transaction-type': 'uint8',
+            '*channel': 'uint8', '*rank': 'uint8', '*nibble-mask': 'uint32',
+            '*bank-group': 'uint8', '*bank': 'uint8', '*row': 'uint32',
+            '*column': 'uint16', '*correction-mask': [ 'uint64' ]
+           }}
+
 ##
 # @cxl-inject-poison:
 #