diff mbox series

[19/20] hw/net/xilinx_ethlite: Map the RAM buffer as RAM memory region

Message ID 20241112181044.92193-20-philmd@linaro.org
State New
Headers show
Series hw/net/xilinx_ethlite: Map RAM buffers as RAM and remove tswap() calls | expand

Commit Message

Philippe Mathieu-Daudé Nov. 12, 2024, 6:10 p.m. UTC
Rather than using I/O registers for RAM buffer, having to
swap endianness back and forth (because the core memory layer
automatically swaps endiannes for us), declare the buffers
as RAM regions. Remove the now unused s->regs[] array.

The memory flat view becomes:

  FlatView #0
   Root memory region: system
    0000000081000000-00000000810007f3 (prio 0, ram): ethlite.tx[0]buf
    00000000810007f4-00000000810007ff (prio 0, i/o): ethlite.tx[0]io
    0000000081000800-0000000081000ff3 (prio 0, ram): ethlite.tx[1]buf
    0000000081000ff4-0000000081000fff (prio 0, i/o): ethlite.tx[1]io
    0000000081001000-00000000810017f3 (prio 0, ram): ethlite.rx[0]buf
    00000000810017fc-00000000810017ff (prio 0, i/o): ethlite.rx[0]io
    0000000081001800-0000000081001ff3 (prio 0, ram): ethlite.rx[1]buf
    0000000081001ffc-0000000081001fff (prio 0, i/o): ethlite.rx[1]io

Mention the device datasheet in the file header.

Reported-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 hw/net/xilinx_ethlite.c | 79 +++++++++++------------------------------
 1 file changed, 20 insertions(+), 59 deletions(-)

Comments

Edgar E. Iglesias Nov. 13, 2024, 3:35 p.m. UTC | #1
On Tue, Nov 12, 2024 at 07:10:43PM +0100, Philippe Mathieu-Daudé wrote:
> Rather than using I/O registers for RAM buffer, having to
> swap endianness back and forth (because the core memory layer
> automatically swaps endiannes for us), declare the buffers
> as RAM regions. Remove the now unused s->regs[] array.
> 
> The memory flat view becomes:
> 
>   FlatView #0
>    Root memory region: system
>     0000000081000000-00000000810007f3 (prio 0, ram): ethlite.tx[0]buf
>     00000000810007f4-00000000810007ff (prio 0, i/o): ethlite.tx[0]io
>     0000000081000800-0000000081000ff3 (prio 0, ram): ethlite.tx[1]buf
>     0000000081000ff4-0000000081000fff (prio 0, i/o): ethlite.tx[1]io
>     0000000081001000-00000000810017f3 (prio 0, ram): ethlite.rx[0]buf
>     00000000810017fc-00000000810017ff (prio 0, i/o): ethlite.rx[0]io
>     0000000081001800-0000000081001ff3 (prio 0, ram): ethlite.rx[1]buf
>     0000000081001ffc-0000000081001fff (prio 0, i/o): ethlite.rx[1]io
> 
> Mention the device datasheet in the file header.

Nice!

Reviewed-by: Edgar E. Iglesias <edgar.iglesias@amd.com>


> 
> Reported-by: Paolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
> ---
>  hw/net/xilinx_ethlite.c | 79 +++++++++++------------------------------
>  1 file changed, 20 insertions(+), 59 deletions(-)
> 
> diff --git a/hw/net/xilinx_ethlite.c b/hw/net/xilinx_ethlite.c
> index f681b91769..da453465ca 100644
> --- a/hw/net/xilinx_ethlite.c
> +++ b/hw/net/xilinx_ethlite.c
> @@ -2,6 +2,10 @@
>   * QEMU model of the Xilinx Ethernet Lite MAC.
>   *
>   * Copyright (c) 2009 Edgar E. Iglesias.
> + * Copyright (c) 2024 Linaro, Ltd
> + *
> + * DS580: https://docs.amd.com/v/u/en-US/xps_ethernetlite
> + * LogiCORE IP XPS Ethernet Lite Media Access Controller
>   *
>   * Permission is hereby granted, free of charge, to any person obtaining a copy
>   * of this software and associated documentation files (the "Software"), to deal
> @@ -27,7 +31,6 @@
>  #include "qemu/bitops.h"
>  #include "qom/object.h"
>  #include "qapi/error.h"
> -#include "exec/tswap.h"
>  #include "hw/sysbus.h"
>  #include "hw/irq.h"
>  #include "hw/qdev-properties.h"
> @@ -46,7 +49,6 @@
>  #define A_RX_BASE0    0x17fc
>  #define R_RX_BUF1     (0x1800 / 4)
>  #define A_RX_BASE1    0x1ffc
> -#define R_MAX         (0x2000 / 4)
>  
>  #define RX_BUFSZ_MAX  0x07e0
>  
> @@ -72,6 +74,8 @@ typedef struct XlnxXpsEthLitePort
>  {
>      MemoryRegion txio;
>      MemoryRegion rxio;
> +    MemoryRegion txbuf;
> +    MemoryRegion rxbuf;
>  
>      struct {
>          uint32_t tx_len;
> @@ -100,7 +104,6 @@ struct XlnxXpsEthLite
>  
>      UnimplementedDeviceState mdio;
>      XlnxXpsEthLitePort port[2];
> -    uint32_t regs[R_MAX];
>  };
>  
>  static inline void eth_pulse_irq(XlnxXpsEthLite *s)
> @@ -118,16 +121,12 @@ static unsigned addr_to_port_index(hwaddr addr)
>  
>  static void *txbuf_ptr(XlnxXpsEthLite *s, unsigned port_index)
>  {
> -    unsigned int rxbase = port_index * (0x800 / 4);
> -
> -    return &s->regs[rxbase + R_TX_BUF0];
> +    return memory_region_get_ram_ptr(&s->port[port_index].txbuf);
>  }
>  
>  static void *rxbuf_ptr(XlnxXpsEthLite *s, unsigned port_index)
>  {
> -    unsigned int rxbase = port_index * (0x800 / 4);
> -
> -    return &s->regs[rxbase + R_RX_BUF0];
> +    return memory_region_get_ram_ptr(&s->port[port_index].rxbuf);
>  }
>  
>  static uint64_t port_tx_read(void *opaque, hwaddr addr, unsigned int size)
> @@ -252,53 +251,6 @@ static const MemoryRegionOps eth_portrx_ops = {
>          },
>  };
>  
> -static uint64_t
> -eth_read(void *opaque, hwaddr addr, unsigned int size)
> -{
> -    XlnxXpsEthLite *s = opaque;
> -    uint32_t r = 0;
> -
> -    addr >>= 2;
> -
> -    switch (addr)
> -    {
> -        default:
> -            r = tswap32(s->regs[addr]);
> -            break;
> -    }
> -    return r;
> -}
> -
> -static void
> -eth_write(void *opaque, hwaddr addr,
> -          uint64_t val64, unsigned int size)
> -{
> -    XlnxXpsEthLite *s = opaque;
> -    uint32_t value = val64;
> -
> -    addr >>= 2;
> -    switch (addr) 
> -    {
> -        default:
> -            s->regs[addr] = tswap32(value);
> -            break;
> -    }
> -}
> -
> -static const MemoryRegionOps eth_ops = {
> -    .read = eth_read,
> -    .write = eth_write,
> -    .endianness = DEVICE_NATIVE_ENDIAN,
> -    .impl = {
> -        .min_access_size = 4,
> -        .max_access_size = 4,
> -    },
> -    .valid = {
> -        .min_access_size = 4,
> -        .max_access_size = 4
> -    }
> -};
> -
>  static bool eth_can_rx(NetClientState *nc)
>  {
>      XlnxXpsEthLite *s = qemu_get_nic_opaque(nc);
> @@ -354,6 +306,9 @@ static void xilinx_ethlite_realize(DeviceState *dev, Error **errp)
>  {
>      XlnxXpsEthLite *s = XILINX_ETHLITE(dev);
>  
> +    memory_region_init(&s->mmio, OBJECT(dev),
> +                       "xlnx.xps-ethernetlite", 0x2000);
> +
>      object_initialize_child(OBJECT(dev), "ethlite.mdio", &s->mdio,
>                             TYPE_UNIMPLEMENTED_DEVICE);
>      qdev_prop_set_string(DEVICE(&s->mdio), "name", "ethlite.mdio");
> @@ -363,6 +318,10 @@ static void xilinx_ethlite_realize(DeviceState *dev, Error **errp)
>                              sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mdio), 0));
>  
>      for (unsigned i = 0; i < 2; i++) {
> +        memory_region_init_ram(&s->port[i].txbuf, OBJECT(dev),
> +                               i ? "ethlite.tx[1]buf" : "ethlite.tx[0]buf",
> +                               0x07f4, &error_abort);
> +        memory_region_add_subregion(&s->mmio, 0x0800 * i, &s->port[i].txbuf);
>          memory_region_init_io(&s->port[i].txio, OBJECT(dev),
>                                &eth_porttx_ops, s,
>                                i ? "ethlite.tx[1]io" : "ethlite.tx[0]io",
> @@ -370,6 +329,11 @@ static void xilinx_ethlite_realize(DeviceState *dev, Error **errp)
>          memory_region_add_subregion(&s->mmio, i ? A_TX_BASE1 : A_TX_BASE0,
>                                      &s->port[i].txio);
>  
> +        memory_region_init_ram(&s->port[i].rxbuf, OBJECT(dev),
> +                               i ? "ethlite.rx[1]buf" : "ethlite.rx[0]buf",
> +                               0x07f4, &error_abort);
> +        memory_region_add_subregion(&s->mmio, 0x1000 + 0x0800 * i,
> +                                    &s->port[i].rxbuf);
>          memory_region_init_io(&s->port[i].rxio, OBJECT(dev),
>                                &eth_portrx_ops, s,
>                                i ? "ethlite.rx[1]io" : "ethlite.rx[0]io",
> @@ -390,9 +354,6 @@ static void xilinx_ethlite_init(Object *obj)
>      XlnxXpsEthLite *s = XILINX_ETHLITE(obj);
>  
>      sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
> -
> -    memory_region_init_io(&s->mmio, obj, &eth_ops, s,
> -                          "xlnx.xps-ethernetlite", R_MAX * 4);
>      sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
>  }
>  
> -- 
> 2.45.2
>
Paolo Bonzini Nov. 13, 2024, 6:21 p.m. UTC | #2
On 11/12/24 19:10, Philippe Mathieu-Daudé wrote:
> Rather than using I/O registers for RAM buffer, having to
> swap endianness back and forth (because the core memory layer
> automatically swaps endiannes for us), declare the buffers
> as RAM regions. Remove the now unused s->regs[] array.
> 
> The memory flat view becomes:
> 
>    FlatView #0
>     Root memory region: system
>      0000000081000000-00000000810007f3 (prio 0, ram): ethlite.tx[0]buf
>      00000000810007f4-00000000810007ff (prio 0, i/o): ethlite.tx[0]io
>      0000000081000800-0000000081000ff3 (prio 0, ram): ethlite.tx[1]buf
>      0000000081000ff4-0000000081000fff (prio 0, i/o): ethlite.tx[1]io
>      0000000081001000-00000000810017f3 (prio 0, ram): ethlite.rx[0]buf
>      00000000810017fc-00000000810017ff (prio 0, i/o): ethlite.rx[0]io
>      0000000081001800-0000000081001ff3 (prio 0, ram): ethlite.rx[1]buf
>      0000000081001ffc-0000000081001fff (prio 0, i/o): ethlite.rx[1]io

The receive buffers should end at 7fb and ffb; no need to repost of course.

Paolo

> 
> Mention the device datasheet in the file header.
> 
> Reported-by: Paolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
> ---
>   hw/net/xilinx_ethlite.c | 79 +++++++++++------------------------------
>   1 file changed, 20 insertions(+), 59 deletions(-)
> 
> diff --git a/hw/net/xilinx_ethlite.c b/hw/net/xilinx_ethlite.c
> index f681b91769..da453465ca 100644
> --- a/hw/net/xilinx_ethlite.c
> +++ b/hw/net/xilinx_ethlite.c
> @@ -2,6 +2,10 @@
>    * QEMU model of the Xilinx Ethernet Lite MAC.
>    *
>    * Copyright (c) 2009 Edgar E. Iglesias.
> + * Copyright (c) 2024 Linaro, Ltd
> + *
> + * DS580: https://docs.amd.com/v/u/en-US/xps_ethernetlite
> + * LogiCORE IP XPS Ethernet Lite Media Access Controller
>    *
>    * Permission is hereby granted, free of charge, to any person obtaining a copy
>    * of this software and associated documentation files (the "Software"), to deal
> @@ -27,7 +31,6 @@
>   #include "qemu/bitops.h"
>   #include "qom/object.h"
>   #include "qapi/error.h"
> -#include "exec/tswap.h"
>   #include "hw/sysbus.h"
>   #include "hw/irq.h"
>   #include "hw/qdev-properties.h"
> @@ -46,7 +49,6 @@
>   #define A_RX_BASE0    0x17fc
>   #define R_RX_BUF1     (0x1800 / 4)
>   #define A_RX_BASE1    0x1ffc
> -#define R_MAX         (0x2000 / 4)
>   
>   #define RX_BUFSZ_MAX  0x07e0
>   
> @@ -72,6 +74,8 @@ typedef struct XlnxXpsEthLitePort
>   {
>       MemoryRegion txio;
>       MemoryRegion rxio;
> +    MemoryRegion txbuf;
> +    MemoryRegion rxbuf;
>   
>       struct {
>           uint32_t tx_len;
> @@ -100,7 +104,6 @@ struct XlnxXpsEthLite
>   
>       UnimplementedDeviceState mdio;
>       XlnxXpsEthLitePort port[2];
> -    uint32_t regs[R_MAX];
>   };
>   
>   static inline void eth_pulse_irq(XlnxXpsEthLite *s)
> @@ -118,16 +121,12 @@ static unsigned addr_to_port_index(hwaddr addr)
>   
>   static void *txbuf_ptr(XlnxXpsEthLite *s, unsigned port_index)
>   {
> -    unsigned int rxbase = port_index * (0x800 / 4);
> -
> -    return &s->regs[rxbase + R_TX_BUF0];
> +    return memory_region_get_ram_ptr(&s->port[port_index].txbuf);
>   }
>   
>   static void *rxbuf_ptr(XlnxXpsEthLite *s, unsigned port_index)
>   {
> -    unsigned int rxbase = port_index * (0x800 / 4);
> -
> -    return &s->regs[rxbase + R_RX_BUF0];
> +    return memory_region_get_ram_ptr(&s->port[port_index].rxbuf);
>   }
>   
>   static uint64_t port_tx_read(void *opaque, hwaddr addr, unsigned int size)
> @@ -252,53 +251,6 @@ static const MemoryRegionOps eth_portrx_ops = {
>           },
>   };
>   
> -static uint64_t
> -eth_read(void *opaque, hwaddr addr, unsigned int size)
> -{
> -    XlnxXpsEthLite *s = opaque;
> -    uint32_t r = 0;
> -
> -    addr >>= 2;
> -
> -    switch (addr)
> -    {
> -        default:
> -            r = tswap32(s->regs[addr]);
> -            break;
> -    }
> -    return r;
> -}
> -
> -static void
> -eth_write(void *opaque, hwaddr addr,
> -          uint64_t val64, unsigned int size)
> -{
> -    XlnxXpsEthLite *s = opaque;
> -    uint32_t value = val64;
> -
> -    addr >>= 2;
> -    switch (addr)
> -    {
> -        default:
> -            s->regs[addr] = tswap32(value);
> -            break;
> -    }
> -}
> -
> -static const MemoryRegionOps eth_ops = {
> -    .read = eth_read,
> -    .write = eth_write,
> -    .endianness = DEVICE_NATIVE_ENDIAN,
> -    .impl = {
> -        .min_access_size = 4,
> -        .max_access_size = 4,
> -    },
> -    .valid = {
> -        .min_access_size = 4,
> -        .max_access_size = 4
> -    }
> -};
> -
>   static bool eth_can_rx(NetClientState *nc)
>   {
>       XlnxXpsEthLite *s = qemu_get_nic_opaque(nc);
> @@ -354,6 +306,9 @@ static void xilinx_ethlite_realize(DeviceState *dev, Error **errp)
>   {
>       XlnxXpsEthLite *s = XILINX_ETHLITE(dev);
>   
> +    memory_region_init(&s->mmio, OBJECT(dev),
> +                       "xlnx.xps-ethernetlite", 0x2000);
> +
>       object_initialize_child(OBJECT(dev), "ethlite.mdio", &s->mdio,
>                              TYPE_UNIMPLEMENTED_DEVICE);
>       qdev_prop_set_string(DEVICE(&s->mdio), "name", "ethlite.mdio");
> @@ -363,6 +318,10 @@ static void xilinx_ethlite_realize(DeviceState *dev, Error **errp)
>                               sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mdio), 0));
>   
>       for (unsigned i = 0; i < 2; i++) {
> +        memory_region_init_ram(&s->port[i].txbuf, OBJECT(dev),
> +                               i ? "ethlite.tx[1]buf" : "ethlite.tx[0]buf",
> +                               0x07f4, &error_abort);
> +        memory_region_add_subregion(&s->mmio, 0x0800 * i, &s->port[i].txbuf);
>           memory_region_init_io(&s->port[i].txio, OBJECT(dev),
>                                 &eth_porttx_ops, s,
>                                 i ? "ethlite.tx[1]io" : "ethlite.tx[0]io",
> @@ -370,6 +329,11 @@ static void xilinx_ethlite_realize(DeviceState *dev, Error **errp)
>           memory_region_add_subregion(&s->mmio, i ? A_TX_BASE1 : A_TX_BASE0,
>                                       &s->port[i].txio);
>   
> +        memory_region_init_ram(&s->port[i].rxbuf, OBJECT(dev),
> +                               i ? "ethlite.rx[1]buf" : "ethlite.rx[0]buf",
> +                               0x07f4, &error_abort);
> +        memory_region_add_subregion(&s->mmio, 0x1000 + 0x0800 * i,
> +                                    &s->port[i].rxbuf);
>           memory_region_init_io(&s->port[i].rxio, OBJECT(dev),
>                                 &eth_portrx_ops, s,
>                                 i ? "ethlite.rx[1]io" : "ethlite.rx[0]io",
> @@ -390,9 +354,6 @@ static void xilinx_ethlite_init(Object *obj)
>       XlnxXpsEthLite *s = XILINX_ETHLITE(obj);
>   
>       sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
> -
> -    memory_region_init_io(&s->mmio, obj, &eth_ops, s,
> -                          "xlnx.xps-ethernetlite", R_MAX * 4);
>       sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
>   }
>
Philippe Mathieu-Daudé Nov. 13, 2024, 7:37 p.m. UTC | #3
On 13/11/24 18:21, Paolo Bonzini wrote:
> On 11/12/24 19:10, Philippe Mathieu-Daudé wrote:
>> Rather than using I/O registers for RAM buffer, having to
>> swap endianness back and forth (because the core memory layer
>> automatically swaps endiannes for us), declare the buffers
>> as RAM regions. Remove the now unused s->regs[] array.
>>
>> The memory flat view becomes:
>>
>>    FlatView #0
>>     Root memory region: system
>>      0000000081000000-00000000810007f3 (prio 0, ram): ethlite.tx[0]buf
>>      00000000810007f4-00000000810007ff (prio 0, i/o): ethlite.tx[0]io
>>      0000000081000800-0000000081000ff3 (prio 0, ram): ethlite.tx[1]buf
>>      0000000081000ff4-0000000081000fff (prio 0, i/o): ethlite.tx[1]io
>>      0000000081001000-00000000810017f3 (prio 0, ram): ethlite.rx[0]buf
>>      00000000810017fc-00000000810017ff (prio 0, i/o): ethlite.rx[0]io
>>      0000000081001800-0000000081001ff3 (prio 0, ram): ethlite.rx[1]buf
>>      0000000081001ffc-0000000081001fff (prio 0, i/o): ethlite.rx[1]io
> 
> The receive buffers should end at 7fb and ffb; no need to repost of course.

Nice catch. Actually, looking at the datasheet p. 20, Table 11 "XPS
Ethernet Lite MAC Memory Map" we have

0x0000 - 0x07E0  TxPingBuf
0x07E4 - 0x07F0  MDIO if C_INCLUDE_MDIO else Reserved
0x07F4 - 0x07FC  TxPingIO
0x0800 - 0x0FE0  TxPongBuf
0x0FE4 - 0x0FF0  Reserved
0x0FF4 - 0x0FFC  TxPongIO
0x1000 - 0x17E0  RxPingBuf
0x17E4 - 0x17F8  Reserved
0x17FC - 0x17FC  RxPingIO
0x1800 - 0x1FE0  RxPongBuf
0x1FE4 - 0x1FF8  Reserved
0x1FFC - 0x1FFC  RxPongIO

I'll update appropriately.

Thanks,

Phil.
diff mbox series

Patch

diff --git a/hw/net/xilinx_ethlite.c b/hw/net/xilinx_ethlite.c
index f681b91769..da453465ca 100644
--- a/hw/net/xilinx_ethlite.c
+++ b/hw/net/xilinx_ethlite.c
@@ -2,6 +2,10 @@ 
  * QEMU model of the Xilinx Ethernet Lite MAC.
  *
  * Copyright (c) 2009 Edgar E. Iglesias.
+ * Copyright (c) 2024 Linaro, Ltd
+ *
+ * DS580: https://docs.amd.com/v/u/en-US/xps_ethernetlite
+ * LogiCORE IP XPS Ethernet Lite Media Access Controller
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -27,7 +31,6 @@ 
 #include "qemu/bitops.h"
 #include "qom/object.h"
 #include "qapi/error.h"
-#include "exec/tswap.h"
 #include "hw/sysbus.h"
 #include "hw/irq.h"
 #include "hw/qdev-properties.h"
@@ -46,7 +49,6 @@ 
 #define A_RX_BASE0    0x17fc
 #define R_RX_BUF1     (0x1800 / 4)
 #define A_RX_BASE1    0x1ffc
-#define R_MAX         (0x2000 / 4)
 
 #define RX_BUFSZ_MAX  0x07e0
 
@@ -72,6 +74,8 @@  typedef struct XlnxXpsEthLitePort
 {
     MemoryRegion txio;
     MemoryRegion rxio;
+    MemoryRegion txbuf;
+    MemoryRegion rxbuf;
 
     struct {
         uint32_t tx_len;
@@ -100,7 +104,6 @@  struct XlnxXpsEthLite
 
     UnimplementedDeviceState mdio;
     XlnxXpsEthLitePort port[2];
-    uint32_t regs[R_MAX];
 };
 
 static inline void eth_pulse_irq(XlnxXpsEthLite *s)
@@ -118,16 +121,12 @@  static unsigned addr_to_port_index(hwaddr addr)
 
 static void *txbuf_ptr(XlnxXpsEthLite *s, unsigned port_index)
 {
-    unsigned int rxbase = port_index * (0x800 / 4);
-
-    return &s->regs[rxbase + R_TX_BUF0];
+    return memory_region_get_ram_ptr(&s->port[port_index].txbuf);
 }
 
 static void *rxbuf_ptr(XlnxXpsEthLite *s, unsigned port_index)
 {
-    unsigned int rxbase = port_index * (0x800 / 4);
-
-    return &s->regs[rxbase + R_RX_BUF0];
+    return memory_region_get_ram_ptr(&s->port[port_index].rxbuf);
 }
 
 static uint64_t port_tx_read(void *opaque, hwaddr addr, unsigned int size)
@@ -252,53 +251,6 @@  static const MemoryRegionOps eth_portrx_ops = {
         },
 };
 
-static uint64_t
-eth_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    XlnxXpsEthLite *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-
-    switch (addr)
-    {
-        default:
-            r = tswap32(s->regs[addr]);
-            break;
-    }
-    return r;
-}
-
-static void
-eth_write(void *opaque, hwaddr addr,
-          uint64_t val64, unsigned int size)
-{
-    XlnxXpsEthLite *s = opaque;
-    uint32_t value = val64;
-
-    addr >>= 2;
-    switch (addr) 
-    {
-        default:
-            s->regs[addr] = tswap32(value);
-            break;
-    }
-}
-
-static const MemoryRegionOps eth_ops = {
-    .read = eth_read,
-    .write = eth_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
 static bool eth_can_rx(NetClientState *nc)
 {
     XlnxXpsEthLite *s = qemu_get_nic_opaque(nc);
@@ -354,6 +306,9 @@  static void xilinx_ethlite_realize(DeviceState *dev, Error **errp)
 {
     XlnxXpsEthLite *s = XILINX_ETHLITE(dev);
 
+    memory_region_init(&s->mmio, OBJECT(dev),
+                       "xlnx.xps-ethernetlite", 0x2000);
+
     object_initialize_child(OBJECT(dev), "ethlite.mdio", &s->mdio,
                            TYPE_UNIMPLEMENTED_DEVICE);
     qdev_prop_set_string(DEVICE(&s->mdio), "name", "ethlite.mdio");
@@ -363,6 +318,10 @@  static void xilinx_ethlite_realize(DeviceState *dev, Error **errp)
                             sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mdio), 0));
 
     for (unsigned i = 0; i < 2; i++) {
+        memory_region_init_ram(&s->port[i].txbuf, OBJECT(dev),
+                               i ? "ethlite.tx[1]buf" : "ethlite.tx[0]buf",
+                               0x07f4, &error_abort);
+        memory_region_add_subregion(&s->mmio, 0x0800 * i, &s->port[i].txbuf);
         memory_region_init_io(&s->port[i].txio, OBJECT(dev),
                               &eth_porttx_ops, s,
                               i ? "ethlite.tx[1]io" : "ethlite.tx[0]io",
@@ -370,6 +329,11 @@  static void xilinx_ethlite_realize(DeviceState *dev, Error **errp)
         memory_region_add_subregion(&s->mmio, i ? A_TX_BASE1 : A_TX_BASE0,
                                     &s->port[i].txio);
 
+        memory_region_init_ram(&s->port[i].rxbuf, OBJECT(dev),
+                               i ? "ethlite.rx[1]buf" : "ethlite.rx[0]buf",
+                               0x07f4, &error_abort);
+        memory_region_add_subregion(&s->mmio, 0x1000 + 0x0800 * i,
+                                    &s->port[i].rxbuf);
         memory_region_init_io(&s->port[i].rxio, OBJECT(dev),
                               &eth_portrx_ops, s,
                               i ? "ethlite.rx[1]io" : "ethlite.rx[0]io",
@@ -390,9 +354,6 @@  static void xilinx_ethlite_init(Object *obj)
     XlnxXpsEthLite *s = XILINX_ETHLITE(obj);
 
     sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
-
-    memory_region_init_io(&s->mmio, obj, &eth_ops, s,
-                          "xlnx.xps-ethernetlite", R_MAX * 4);
     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
 }