aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2018-01-11 14:34:41 +0000
committerPeter Maydell <peter.maydell@linaro.org>2018-01-11 14:34:41 +0000
commit997eba28a3ed5400a80f754bf3a1c8044b75b9ff (patch)
tree2535822ed76e5896b201eab730206f00a5582f35 /hw
parente890966d60867810358449ec5384a109d5a48f46 (diff)
parent0cf09852015e47a5fbb974ff7ac320366afd21ee (diff)
downloadqemu-997eba28a3ed5400a80f754bf3a1c8044b75b9ff.zip
qemu-997eba28a3ed5400a80f754bf3a1c8044b75b9ff.tar.gz
qemu-997eba28a3ed5400a80f754bf3a1c8044b75b9ff.tar.bz2
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20180111' into staging
target-arm queue: * add aarch64_be linux-user target * Virt: ACPI: fix qemu assert due to re-assigned table data address * imx_fec: various bug fixes and cleanups * hw/timer/pxa2xx_timer: replace hw_error() -> qemu_log_mask() * hw/sd/pxa2xx_mmci: add read/write() trace events * linux-user/arm/nwfpe: Check coprocessor number for FPA emulation * target/arm: Make disas_thumb2_insn() generate its own UNDEF exceptions * hw/intc/arm_gicv3: Make reserved register addresses RAZ/WI * hw/intc/arm_gic: reserved register addresses are RAZ/WI # gpg: Signature made Thu 11 Jan 2018 13:37:25 GMT # gpg: using RSA key 0x3C2525ED14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20180111: (26 commits) hw/intc/arm_gic: reserved register addresses are RAZ/WI hw/intc/arm_gicv3: Make reserved register addresses RAZ/WI target/arm: Make disas_thumb2_insn() generate its own UNDEF exceptions linux-user/arm/nwfpe: Check coprocessor number for FPA emulation hw/sd/pxa2xx_mmci: add read/write() trace events hw/timer/pxa2xx_timer: replace hw_error() -> qemu_log_mask() imx_fec: Reserve full FSL_IMX25_FEC_SIZE page for the register file imx_fec: Fix a typo in imx_enet_receive() imx_fec: Use correct length for packet size imx_fec: Add support for multiple Tx DMA rings imx_fec: Emulate SHIFT16 in ENETx_RACC imx_fec: Use MIN instead of explicit ternary operator imx_fec: Use ENET_FTRL to determine truncation length imx_fec: Move Tx frame buffer away from the stack imx_fec: Change queue flushing heuristics imx_fec: Refactor imx_eth_enable_rx() imx_fec: Do not link to netdev Virt: ACPI: fix qemu assert due to re-assigned table data address target/arm: Fix stlxp for aarch64_be linux-user: Activate armeb handler registration ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/arm/fsl-imx6.c1
-rw-r--r--hw/arm/virt-acpi-build.c18
-rw-r--r--hw/intc/arm_gic.c5
-rw-r--r--hw/intc/arm_gicv3_dist.c13
-rw-r--r--hw/intc/arm_gicv3_its_common.c8
-rw-r--r--hw/intc/arm_gicv3_redist.c13
-rw-r--r--hw/net/imx_fec.c210
-rw-r--r--hw/sd/pxa2xx_mmci.c78
-rw-r--r--hw/sd/trace-events4
-rw-r--r--hw/timer/pxa2xx_timer.c17
10 files changed, 276 insertions, 91 deletions
diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c
index 59ef33e..b0d4088 100644
--- a/hw/arm/fsl-imx6.c
+++ b/hw/arm/fsl-imx6.c
@@ -385,6 +385,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
spi_table[i].irq));
}
+ qdev_set_nic_properties(DEVICE(&s->eth), &nd_table[0]);
object_property_set_bool(OBJECT(&s->eth), true, "realized", &err);
if (err) {
error_propagate(errp, err);
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 3d78ff6..f7fa795 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -453,6 +453,7 @@ build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
AcpiSerialPortConsoleRedirection *spcr;
const MemMapEntry *uart_memmap = &vms->memmap[VIRT_UART];
int irq = vms->irqmap[VIRT_UART] + ARM_SPI_BASE;
+ int spcr_start = table_data->len;
spcr = acpi_data_push(table_data, sizeof(*spcr));
@@ -476,8 +477,8 @@ build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
spcr->pci_device_id = 0xffff; /* PCI Device ID: not a PCI device */
spcr->pci_vendor_id = 0xffff; /* PCI Vendor ID: not a PCI device */
- build_header(linker, table_data, (void *)spcr, "SPCR", sizeof(*spcr), 2,
- NULL, NULL);
+ build_header(linker, table_data, (void *)(table_data->data + spcr_start),
+ "SPCR", table_data->len - spcr_start, 2, NULL, NULL);
}
static void
@@ -512,8 +513,8 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
mem_base += numa_info[i].node_mem;
}
- build_header(linker, table_data, (void *)srat, "SRAT",
- table_data->len - srat_start, 3, NULL, NULL);
+ build_header(linker, table_data, (void *)(table_data->data + srat_start),
+ "SRAT", table_data->len - srat_start, 3, NULL, NULL);
}
static void
@@ -522,6 +523,7 @@ build_mcfg(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
AcpiTableMcfg *mcfg;
const MemMapEntry *memmap = vms->memmap;
int len = sizeof(*mcfg) + sizeof(mcfg->allocation[0]);
+ int mcfg_start = table_data->len;
mcfg = acpi_data_push(table_data, len);
mcfg->allocation[0].address = cpu_to_le64(memmap[VIRT_PCIE_ECAM].base);
@@ -532,7 +534,8 @@ build_mcfg(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
mcfg->allocation[0].end_bus_number = (memmap[VIRT_PCIE_ECAM].size
/ PCIE_MMCFG_SIZE_MIN) - 1;
- build_header(linker, table_data, (void *)mcfg, "MCFG", len, 1, NULL, NULL);
+ build_header(linker, table_data, (void *)(table_data->data + mcfg_start),
+ "MCFG", table_data->len - mcfg_start, 1, NULL, NULL);
}
/* GTDT */
@@ -651,6 +654,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
static void build_fadt(GArray *table_data, BIOSLinker *linker,
VirtMachineState *vms, unsigned dsdt_tbl_offset)
{
+ int fadt_start = table_data->len;
AcpiFadtDescriptorRev5_1 *fadt = acpi_data_push(table_data, sizeof(*fadt));
unsigned xdsdt_entry_offset = (char *)&fadt->x_dsdt - table_data->data;
uint16_t bootflags;
@@ -681,8 +685,8 @@ static void build_fadt(GArray *table_data, BIOSLinker *linker,
ACPI_BUILD_TABLE_FILE, xdsdt_entry_offset, sizeof(fadt->x_dsdt),
ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset);
- build_header(linker, table_data,
- (void *)fadt, "FACP", sizeof(*fadt), 5, NULL, NULL);
+ build_header(linker, table_data, (void *)(table_data->data + fadt_start),
+ "FACP", table_data->len - fadt_start, 5, NULL, NULL);
}
/* DSDT */
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
index 5a0e2a3..d701e49 100644
--- a/hw/intc/arm_gic.c
+++ b/hw/intc/arm_gic.c
@@ -1261,7 +1261,8 @@ static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset,
default:
qemu_log_mask(LOG_GUEST_ERROR,
"gic_cpu_read: Bad offset %x\n", (int)offset);
- return MEMTX_ERROR;
+ *data = 0;
+ break;
}
return MEMTX_OK;
}
@@ -1329,7 +1330,7 @@ static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset,
default:
qemu_log_mask(LOG_GUEST_ERROR,
"gic_cpu_write: Bad offset %x\n", (int)offset);
- return MEMTX_ERROR;
+ return MEMTX_OK;
}
gic_update(s);
return MEMTX_OK;
diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c
index 3ea3dd0..93fe936 100644
--- a/hw/intc/arm_gicv3_dist.c
+++ b/hw/intc/arm_gicv3_dist.c
@@ -817,6 +817,13 @@ MemTxResult gicv3_dist_read(void *opaque, hwaddr offset, uint64_t *data,
"%s: invalid guest read at offset " TARGET_FMT_plx
"size %u\n", __func__, offset, size);
trace_gicv3_dist_badread(offset, size, attrs.secure);
+ /* The spec requires that reserved registers are RAZ/WI;
+ * so use MEMTX_ERROR returns from leaf functions as a way to
+ * trigger the guest-error logging but don't return it to
+ * the caller, or we'll cause a spurious guest data abort.
+ */
+ r = MEMTX_OK;
+ *data = 0;
} else {
trace_gicv3_dist_read(offset, *data, size, attrs.secure);
}
@@ -852,6 +859,12 @@ MemTxResult gicv3_dist_write(void *opaque, hwaddr offset, uint64_t data,
"%s: invalid guest write at offset " TARGET_FMT_plx
"size %u\n", __func__, offset, size);
trace_gicv3_dist_badwrite(offset, data, size, attrs.secure);
+ /* The spec requires that reserved registers are RAZ/WI;
+ * so use MEMTX_ERROR returns from leaf functions as a way to
+ * trigger the guest-error logging but don't return it to
+ * the caller, or we'll cause a spurious guest data abort.
+ */
+ r = MEMTX_OK;
} else {
trace_gicv3_dist_write(offset, data, size, attrs.secure);
}
diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c
index 2bd2f0f..284c0a7 100644
--- a/hw/intc/arm_gicv3_its_common.c
+++ b/hw/intc/arm_gicv3_its_common.c
@@ -67,7 +67,8 @@ static MemTxResult gicv3_its_trans_read(void *opaque, hwaddr offset,
MemTxAttrs attrs)
{
qemu_log_mask(LOG_GUEST_ERROR, "ITS read at offset 0x%"PRIx64"\n", offset);
- return MEMTX_ERROR;
+ *data = 0;
+ return MEMTX_OK;
}
static MemTxResult gicv3_its_trans_write(void *opaque, hwaddr offset,
@@ -82,15 +83,12 @@ static MemTxResult gicv3_its_trans_write(void *opaque, hwaddr offset,
if (ret <= 0) {
qemu_log_mask(LOG_GUEST_ERROR,
"ITS: Error sending MSI: %s\n", strerror(-ret));
- return MEMTX_DECODE_ERROR;
}
-
- return MEMTX_OK;
} else {
qemu_log_mask(LOG_GUEST_ERROR,
"ITS write at bad offset 0x%"PRIx64"\n", offset);
- return MEMTX_DECODE_ERROR;
}
+ return MEMTX_OK;
}
static const MemoryRegionOps gicv3_its_trans_ops = {
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
index 77e5cfa..8a8684d 100644
--- a/hw/intc/arm_gicv3_redist.c
+++ b/hw/intc/arm_gicv3_redist.c
@@ -455,6 +455,13 @@ MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data,
"size %u\n", __func__, offset, size);
trace_gicv3_redist_badread(gicv3_redist_affid(cs), offset,
size, attrs.secure);
+ /* The spec requires that reserved registers are RAZ/WI;
+ * so use MEMTX_ERROR returns from leaf functions as a way to
+ * trigger the guest-error logging but don't return it to
+ * the caller, or we'll cause a spurious guest data abort.
+ */
+ r = MEMTX_OK;
+ *data = 0;
} else {
trace_gicv3_redist_read(gicv3_redist_affid(cs), offset, *data,
size, attrs.secure);
@@ -505,6 +512,12 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
"size %u\n", __func__, offset, size);
trace_gicv3_redist_badwrite(gicv3_redist_affid(cs), offset, data,
size, attrs.secure);
+ /* The spec requires that reserved registers are RAZ/WI;
+ * so use MEMTX_ERROR returns from leaf functions as a way to
+ * trigger the guest-error logging but don't return it to
+ * the caller, or we'll cause a spurious guest data abort.
+ */
+ r = MEMTX_OK;
} else {
trace_gicv3_redist_write(gicv3_redist_affid(cs), offset, data,
size, attrs.secure);
diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c
index 90e6ee3..4fb48f6 100644
--- a/hw/net/imx_fec.c
+++ b/hw/net/imx_fec.c
@@ -196,6 +196,31 @@ static const char *imx_eth_reg_name(IMXFECState *s, uint32_t index)
}
}
+/*
+ * Versions of this device with more than one TX descriptor save the
+ * 2nd and 3rd descriptors in a subsection, to maintain migration
+ * compatibility with previous versions of the device that only
+ * supported a single descriptor.
+ */
+static bool imx_eth_is_multi_tx_ring(void *opaque)
+{
+ IMXFECState *s = IMX_FEC(opaque);
+
+ return s->tx_ring_num > 1;
+}
+
+static const VMStateDescription vmstate_imx_eth_txdescs = {
+ .name = "imx.fec/txdescs",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = imx_eth_is_multi_tx_ring,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(tx_descriptor[1], IMXFECState),
+ VMSTATE_UINT32(tx_descriptor[2], IMXFECState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_imx_eth = {
.name = TYPE_IMX_FEC,
.version_id = 2,
@@ -203,15 +228,18 @@ static const VMStateDescription vmstate_imx_eth = {
.fields = (VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, IMXFECState, ENET_MAX),
VMSTATE_UINT32(rx_descriptor, IMXFECState),
- VMSTATE_UINT32(tx_descriptor, IMXFECState),
-
+ VMSTATE_UINT32(tx_descriptor[0], IMXFECState),
VMSTATE_UINT32(phy_status, IMXFECState),
VMSTATE_UINT32(phy_control, IMXFECState),
VMSTATE_UINT32(phy_advertise, IMXFECState),
VMSTATE_UINT32(phy_int, IMXFECState),
VMSTATE_UINT32(phy_int_mask, IMXFECState),
VMSTATE_END_OF_LIST()
- }
+ },
+ .subsections = (const VMStateDescription * []) {
+ &vmstate_imx_eth_txdescs,
+ NULL
+ },
};
#define PHY_INT_ENERGYON (1 << 7)
@@ -405,9 +433,8 @@ static void imx_eth_update(IMXFECState *s)
static void imx_fec_do_tx(IMXFECState *s)
{
int frame_size = 0, descnt = 0;
- uint8_t frame[ENET_MAX_FRAME_SIZE];
- uint8_t *ptr = frame;
- uint32_t addr = s->tx_descriptor;
+ uint8_t *ptr = s->frame;
+ uint32_t addr = s->tx_descriptor[0];
while (descnt++ < IMX_MAX_DESC) {
IMXFECBufDesc bd;
@@ -431,8 +458,8 @@ static void imx_fec_do_tx(IMXFECState *s)
frame_size += len;
if (bd.flags & ENET_BD_L) {
/* Last buffer in frame. */
- qemu_send_packet(qemu_get_queue(s->nic), frame, frame_size);
- ptr = frame;
+ qemu_send_packet(qemu_get_queue(s->nic), s->frame, frame_size);
+ ptr = s->frame;
frame_size = 0;
s->regs[ENET_EIR] |= ENET_INT_TXF;
}
@@ -448,17 +475,47 @@ static void imx_fec_do_tx(IMXFECState *s)
}
}
- s->tx_descriptor = addr;
+ s->tx_descriptor[0] = addr;
imx_eth_update(s);
}
-static void imx_enet_do_tx(IMXFECState *s)
+static void imx_enet_do_tx(IMXFECState *s, uint32_t index)
{
int frame_size = 0, descnt = 0;
- uint8_t frame[ENET_MAX_FRAME_SIZE];
- uint8_t *ptr = frame;
- uint32_t addr = s->tx_descriptor;
+
+ uint8_t *ptr = s->frame;
+ uint32_t addr, int_txb, int_txf, tdsr;
+ size_t ring;
+
+ switch (index) {
+ case ENET_TDAR:
+ ring = 0;
+ int_txb = ENET_INT_TXB;
+ int_txf = ENET_INT_TXF;
+ tdsr = ENET_TDSR;
+ break;
+ case ENET_TDAR1:
+ ring = 1;
+ int_txb = ENET_INT_TXB1;
+ int_txf = ENET_INT_TXF1;
+ tdsr = ENET_TDSR1;
+ break;
+ case ENET_TDAR2:
+ ring = 2;
+ int_txb = ENET_INT_TXB2;
+ int_txf = ENET_INT_TXF2;
+ tdsr = ENET_TDSR2;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bogus value for index %x\n",
+ __func__, index);
+ abort();
+ break;
+ }
+
+ addr = s->tx_descriptor[ring];
while (descnt++ < IMX_MAX_DESC) {
IMXENETBufDesc bd;
@@ -482,13 +539,13 @@ static void imx_enet_do_tx(IMXFECState *s)
frame_size += len;
if (bd.flags & ENET_BD_L) {
if (bd.option & ENET_BD_PINS) {
- struct ip_header *ip_hd = PKT_GET_IP_HDR(frame);
+ struct ip_header *ip_hd = PKT_GET_IP_HDR(s->frame);
if (IP_HEADER_VERSION(ip_hd) == 4) {
- net_checksum_calculate(frame, frame_size);
+ net_checksum_calculate(s->frame, frame_size);
}
}
if (bd.option & ENET_BD_IINS) {
- struct ip_header *ip_hd = PKT_GET_IP_HDR(frame);
+ struct ip_header *ip_hd = PKT_GET_IP_HDR(s->frame);
/* We compute checksum only for IPv4 frames */
if (IP_HEADER_VERSION(ip_hd) == 4) {
uint16_t csum;
@@ -498,57 +555,59 @@ static void imx_enet_do_tx(IMXFECState *s)
}
}
/* Last buffer in frame. */
- qemu_send_packet(qemu_get_queue(s->nic), frame, len);
- ptr = frame;
+
+ qemu_send_packet(qemu_get_queue(s->nic), s->frame, frame_size);
+ ptr = s->frame;
+
frame_size = 0;
if (bd.option & ENET_BD_TX_INT) {
- s->regs[ENET_EIR] |= ENET_INT_TXF;
+ s->regs[ENET_EIR] |= int_txf;
}
}
if (bd.option & ENET_BD_TX_INT) {
- s->regs[ENET_EIR] |= ENET_INT_TXB;
+ s->regs[ENET_EIR] |= int_txb;
}
bd.flags &= ~ENET_BD_R;
/* Write back the modified descriptor. */
imx_enet_write_bd(&bd, addr);
/* Advance to the next descriptor. */
if ((bd.flags & ENET_BD_W) != 0) {
- addr = s->regs[ENET_TDSR];
+ addr = s->regs[tdsr];
} else {
addr += sizeof(bd);
}
}
- s->tx_descriptor = addr;
+ s->tx_descriptor[ring] = addr;
imx_eth_update(s);
}
-static void imx_eth_do_tx(IMXFECState *s)
+static void imx_eth_do_tx(IMXFECState *s, uint32_t index)
{
if (!s->is_fec && (s->regs[ENET_ECR] & ENET_ECR_EN1588)) {
- imx_enet_do_tx(s);
+ imx_enet_do_tx(s, index);
} else {
imx_fec_do_tx(s);
}
}
-static void imx_eth_enable_rx(IMXFECState *s)
+static void imx_eth_enable_rx(IMXFECState *s, bool flush)
{
IMXFECBufDesc bd;
- bool tmp;
+ bool rx_ring_full;
imx_fec_read_bd(&bd, s->rx_descriptor);
- tmp = ((bd.flags & ENET_BD_E) != 0);
+ rx_ring_full = !(bd.flags & ENET_BD_E);
- if (!tmp) {
+ if (rx_ring_full) {
FEC_PRINTF("RX buffer full\n");
- } else if (!s->regs[ENET_RDAR]) {
+ } else if (flush) {
qemu_flush_queued_packets(qemu_get_queue(s->nic));
}
- s->regs[ENET_RDAR] = tmp ? ENET_RDAR_RDAR : 0;
+ s->regs[ENET_RDAR] = rx_ring_full ? 0 : ENET_RDAR_RDAR;
}
static void imx_eth_reset(DeviceState *d)
@@ -585,7 +644,7 @@ static void imx_eth_reset(DeviceState *d)
}
s->rx_descriptor = 0;
- s->tx_descriptor = 0;
+ memset(s->tx_descriptor, 0, sizeof(s->tx_descriptor));
/* We also reset the PHY */
phy_reset(s);
@@ -791,6 +850,7 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value,
unsigned size)
{
IMXFECState *s = IMX_FEC(opaque);
+ const bool single_tx_ring = !imx_eth_is_multi_tx_ring(s);
uint32_t index = offset >> 2;
FEC_PRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx_eth_reg_name(s, index),
@@ -807,16 +867,24 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value,
if (s->regs[ENET_ECR] & ENET_ECR_ETHEREN) {
if (!s->regs[index]) {
s->regs[index] = ENET_RDAR_RDAR;
- imx_eth_enable_rx(s);
+ imx_eth_enable_rx(s, true);
}
} else {
s->regs[index] = 0;
}
break;
- case ENET_TDAR:
+ case ENET_TDAR1: /* FALLTHROUGH */
+ case ENET_TDAR2: /* FALLTHROUGH */
+ if (unlikely(single_tx_ring)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "[%s]%s: trying to access TDAR2 or TDAR1\n",
+ TYPE_IMX_FEC, __func__);
+ return;
+ }
+ case ENET_TDAR: /* FALLTHROUGH */
if (s->regs[ENET_ECR] & ENET_ECR_ETHEREN) {
s->regs[index] = ENET_TDAR_TDAR;
- imx_eth_do_tx(s);
+ imx_eth_do_tx(s, index);
}
s->regs[index] = 0;
break;
@@ -828,8 +896,12 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value,
if ((s->regs[index] & ENET_ECR_ETHEREN) == 0) {
s->regs[ENET_RDAR] = 0;
s->rx_descriptor = s->regs[ENET_RDSR];
- s->regs[ENET_TDAR] = 0;
- s->tx_descriptor = s->regs[ENET_TDSR];
+ s->regs[ENET_TDAR] = 0;
+ s->regs[ENET_TDAR1] = 0;
+ s->regs[ENET_TDAR2] = 0;
+ s->tx_descriptor[0] = s->regs[ENET_TDSR];
+ s->tx_descriptor[1] = s->regs[ENET_TDSR1];
+ s->tx_descriptor[2] = s->regs[ENET_TDSR2];
}
break;
case ENET_MMFR:
@@ -907,7 +979,29 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value,
} else {
s->regs[index] = value & ~7;
}
- s->tx_descriptor = s->regs[index];
+ s->tx_descriptor[0] = s->regs[index];
+ break;
+ case ENET_TDSR1:
+ if (unlikely(single_tx_ring)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "[%s]%s: trying to access TDSR1\n",
+ TYPE_IMX_FEC, __func__);
+ return;
+ }
+
+ s->regs[index] = value & ~7;
+ s->tx_descriptor[1] = s->regs[index];
+ break;
+ case ENET_TDSR2:
+ if (unlikely(single_tx_ring)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "[%s]%s: trying to access TDSR2\n",
+ TYPE_IMX_FEC, __func__);
+ return;
+ }
+
+ s->regs[index] = value & ~7;
+ s->tx_descriptor[2] = s->regs[index];
break;
case ENET_MRBR:
s->regs[index] = value & 0x00003ff0;
@@ -930,7 +1024,7 @@ static int imx_eth_can_receive(NetClientState *nc)
FEC_PRINTF("\n");
- return s->regs[ENET_RDAR] ? 1 : 0;
+ return !!s->regs[ENET_RDAR];
}
static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf,
@@ -1020,7 +1114,7 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf,
}
}
s->rx_descriptor = addr;
- imx_eth_enable_rx(s);
+ imx_eth_enable_rx(s, false);
imx_eth_update(s);
return len;
}
@@ -1037,6 +1131,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf,
uint8_t *crc_ptr;
unsigned int buf_len;
size_t size = len;
+ bool shift16 = s->regs[ENET_RACC] & ENET_RACC_SHIFT16;
FEC_PRINTF("len %d\n", (int)size);
@@ -1051,9 +1146,13 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf,
crc = cpu_to_be32(crc32(~0, buf, size));
crc_ptr = (uint8_t *) &crc;
- /* Huge frames are truncted. */
- if (size > ENET_MAX_FRAME_SIZE) {
- size = ENET_MAX_FRAME_SIZE;
+ if (shift16) {
+ size += 2;
+ }
+
+ /* Huge frames are truncated. */
+ if (size > s->regs[ENET_FTRL]) {
+ size = s->regs[ENET_FTRL];
flags |= ENET_BD_TR | ENET_BD_LG;
}
@@ -1076,7 +1175,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf,
TYPE_IMX_FEC, __func__);
break;
}
- buf_len = (size <= s->regs[ENET_MRBR]) ? size : s->regs[ENET_MRBR];
+ buf_len = MIN(size, s->regs[ENET_MRBR]);
bd.length = buf_len;
size -= buf_len;
@@ -1087,6 +1186,24 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf,
buf_len += size - 4;
}
buf_addr = bd.data;
+
+ if (shift16) {
+ /*
+ * If SHIFT16 bit of ENETx_RACC register is set we need to
+ * align the payload to 4-byte boundary.
+ */
+ const uint8_t zeros[2] = { 0 };
+
+ dma_memory_write(&address_space_memory, buf_addr,
+ zeros, sizeof(zeros));
+
+ buf_addr += sizeof(zeros);
+ buf_len -= sizeof(zeros);
+
+ /* We only do this once per Ethernet frame */
+ shift16 = false;
+ }
+
dma_memory_write(&address_space_memory, buf_addr, buf, buf_len);
buf += buf_len;
if (size < 4) {
@@ -1116,7 +1233,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf,
}
}
s->rx_descriptor = addr;
- imx_eth_enable_rx(s);
+ imx_eth_enable_rx(s, false);
imx_eth_update(s);
return len;
}
@@ -1164,15 +1281,13 @@ static void imx_eth_realize(DeviceState *dev, Error **errp)
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
memory_region_init_io(&s->iomem, OBJECT(dev), &imx_eth_ops, s,
- TYPE_IMX_FEC, 0x400);
+ TYPE_IMX_FEC, FSL_IMX25_FEC_SIZE);
sysbus_init_mmio(sbd, &s->iomem);
sysbus_init_irq(sbd, &s->irq[0]);
sysbus_init_irq(sbd, &s->irq[1]);
qemu_macaddr_default_if_unset(&s->conf.macaddr);
- s->conf.peers.ncs[0] = nd_table[0].netdev;
-
s->nic = qemu_new_nic(&imx_eth_net_info, &s->conf,
object_get_typename(OBJECT(dev)),
DEVICE(dev)->id, s);
@@ -1182,6 +1297,7 @@ static void imx_eth_realize(DeviceState *dev, Error **errp)
static Property imx_eth_properties[] = {
DEFINE_NIC_PROPERTIES(IMXFECState, conf),
+ DEFINE_PROP_UINT32("tx-ring-num", IMXFECState, tx_ring_num, 1),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c
index 3deccf0..82f8ec0 100644
--- a/hw/sd/pxa2xx_mmci.c
+++ b/hw/sd/pxa2xx_mmci.c
@@ -19,6 +19,8 @@
#include "hw/qdev.h"
#include "hw/qdev-properties.h"
#include "qemu/error-report.h"
+#include "qemu/log.h"
+#include "trace.h"
#define TYPE_PXA2XX_MMCI "pxa2xx-mmci"
#define PXA2XX_MMCI(obj) OBJECT_CHECK(PXA2xxMMCIState, (obj), TYPE_PXA2XX_MMCI)
@@ -278,45 +280,56 @@ static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s)
static uint64_t pxa2xx_mmci_read(void *opaque, hwaddr offset, unsigned size)
{
PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
- uint32_t ret;
+ uint32_t ret = 0;
switch (offset) {
case MMC_STRPCL:
- return 0;
+ break;
case MMC_STAT:
- return s->status;
+ ret = s->status;
+ break;
case MMC_CLKRT:
- return s->clkrt;
+ ret = s->clkrt;
+ break;
case MMC_SPI:
- return s->spi;
+ ret = s->spi;
+ break;
case MMC_CMDAT:
- return s->cmdat;
+ ret = s->cmdat;
+ break;
case MMC_RESTO:
- return s->resp_tout;
+ ret = s->resp_tout;
+ break;
case MMC_RDTO:
- return s->read_tout;
+ ret = s->read_tout;
+ break;
case MMC_BLKLEN:
- return s->blklen;
+ ret = s->blklen;
+ break;
case MMC_NUMBLK:
- return s->numblk;
+ ret = s->numblk;
+ break;
case MMC_PRTBUF:
- return 0;
+ break;
case MMC_I_MASK:
- return s->intmask;
+ ret = s->intmask;
+ break;
case MMC_I_REG:
- return s->intreq;
+ ret = s->intreq;
+ break;
case MMC_CMD:
- return s->cmd | 0x40;
+ ret = s->cmd | 0x40;
+ break;
case MMC_ARGH:
- return s->arg >> 16;
+ ret = s->arg >> 16;
+ break;
case MMC_ARGL:
- return s->arg & 0xffff;
+ ret = s->arg & 0xffff;
+ break;
case MMC_RES:
- if (s->resp_len < 9)
- return s->resp_fifo[s->resp_len ++];
- return 0;
+ ret = (s->resp_len < 9) ? s->resp_fifo[s->resp_len++] : 0;
+ break;
case MMC_RXFIFO:
- ret = 0;
while (size-- && s->rx_len) {
ret |= s->rx_fifo[s->rx_start++] << (size << 3);
s->rx_start &= 0x1f;
@@ -324,16 +337,20 @@ static uint64_t pxa2xx_mmci_read(void *opaque, hwaddr offset, unsigned size)
}
s->intreq &= ~INT_RXFIFO_REQ;
pxa2xx_mmci_fifo_update(s);
- return ret;
+ break;
case MMC_RDWAIT:
- return 0;
+ break;
case MMC_BLKS_REM:
- return s->numblk;
+ ret = s->numblk;
+ break;
default:
- hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: incorrect register 0x%02" HWADDR_PRIx "\n",
+ __func__, offset);
}
+ trace_pxa2xx_mmci_read(size, offset, ret);
- return 0;
+ return ret;
}
static void pxa2xx_mmci_write(void *opaque,
@@ -341,6 +358,7 @@ static void pxa2xx_mmci_write(void *opaque,
{
PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+ trace_pxa2xx_mmci_write(size, offset, value);
switch (offset) {
case MMC_STRPCL:
if (value & STRPCL_STRT_CLK) {
@@ -368,8 +386,10 @@ static void pxa2xx_mmci_write(void *opaque,
case MMC_SPI:
s->spi = value & 0xf;
- if (value & SPI_SPI_MODE)
- printf("%s: attempted to use card in SPI mode\n", __FUNCTION__);
+ if (value & SPI_SPI_MODE) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: attempted to use card in SPI mode\n", __func__);
+ }
break;
case MMC_CMDAT:
@@ -442,7 +462,9 @@ static void pxa2xx_mmci_write(void *opaque,
break;
default:
- hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: incorrect reg 0x%02" HWADDR_PRIx " "
+ "(value 0x%08" PRIx64 ")\n", __func__, offset, value);
}
}
diff --git a/hw/sd/trace-events b/hw/sd/trace-events
index 1fc0bcf..6eca347 100644
--- a/hw/sd/trace-events
+++ b/hw/sd/trace-events
@@ -3,3 +3,7 @@
# hw/sd/milkymist-memcard.c
milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
+
+# hw/sd/pxa2xx_mmci.c
+pxa2xx_mmci_read(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x"
+pxa2xx_mmci_write(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x"
diff --git a/hw/timer/pxa2xx_timer.c b/hw/timer/pxa2xx_timer.c
index 68ba5a7..a489bf5 100644
--- a/hw/timer/pxa2xx_timer.c
+++ b/hw/timer/pxa2xx_timer.c
@@ -13,6 +13,7 @@
#include "sysemu/sysemu.h"
#include "hw/arm/pxa.h"
#include "hw/sysbus.h"
+#include "qemu/log.h"
#define OSMR0 0x00
#define OSMR1 0x04
@@ -252,8 +253,14 @@ static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset,
case OSNR:
return s->snapshot;
default:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: unknown register 0x%02" HWADDR_PRIx "\n",
+ __func__, offset);
+ break;
badreg:
- hw_error("pxa2xx_timer_read: Bad offset " REG_FMT "\n", offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: incorrect register 0x%02" HWADDR_PRIx "\n",
+ __func__, offset);
}
return 0;
@@ -377,8 +384,14 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset,
}
break;
default:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: unknown register 0x%02" HWADDR_PRIx " "
+ "(value 0x%08" PRIx64 ")\n", __func__, offset, value);
+ break;
badreg:
- hw_error("pxa2xx_timer_write: Bad offset " REG_FMT "\n", offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: incorrect register 0x%02" HWADDR_PRIx " "
+ "(value 0x%08" PRIx64 ")\n", __func__, offset, value);
}
}