aboutsummaryrefslogtreecommitdiff
path: root/hw/net/ftgmac100.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/net/ftgmac100.c')
-rw-r--r--hw/net/ftgmac100.c178
1 files changed, 140 insertions, 38 deletions
diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c
index 74b6c3d..c41ce88 100644
--- a/hw/net/ftgmac100.c
+++ b/hw/net/ftgmac100.c
@@ -14,7 +14,7 @@
#include "qemu/osdep.h"
#include "hw/irq.h"
#include "hw/net/ftgmac100.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "qapi/error.h"
#include "qemu/log.h"
#include "qemu/module.h"
@@ -24,8 +24,7 @@
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
-/* For crc32 */
-#include <zlib.h>
+#include <zlib.h> /* for crc32 */
/*
* FTGMAC100 registers
@@ -57,6 +56,16 @@
#define FTGMAC100_FCR 0x68
/*
+ * FTGMAC100 registers high
+ *
+ * values below are offset by - FTGMAC100_REG_HIGH_OFFSET from datasheet
+ * because its memory region is start at FTGMAC100_REG_HIGH_OFFSET
+ */
+#define FTGMAC100_NPTXR_BADR_HIGH (0x17C - FTGMAC100_REG_HIGH_OFFSET)
+#define FTGMAC100_HPTXR_BADR_HIGH (0x184 - FTGMAC100_REG_HIGH_OFFSET)
+#define FTGMAC100_RXR_BADR_HIGH (0x18C - FTGMAC100_REG_HIGH_OFFSET)
+
+/*
* Interrupt status register & interrupt enable register
*/
#define FTGMAC100_INT_RPKT_BUF (1 << 0)
@@ -165,6 +174,8 @@
#define FTGMAC100_TXDES1_TX2FIC (1 << 30)
#define FTGMAC100_TXDES1_TXIC (1 << 31)
+#define FTGMAC100_TXDES2_TXBUF_BADR_HI(x) (((x) >> 16) & 0x7)
+
/*
* Receive descriptor
*/
@@ -198,13 +209,15 @@
#define FTGMAC100_RXDES1_UDP_CHKSUM_ERR (1 << 26)
#define FTGMAC100_RXDES1_IP_CHKSUM_ERR (1 << 27)
+#define FTGMAC100_RXDES2_RXBUF_BADR_HI(x) (((x) >> 16) & 0x7)
+
/*
* Receive and transmit Buffer Descriptor
*/
typedef struct {
uint32_t des0;
uint32_t des1;
- uint32_t des2; /* not used by HW */
+ uint32_t des2; /* used by HW 64 bits DMA */
uint32_t des3;
} FTGMAC100Desc;
@@ -238,7 +251,8 @@ typedef struct {
*/
#define FTGMAC100_MAX_FRAME_SIZE 9220
-/* Limits depending on the type of the frame
+/*
+ * Limits depending on the type of the frame
*
* 9216 for Jumbo frames (+ 4 for VLAN)
* 1518 for other frames (+ 4 for VLAN)
@@ -514,12 +528,13 @@ out:
return frame_size;
}
-static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring,
- uint32_t tx_descriptor)
+static void ftgmac100_do_tx(FTGMAC100State *s, uint64_t tx_ring,
+ uint64_t tx_descriptor)
{
int frame_size = 0;
uint8_t *ptr = s->frame;
- uint32_t addr = tx_descriptor;
+ uint64_t addr = tx_descriptor;
+ uint64_t buf_addr = 0;
uint32_t flags = 0;
while (1) {
@@ -533,8 +548,10 @@ static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring,
break;
}
- /* record transmit flags as they are valid only on the first
- * segment */
+ /*
+ * record transmit flags as they are valid only on the first
+ * segment
+ */
if (bd.des0 & FTGMAC100_TXDES0_FTS) {
flags = bd.des1;
}
@@ -556,7 +573,12 @@ static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring,
len = sizeof(s->frame) - frame_size;
}
- if (dma_memory_read(&address_space_memory, bd.des3,
+ buf_addr = bd.des3;
+ if (s->dma64) {
+ buf_addr = deposit64(buf_addr, 32, 32,
+ FTGMAC100_TXDES2_TXBUF_BADR_HI(bd.des2));
+ }
+ if (dma_memory_read(&address_space_memory, buf_addr,
ptr, len, MEMTXATTRS_UNSPECIFIED)) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to read packet @ 0x%x\n",
__func__, bd.des3);
@@ -639,7 +661,8 @@ static bool ftgmac100_can_receive(NetClientState *nc)
*/
static uint32_t ftgmac100_rxpoll(FTGMAC100State *s)
{
- /* Polling times :
+ /*
+ * Polling times :
*
* Speed TIME_SEL=0 TIME_SEL=1
*
@@ -722,9 +745,9 @@ static uint64_t ftgmac100_read(void *opaque, hwaddr addr, unsigned size)
case FTGMAC100_MATH1:
return s->math[1];
case FTGMAC100_RXR_BADR:
- return s->rx_ring;
+ return extract64(s->rx_ring, 0, 32);
case FTGMAC100_NPTXR_BADR:
- return s->tx_ring;
+ return extract64(s->tx_ring, 0, 32);
case FTGMAC100_ITC:
return s->itc;
case FTGMAC100_DBLAC:
@@ -795,9 +818,8 @@ static void ftgmac100_write(void *opaque, hwaddr addr,
HWADDR_PRIx "\n", __func__, value);
return;
}
-
- s->rx_ring = value;
- s->rx_descriptor = s->rx_ring;
+ s->rx_ring = deposit64(s->rx_ring, 0, 32, value);
+ s->rx_descriptor = deposit64(s->rx_descriptor, 0, 32, value);
break;
case FTGMAC100_RBSR: /* DMA buffer size */
@@ -810,8 +832,8 @@ static void ftgmac100_write(void *opaque, hwaddr addr,
HWADDR_PRIx "\n", __func__, value);
return;
}
- s->tx_ring = value;
- s->tx_descriptor = s->tx_ring;
+ s->tx_ring = deposit64(s->tx_ring, 0, 32, value);
+ s->tx_descriptor = deposit64(s->tx_descriptor, 0, 32, value);
break;
case FTGMAC100_NPTXPD: /* Trigger transmit */
@@ -910,6 +932,60 @@ static void ftgmac100_write(void *opaque, hwaddr addr,
ftgmac100_update_irq(s);
}
+static uint64_t ftgmac100_high_read(void *opaque, hwaddr addr, unsigned size)
+{
+ FTGMAC100State *s = FTGMAC100(opaque);
+ uint64_t val = 0;
+
+ switch (addr) {
+ case FTGMAC100_NPTXR_BADR_HIGH:
+ val = extract64(s->tx_ring, 32, 32);
+ break;
+ case FTGMAC100_HPTXR_BADR_HIGH:
+ /* High Priority Transmit Ring Base High Address */
+ qemu_log_mask(LOG_UNIMP, "%s: read to unimplemented register 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ break;
+ case FTGMAC100_RXR_BADR_HIGH:
+ val = extract64(s->rx_ring, 32, 32);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address at offset 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ break;
+ }
+
+ return val;
+}
+
+static void ftgmac100_high_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ FTGMAC100State *s = FTGMAC100(opaque);
+
+ switch (addr) {
+ case FTGMAC100_NPTXR_BADR_HIGH:
+ s->tx_ring = deposit64(s->tx_ring, 32, 32, value);
+ s->tx_descriptor = deposit64(s->tx_descriptor, 32, 32, value);
+ break;
+ case FTGMAC100_HPTXR_BADR_HIGH:
+ /* High Priority Transmit Ring Base High Address */
+ qemu_log_mask(LOG_UNIMP, "%s: write to unimplemented register 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ break;
+ case FTGMAC100_RXR_BADR_HIGH:
+ s->rx_ring = deposit64(s->rx_ring, 32, 32, value);
+ s->rx_descriptor = deposit64(s->rx_descriptor, 32, 32, value);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address at offset 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ break;
+ }
+
+ ftgmac100_update_irq(s);
+}
+
static int ftgmac100_filter(FTGMAC100State *s, const uint8_t *buf, size_t len)
{
unsigned mcast_idx;
@@ -953,9 +1029,9 @@ static ssize_t ftgmac100_receive(NetClientState *nc, const uint8_t *buf,
FTGMAC100State *s = FTGMAC100(qemu_get_nic_opaque(nc));
FTGMAC100Desc bd;
uint32_t flags = 0;
- uint32_t addr;
+ uint64_t addr;
uint32_t crc;
- uint32_t buf_addr;
+ uint64_t buf_addr = 0;
uint8_t *crc_ptr;
uint32_t buf_len;
size_t size = len;
@@ -1020,7 +1096,12 @@ static ssize_t ftgmac100_receive(NetClientState *nc, const uint8_t *buf,
if (size < 4) {
buf_len += size - 4;
}
+
buf_addr = bd.des3;
+ if (s->dma64) {
+ buf_addr = deposit64(buf_addr, 32, 32,
+ FTGMAC100_RXDES2_RXBUF_BADR_HI(bd.des2));
+ }
if (first && proto == ETH_P_VLAN && buf_len >= 18) {
bd.des1 = lduw_be_p(buf + 14) | FTGMAC100_RXDES1_VLANTAG_AVAIL;
@@ -1074,6 +1155,14 @@ static const MemoryRegionOps ftgmac100_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
+static const MemoryRegionOps ftgmac100_high_ops = {
+ .read = ftgmac100_high_read,
+ .write = ftgmac100_high_write,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
static void ftgmac100_cleanup(NetClientState *nc)
{
FTGMAC100State *s = FTGMAC100(qemu_get_nic_opaque(nc));
@@ -1103,9 +1192,23 @@ static void ftgmac100_realize(DeviceState *dev, Error **errp)
s->rxdes0_edorr = FTGMAC100_RXDES0_EDORR;
}
- memory_region_init_io(&s->iomem, OBJECT(dev), &ftgmac100_ops, s,
- TYPE_FTGMAC100, 0x2000);
- sysbus_init_mmio(sbd, &s->iomem);
+ memory_region_init(&s->iomem_container, OBJECT(s),
+ TYPE_FTGMAC100 ".container", FTGMAC100_MEM_SIZE);
+ sysbus_init_mmio(sbd, &s->iomem_container);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &ftgmac100_ops, s,
+ TYPE_FTGMAC100 ".regs", FTGMAC100_REG_MEM_SIZE);
+ memory_region_add_subregion(&s->iomem_container, 0x0, &s->iomem);
+
+ if (s->dma64) {
+ memory_region_init_io(&s->iomem_high, OBJECT(s), &ftgmac100_high_ops,
+ s, TYPE_FTGMAC100 ".regs.high",
+ FTGMAC100_REG_HIGH_MEM_SIZE);
+ memory_region_add_subregion(&s->iomem_container,
+ FTGMAC100_REG_HIGH_OFFSET,
+ &s->iomem_high);
+ }
+
sysbus_init_irq(sbd, &s->irq);
qemu_macaddr_default_if_unset(&s->conf.macaddr);
@@ -1117,18 +1220,14 @@ static void ftgmac100_realize(DeviceState *dev, Error **errp)
static const VMStateDescription vmstate_ftgmac100 = {
.name = TYPE_FTGMAC100,
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (const VMStateField[]) {
VMSTATE_UINT32(irq_state, FTGMAC100State),
VMSTATE_UINT32(isr, FTGMAC100State),
VMSTATE_UINT32(ier, FTGMAC100State),
VMSTATE_UINT32(rx_enabled, FTGMAC100State),
- VMSTATE_UINT32(rx_ring, FTGMAC100State),
VMSTATE_UINT32(rbsr, FTGMAC100State),
- VMSTATE_UINT32(tx_ring, FTGMAC100State),
- VMSTATE_UINT32(rx_descriptor, FTGMAC100State),
- VMSTATE_UINT32(tx_descriptor, FTGMAC100State),
VMSTATE_UINT32_ARRAY(math, FTGMAC100State, 2),
VMSTATE_UINT32(itc, FTGMAC100State),
VMSTATE_UINT32(aptcr, FTGMAC100State),
@@ -1147,22 +1246,26 @@ static const VMStateDescription vmstate_ftgmac100 = {
VMSTATE_UINT32(phy_int_mask, FTGMAC100State),
VMSTATE_UINT32(txdes0_edotr, FTGMAC100State),
VMSTATE_UINT32(rxdes0_edorr, FTGMAC100State),
+ VMSTATE_UINT64(rx_ring, FTGMAC100State),
+ VMSTATE_UINT64(tx_ring, FTGMAC100State),
+ VMSTATE_UINT64(rx_descriptor, FTGMAC100State),
+ VMSTATE_UINT64(tx_descriptor, FTGMAC100State),
VMSTATE_END_OF_LIST()
}
};
-static Property ftgmac100_properties[] = {
+static const Property ftgmac100_properties[] = {
DEFINE_PROP_BOOL("aspeed", FTGMAC100State, aspeed, false),
DEFINE_NIC_PROPERTIES(FTGMAC100State, conf),
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_BOOL("dma64", FTGMAC100State, dma64, false),
};
-static void ftgmac100_class_init(ObjectClass *klass, void *data)
+static void ftgmac100_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_ftgmac100;
- dc->reset = ftgmac100_reset;
+ device_class_set_legacy_reset(dc, ftgmac100_reset);
device_class_set_props(dc, ftgmac100_properties);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->realize = ftgmac100_realize;
@@ -1311,18 +1414,17 @@ static const VMStateDescription vmstate_aspeed_mii = {
}
};
-static Property aspeed_mii_properties[] = {
+static const Property aspeed_mii_properties[] = {
DEFINE_PROP_LINK("nic", AspeedMiiState, nic, TYPE_FTGMAC100,
FTGMAC100State *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void aspeed_mii_class_init(ObjectClass *klass, void *data)
+static void aspeed_mii_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_aspeed_mii;
- dc->reset = aspeed_mii_reset;
+ device_class_set_legacy_reset(dc, aspeed_mii_reset);
dc->realize = aspeed_mii_realize;
dc->desc = "Aspeed MII controller";
device_class_set_props(dc, aspeed_mii_properties);