]> git.proxmox.com Git - mirror_qemu.git/blobdiff - hw/net/mcf_fec.c
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-5.2-20200818' into staging
[mirror_qemu.git] / hw / net / mcf_fec.c
index 0ee8ad9d6687a20dca2bdbc88b51b224e22fb630..281345862c27f1ba78cee93f54bc591399662c67 100644 (file)
@@ -5,14 +5,19 @@
  *
  * This code is licensed under the GPL
  */
+
 #include "qemu/osdep.h"
-#include "hw/hw.h"
+#include "qemu/log.h"
+#include "hw/irq.h"
 #include "net/net.h"
+#include "qemu/module.h"
 #include "hw/m68k/mcf.h"
+#include "hw/m68k/mcf_fec.h"
 #include "hw/net/mii.h"
+#include "hw/qdev-properties.h"
+#include "hw/sysbus.h"
 /* For crc32 */
 #include <zlib.h>
-#include "exec/address-spaces.h"
 
 //#define DEBUG_FEC 1
 
@@ -23,12 +28,15 @@ do { printf("mcf_fec: " fmt , ## __VA_ARGS__); } while (0)
 #define DPRINTF(fmt, ...) do {} while(0)
 #endif
 
+#define FEC_MAX_DESC 1024
 #define FEC_MAX_FRAME_SIZE 2032
+#define FEC_MIB_SIZE 64
 
 typedef struct {
-    MemoryRegion *sysmem;
+    SysBusDevice parent_obj;
+
     MemoryRegion iomem;
-    qemu_irq *irq;
+    qemu_irq irq[FEC_NUM_IRQ];
     NICState *nic;
     NICConf conf;
     uint32_t irq_state;
@@ -47,6 +55,7 @@ typedef struct {
     uint32_t erdsr;
     uint32_t etdsr;
     uint32_t emrbr;
+    uint32_t mib[FEC_MIB_SIZE];
 } mcf_fec_state;
 
 #define FEC_INT_HB   0x80000000
@@ -67,7 +76,6 @@ typedef struct {
 #define FEC_RESET   1
 
 /* Map interrupt flags onto IRQ lines.  */
-#define FEC_NUM_IRQ 13
 static const uint32_t mcf_fec_irq_map[FEC_NUM_IRQ] = {
     FEC_INT_TXF,
     FEC_INT_TXB,
@@ -108,6 +116,63 @@ typedef struct {
 #define FEC_BD_OV   0x0002
 #define FEC_BD_TR   0x0001
 
+#define MIB_RMON_T_DROP         0
+#define MIB_RMON_T_PACKETS      1
+#define MIB_RMON_T_BC_PKT       2
+#define MIB_RMON_T_MC_PKT       3
+#define MIB_RMON_T_CRC_ALIGN    4
+#define MIB_RMON_T_UNDERSIZE    5
+#define MIB_RMON_T_OVERSIZE     6
+#define MIB_RMON_T_FRAG         7
+#define MIB_RMON_T_JAB          8
+#define MIB_RMON_T_COL          9
+#define MIB_RMON_T_P64          10
+#define MIB_RMON_T_P65TO127     11
+#define MIB_RMON_T_P128TO255    12
+#define MIB_RMON_T_P256TO511    13
+#define MIB_RMON_T_P512TO1023   14
+#define MIB_RMON_T_P1024TO2047  15
+#define MIB_RMON_T_P_GTE2048    16
+#define MIB_RMON_T_OCTETS       17
+#define MIB_IEEE_T_DROP         18
+#define MIB_IEEE_T_FRAME_OK     19
+#define MIB_IEEE_T_1COL         20
+#define MIB_IEEE_T_MCOL         21
+#define MIB_IEEE_T_DEF          22
+#define MIB_IEEE_T_LCOL         23
+#define MIB_IEEE_T_EXCOL        24
+#define MIB_IEEE_T_MACERR       25
+#define MIB_IEEE_T_CSERR        26
+#define MIB_IEEE_T_SQE          27
+#define MIB_IEEE_T_FDXFC        28
+#define MIB_IEEE_T_OCTETS_OK    29
+
+#define MIB_RMON_R_DROP         32
+#define MIB_RMON_R_PACKETS      33
+#define MIB_RMON_R_BC_PKT       34
+#define MIB_RMON_R_MC_PKT       35
+#define MIB_RMON_R_CRC_ALIGN    36
+#define MIB_RMON_R_UNDERSIZE    37
+#define MIB_RMON_R_OVERSIZE     38
+#define MIB_RMON_R_FRAG         39
+#define MIB_RMON_R_JAB          40
+#define MIB_RMON_R_RESVD_0      41
+#define MIB_RMON_R_P64          42
+#define MIB_RMON_R_P65TO127     43
+#define MIB_RMON_R_P128TO255    44
+#define MIB_RMON_R_P256TO511    45
+#define MIB_RMON_R_P512TO1023   46
+#define MIB_RMON_R_P1024TO2047  47
+#define MIB_RMON_R_P_GTE2048    48
+#define MIB_RMON_R_OCTETS       49
+#define MIB_IEEE_R_DROP         50
+#define MIB_IEEE_R_FRAME_OK     51
+#define MIB_IEEE_R_CRC          52
+#define MIB_IEEE_R_ALIGN        53
+#define MIB_IEEE_R_MACERR       54
+#define MIB_IEEE_R_FDXFC        55
+#define MIB_IEEE_R_OCTETS_OK    56
+
 static void mcf_fec_read_bd(mcf_fec_bd *bd, uint32_t addr)
 {
     cpu_physical_memory_read(addr, bd, sizeof(*bd));
@@ -144,12 +209,37 @@ static void mcf_fec_update(mcf_fec_state *s)
     s->irq_state = active;
 }
 
+static void mcf_fec_tx_stats(mcf_fec_state *s, int size)
+{
+    s->mib[MIB_RMON_T_PACKETS]++;
+    s->mib[MIB_RMON_T_OCTETS] += size;
+    if (size < 64) {
+        s->mib[MIB_RMON_T_FRAG]++;
+    } else if (size == 64) {
+        s->mib[MIB_RMON_T_P64]++;
+    } else if (size < 128) {
+        s->mib[MIB_RMON_T_P65TO127]++;
+    } else if (size < 256) {
+        s->mib[MIB_RMON_T_P128TO255]++;
+    } else if (size < 512) {
+        s->mib[MIB_RMON_T_P256TO511]++;
+    } else if (size < 1024) {
+        s->mib[MIB_RMON_T_P512TO1023]++;
+    } else if (size < 2048) {
+        s->mib[MIB_RMON_T_P1024TO2047]++;
+    } else {
+        s->mib[MIB_RMON_T_P_GTE2048]++;
+    }
+    s->mib[MIB_IEEE_T_FRAME_OK]++;
+    s->mib[MIB_IEEE_T_OCTETS_OK] += size;
+}
+
 static void mcf_fec_do_tx(mcf_fec_state *s)
 {
     uint32_t addr;
     mcf_fec_bd bd;
     int frame_size;
-    int len;
+    int len, descnt = 0;
     uint8_t frame[FEC_MAX_FRAME_SIZE];
     uint8_t *ptr;
 
@@ -157,7 +247,7 @@ static void mcf_fec_do_tx(mcf_fec_state *s)
     ptr = frame;
     frame_size = 0;
     addr = s->tx_descriptor;
-    while (1) {
+    while (descnt++ < FEC_MAX_DESC) {
         mcf_fec_read_bd(&bd, addr);
         DPRINTF("tx_bd %x flags %04x len %d data %08x\n",
                 addr, bd.flags, bd.length, bd.data);
@@ -176,7 +266,8 @@ static void mcf_fec_do_tx(mcf_fec_state *s)
         if (bd.flags & FEC_BD_L) {
             /* Last buffer in frame.  */
             DPRINTF("Sending packet\n");
-            qemu_send_packet(qemu_get_queue(s->nic), frame, len);
+            qemu_send_packet(qemu_get_queue(s->nic), frame, frame_size);
+            mcf_fec_tx_stats(s, frame_size);
             ptr = frame;
             frame_size = 0;
             s->eir |= FEC_INT_TXF;
@@ -207,8 +298,10 @@ static void mcf_fec_enable_rx(mcf_fec_state *s)
     }
 }
 
-static void mcf_fec_reset(mcf_fec_state *s)
+static void mcf_fec_reset(DeviceState *dev)
 {
+    mcf_fec_state *s = MCF_FEC_NET(dev);
+
     s->eir = 0;
     s->eimr = 0;
     s->rx_enabled = 0;
@@ -297,8 +390,10 @@ static uint64_t mcf_fec_read(void *opaque, hwaddr addr,
     case 0x180: return s->erdsr;
     case 0x184: return s->etdsr;
     case 0x188: return s->emrbr;
+    case 0x200 ... 0x2e0: return s->mib[(addr & 0x1ff) / 4];
     default:
-        hw_error("mcf_fec_read: Bad address 0x%x\n", (int)addr);
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address 0x%" HWADDR_PRIX "\n",
+                      __func__, addr);
         return 0;
     }
 }
@@ -329,7 +424,7 @@ static void mcf_fec_write(void *opaque, hwaddr addr,
         s->ecr = value;
         if (value & FEC_RESET) {
             DPRINTF("Reset\n");
-            mcf_fec_reset(s);
+            mcf_fec_reset(opaque);
         }
         if ((s->ecr & FEC_EN) == 0) {
             s->rx_enabled = 0;
@@ -392,14 +487,44 @@ static void mcf_fec_write(void *opaque, hwaddr addr,
         s->tx_descriptor = s->etdsr;
         break;
     case 0x188:
-        s->emrbr = value & 0x7f0;
+        s->emrbr = value > 0 ? value & 0x7F0 : 0x7F0;
+        break;
+    case 0x200 ... 0x2e0:
+        s->mib[(addr & 0x1ff) / 4] = value;
         break;
     default:
-        hw_error("mcf_fec_write Bad address 0x%x\n", (int)addr);
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address 0x%" HWADDR_PRIX "\n",
+                      __func__, addr);
+        return;
     }
     mcf_fec_update(s);
 }
 
+static void mcf_fec_rx_stats(mcf_fec_state *s, int size)
+{
+    s->mib[MIB_RMON_R_PACKETS]++;
+    s->mib[MIB_RMON_R_OCTETS] += size;
+    if (size < 64) {
+        s->mib[MIB_RMON_R_FRAG]++;
+    } else if (size == 64) {
+        s->mib[MIB_RMON_R_P64]++;
+    } else if (size < 128) {
+        s->mib[MIB_RMON_R_P65TO127]++;
+    } else if (size < 256) {
+        s->mib[MIB_RMON_R_P128TO255]++;
+    } else if (size < 512) {
+        s->mib[MIB_RMON_R_P256TO511]++;
+    } else if (size < 1024) {
+        s->mib[MIB_RMON_R_P512TO1023]++;
+    } else if (size < 2048) {
+        s->mib[MIB_RMON_R_P1024TO2047]++;
+    } else {
+        s->mib[MIB_RMON_R_P_GTE2048]++;
+    }
+    s->mib[MIB_IEEE_R_FRAME_OK]++;
+    s->mib[MIB_IEEE_R_OCTETS_OK] += size;
+}
+
 static int mcf_fec_have_receive_space(mcf_fec_state *s, size_t want)
 {
     mcf_fec_bd bd;
@@ -495,6 +620,7 @@ static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t si
         }
     }
     s->rx_descriptor = addr;
+    mcf_fec_rx_stats(s, retsize);
     mcf_fec_enable_rx(s);
     mcf_fec_update(s);
     return retsize;
@@ -512,24 +638,55 @@ static NetClientInfo net_mcf_fec_info = {
     .receive = mcf_fec_receive,
 };
 
-void mcf_fec_init(MemoryRegion *sysmem, NICInfo *nd,
-                  hwaddr base, qemu_irq *irq)
+static void mcf_fec_realize(DeviceState *dev, Error **errp)
 {
-    mcf_fec_state *s;
+    mcf_fec_state *s = MCF_FEC_NET(dev);
 
-    qemu_check_nic_model(nd, "mcf_fec");
+    s->nic = qemu_new_nic(&net_mcf_fec_info, &s->conf,
+                          object_get_typename(OBJECT(dev)), dev->id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+}
 
-    s = (mcf_fec_state *)g_malloc0(sizeof(mcf_fec_state));
-    s->sysmem = sysmem;
-    s->irq = irq;
+static void mcf_fec_instance_init(Object *obj)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    mcf_fec_state *s = MCF_FEC_NET(obj);
+    int i;
+
+    memory_region_init_io(&s->iomem, obj, &mcf_fec_ops, s, "fec", 0x400);
+    sysbus_init_mmio(sbd, &s->iomem);
+    for (i = 0; i < FEC_NUM_IRQ; i++) {
+        sysbus_init_irq(sbd, &s->irq[i]);
+    }
+}
+
+static Property mcf_fec_properties[] = {
+    DEFINE_NIC_PROPERTIES(mcf_fec_state, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
 
-    memory_region_init_io(&s->iomem, NULL, &mcf_fec_ops, s, "fec", 0x400);
-    memory_region_add_subregion(sysmem, base, &s->iomem);
+static void mcf_fec_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
 
-    s->conf.macaddr = nd->macaddr;
-    s->conf.peers.ncs[0] = nd->netdev;
+    set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
+    dc->realize = mcf_fec_realize;
+    dc->desc = "MCF Fast Ethernet Controller network device";
+    dc->reset = mcf_fec_reset;
+    device_class_set_props(dc, mcf_fec_properties);
+}
 
-    s->nic = qemu_new_nic(&net_mcf_fec_info, &s->conf, nd->model, nd->name, s);
+static const TypeInfo mcf_fec_info = {
+    .name          = TYPE_MCF_FEC_NET,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(mcf_fec_state),
+    .instance_init = mcf_fec_instance_init,
+    .class_init    = mcf_fec_class_init,
+};
 
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+static void mcf_fec_register_types(void)
+{
+    type_register_static(&mcf_fec_info);
 }
+
+type_init(mcf_fec_register_types)