提交 112a829f 编写于 作者: P Peter Maydell

hw/dma/pl080: Don't use CPU address space for DMA accesses

Currently our PL080/PL081 model uses a combination of the CPU's
address space (via cpu_physical_memory_{read,write}()) and the
system address space for performing DMA accesses.

For the PL081s in the MPS FPGA images, their DMA accesses
must go via Master Security Controllers. Switch the
PL080/PL081 model to take a MemoryRegion property which
defines its downstream for making DMA accesses.

Since the PL08x are only used in two board models, we
make provision of the 'downstream' link mandatory and convert
both users at once, rather than having it be optional with
a default to the system address space.
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
Reviewed-by: NPhilippe Mathieu-Daudé <f4bug@amsat.org>
上级 6d0ed6ba
...@@ -201,7 +201,13 @@ static void realview_init(MachineState *machine, ...@@ -201,7 +201,13 @@ static void realview_init(MachineState *machine,
pl011_create(0x1000c000, pic[15], serial_hd(3)); pl011_create(0x1000c000, pic[15], serial_hd(3));
/* DMA controller is optional, apparently. */ /* DMA controller is optional, apparently. */
sysbus_create_simple("pl081", 0x10030000, pic[24]); dev = qdev_create(NULL, "pl081");
object_property_set_link(OBJECT(dev), OBJECT(sysmem), "downstream",
&error_fatal);
qdev_init_nofail(dev);
busdev = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(busdev, 0, 0x10030000);
sysbus_connect_irq(busdev, 0, pic[24]);
sysbus_create_simple("sp804", 0x10011000, pic[4]); sysbus_create_simple("sp804", 0x10011000, pic[4]);
sysbus_create_simple("sp804", 0x10012000, pic[5]); sysbus_create_simple("sp804", 0x10012000, pic[5]);
......
...@@ -287,7 +287,14 @@ static void versatile_init(MachineState *machine, int board_id) ...@@ -287,7 +287,14 @@ static void versatile_init(MachineState *machine, int board_id)
pl011_create(0x101f3000, pic[14], serial_hd(2)); pl011_create(0x101f3000, pic[14], serial_hd(2));
pl011_create(0x10009000, sic[6], serial_hd(3)); pl011_create(0x10009000, sic[6], serial_hd(3));
sysbus_create_simple("pl080", 0x10130000, pic[17]); dev = qdev_create(NULL, "pl080");
object_property_set_link(OBJECT(dev), OBJECT(sysmem), "downstream",
&error_fatal);
qdev_init_nofail(dev);
busdev = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(busdev, 0, 0x10130000);
sysbus_connect_irq(busdev, 0, pic[17]);
sysbus_create_simple("sp804", 0x101e2000, pic[4]); sysbus_create_simple("sp804", 0x101e2000, pic[4]);
sysbus_create_simple("sp804", 0x101e3000, pic[5]); sysbus_create_simple("sp804", 0x101e3000, pic[5]);
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "exec/address-spaces.h" #include "exec/address-spaces.h"
#include "qemu/log.h" #include "qemu/log.h"
#include "hw/dma/pl080.h" #include "hw/dma/pl080.h"
#include "qapi/error.h"
#define PL080_CONF_E 0x1 #define PL080_CONF_E 0x1
#define PL080_CONF_M1 0x2 #define PL080_CONF_M1 0x2
...@@ -161,14 +162,16 @@ again: ...@@ -161,14 +162,16 @@ again:
swidth = 1 << ((ch->ctrl >> 18) & 7); swidth = 1 << ((ch->ctrl >> 18) & 7);
dwidth = 1 << ((ch->ctrl >> 21) & 7); dwidth = 1 << ((ch->ctrl >> 21) & 7);
for (n = 0; n < dwidth; n+= swidth) { for (n = 0; n < dwidth; n+= swidth) {
cpu_physical_memory_read(ch->src, buff + n, swidth); address_space_read(&s->downstream_as, ch->src,
MEMTXATTRS_UNSPECIFIED, buff + n, swidth);
if (ch->ctrl & PL080_CCTRL_SI) if (ch->ctrl & PL080_CCTRL_SI)
ch->src += swidth; ch->src += swidth;
} }
xsize = (dwidth < swidth) ? swidth : dwidth; xsize = (dwidth < swidth) ? swidth : dwidth;
/* ??? This may pad the value incorrectly for dwidth < 32. */ /* ??? This may pad the value incorrectly for dwidth < 32. */
for (n = 0; n < xsize; n += dwidth) { for (n = 0; n < xsize; n += dwidth) {
cpu_physical_memory_write(ch->dest + n, buff + n, dwidth); address_space_write(&s->downstream_as, ch->dest + n,
MEMTXATTRS_UNSPECIFIED, buff + n, dwidth);
if (ch->ctrl & PL080_CCTRL_DI) if (ch->ctrl & PL080_CCTRL_DI)
ch->dest += swidth; ch->dest += swidth;
} }
...@@ -178,19 +181,19 @@ again: ...@@ -178,19 +181,19 @@ again:
if (size == 0) { if (size == 0) {
/* Transfer complete. */ /* Transfer complete. */
if (ch->lli) { if (ch->lli) {
ch->src = address_space_ldl_le(&address_space_memory, ch->src = address_space_ldl_le(&s->downstream_as,
ch->lli, ch->lli,
MEMTXATTRS_UNSPECIFIED, MEMTXATTRS_UNSPECIFIED,
NULL); NULL);
ch->dest = address_space_ldl_le(&address_space_memory, ch->dest = address_space_ldl_le(&s->downstream_as,
ch->lli + 4, ch->lli + 4,
MEMTXATTRS_UNSPECIFIED, MEMTXATTRS_UNSPECIFIED,
NULL); NULL);
ch->ctrl = address_space_ldl_le(&address_space_memory, ch->ctrl = address_space_ldl_le(&s->downstream_as,
ch->lli + 12, ch->lli + 12,
MEMTXATTRS_UNSPECIFIED, MEMTXATTRS_UNSPECIFIED,
NULL); NULL);
ch->lli = address_space_ldl_le(&address_space_memory, ch->lli = address_space_ldl_le(&s->downstream_as,
ch->lli + 8, ch->lli + 8,
MEMTXATTRS_UNSPECIFIED, MEMTXATTRS_UNSPECIFIED,
NULL); NULL);
...@@ -358,6 +361,18 @@ static void pl080_init(Object *obj) ...@@ -358,6 +361,18 @@ static void pl080_init(Object *obj)
s->nchannels = 8; s->nchannels = 8;
} }
static void pl080_realize(DeviceState *dev, Error **errp)
{
PL080State *s = PL080(dev);
if (!s->downstream) {
error_setg(errp, "PL080 'downstream' link not set");
return;
}
address_space_init(&s->downstream_as, s->downstream, "pl080-downstream");
}
static void pl081_init(Object *obj) static void pl081_init(Object *obj)
{ {
PL080State *s = PL080(obj); PL080State *s = PL080(obj);
...@@ -365,11 +380,19 @@ static void pl081_init(Object *obj) ...@@ -365,11 +380,19 @@ static void pl081_init(Object *obj)
s->nchannels = 2; s->nchannels = 2;
} }
static Property pl080_properties[] = {
DEFINE_PROP_LINK("downstream", PL080State, downstream,
TYPE_MEMORY_REGION, MemoryRegion *),
DEFINE_PROP_END_OF_LIST(),
};
static void pl080_class_init(ObjectClass *oc, void *data) static void pl080_class_init(ObjectClass *oc, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc);
dc->vmsd = &vmstate_pl080; dc->vmsd = &vmstate_pl080;
dc->realize = pl080_realize;
dc->props = pl080_properties;
} }
static const TypeInfo pl080_info = { static const TypeInfo pl080_info = {
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
* + sysbus IRQ 1: DMACINTERR error interrupt request * + sysbus IRQ 1: DMACINTERR error interrupt request
* + sysbus IRQ 2: DMACINTTC count interrupt request * + sysbus IRQ 2: DMACINTTC count interrupt request
* + sysbus MMIO region 0: MemoryRegion for the device's registers * + sysbus MMIO region 0: MemoryRegion for the device's registers
* + QOM property "downstream": MemoryRegion defining where DMA
* bus master transactions are made
*/ */
#ifndef HW_DMA_PL080_H #ifndef HW_DMA_PL080_H
...@@ -61,6 +63,9 @@ typedef struct PL080State { ...@@ -61,6 +63,9 @@ typedef struct PL080State {
qemu_irq irq; qemu_irq irq;
qemu_irq interr; qemu_irq interr;
qemu_irq inttc; qemu_irq inttc;
MemoryRegion *downstream;
AddressSpace downstream_as;
} PL080State; } PL080State;
#endif #endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册