]> Git Repo - qemu.git/blobdiff - hw/net/opencores_eth.c
Merge remote-tracking branch 'remotes/kraxel/tags/audio-20170717-pull-request' into...
[qemu.git] / hw / net / opencores_eth.c
index 4118d54ac81ef4347b234fc09d8207fe6fcb1cb9..268d6a7892cd233ef01c02a172f1806cf21992ac 100644 (file)
@@ -31,7 +31,9 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "qemu/osdep.h"
 #include "hw/hw.h"
+#include "hw/net/mii.h"
 #include "hw/sysbus.h"
 #include "net/net.h"
 #include "sysemu/sysemu.h"
 
 /* PHY MII registers */
 enum {
-    MII_BMCR,
-    MII_BMSR,
-    MII_PHYIDR1,
-    MII_PHYIDR2,
-    MII_ANAR,
-    MII_ANLPAR,
     MII_REG_MAX = 16,
 };
 
@@ -71,10 +67,11 @@ typedef struct Mii {
 static void mii_set_link(Mii *s, bool link_ok)
 {
     if (link_ok) {
-        s->regs[MII_BMSR] |= 0x4;
-        s->regs[MII_ANLPAR] |= 0x01e1;
+        s->regs[MII_BMSR] |= MII_BMSR_LINK_ST;
+        s->regs[MII_ANLPAR] |= MII_ANLPAR_TXFD | MII_ANLPAR_TX |
+            MII_ANLPAR_10FD | MII_ANLPAR_10 | MII_ANLPAR_CSMACD;
     } else {
-        s->regs[MII_BMSR] &= ~0x4;
+        s->regs[MII_BMSR] &= ~MII_BMSR_LINK_ST;
         s->regs[MII_ANLPAR] &= 0x01ff;
     }
     s->link_ok = link_ok;
@@ -83,11 +80,14 @@ static void mii_set_link(Mii *s, bool link_ok)
 static void mii_reset(Mii *s)
 {
     memset(s->regs, 0, sizeof(s->regs));
-    s->regs[MII_BMCR] = 0x1000;
-    s->regs[MII_BMSR] = 0x7848; /* no ext regs */
-    s->regs[MII_PHYIDR1] = 0x2000;
-    s->regs[MII_PHYIDR2] = 0x5c90;
-    s->regs[MII_ANAR] = 0x01e1;
+    s->regs[MII_BMCR] = MII_BMCR_AUTOEN;
+    s->regs[MII_BMSR] = MII_BMSR_100TX_FD | MII_BMSR_100TX_HD |
+        MII_BMSR_10T_FD | MII_BMSR_10T_HD | MII_BMSR_MFPS |
+        MII_BMSR_AN_COMP | MII_BMSR_AUTONEG;
+    s->regs[MII_PHYID1] = 0x2000;
+    s->regs[MII_PHYID2] = 0x5c90;
+    s->regs[MII_ANAR] = MII_ANAR_TXFD | MII_ANAR_TX |
+        MII_ANAR_10FD | MII_ANAR_10 | MII_ANAR_CSMACD;
     mii_set_link(s, s->link_ok);
 }
 
@@ -97,7 +97,7 @@ static void mii_ro(Mii *s, uint16_t v)
 
 static void mii_write_bmcr(Mii *s, uint16_t v)
 {
-    if (v & 0x8000) {
+    if (v & MII_BMCR_RESET) {
         mii_reset(s);
     } else {
         s->regs[MII_BMCR] = v;
@@ -109,8 +109,8 @@ static void mii_write_host(Mii *s, unsigned idx, uint16_t v)
     static void (*reg_write[MII_REG_MAX])(Mii *s, uint16_t v) = {
         [MII_BMCR] = mii_write_bmcr,
         [MII_BMSR] = mii_ro,
-        [MII_PHYIDR1] = mii_ro,
-        [MII_PHYIDR2] = mii_ro,
+        [MII_PHYID1] = mii_ro,
+        [MII_PHYID2] = mii_ro,
     };
 
     if (idx < MII_REG_MAX) {
@@ -169,6 +169,7 @@ enum {
 };
 
 enum {
+    INT_SOURCE_BUSY = 0x10,
     INT_SOURCE_RXB = 0x4,
     INT_SOURCE_TXB = 0x1,
 };
@@ -351,8 +352,7 @@ static int open_eth_can_receive(NetClientState *nc)
     OpenEthState *s = qemu_get_nic_opaque(nc);
 
     return GET_REGBIT(s, MODER, RXEN) &&
-        (s->regs[TX_BD_NUM] < 0x80) &&
-        (rx_desc(s)->len_flags & RXD_E);
+        (s->regs[TX_BD_NUM] < 0x80);
 }
 
 static ssize_t open_eth_receive(NetClientState *nc,
@@ -402,6 +402,12 @@ static ssize_t open_eth_receive(NetClientState *nc,
         desc *desc = rx_desc(s);
         size_t copy_size = GET_REGBIT(s, MODER, HUGEN) ? 65536 : maxfl;
 
+        if (!(desc->len_flags & RXD_E)) {
+            open_eth_int_source_write(s,
+                    s->regs[INT_SOURCE] | INT_SOURCE_BUSY);
+            return size;
+        }
+
         desc->len_flags &= ~(RXD_CF | RXD_M | RXD_OR |
                 RXD_IS | RXD_DN | RXD_TL | RXD_SF | RXD_CRC | RXD_LC);
 
@@ -466,22 +472,18 @@ static ssize_t open_eth_receive(NetClientState *nc,
     return size;
 }
 
-static void open_eth_cleanup(NetClientState *nc)
-{
-}
-
 static NetClientInfo net_open_eth_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .can_receive = open_eth_can_receive,
     .receive = open_eth_receive,
-    .cleanup = open_eth_cleanup,
     .link_status_changed = open_eth_set_link_status,
 };
 
 static void open_eth_start_xmit(OpenEthState *s, desc *tx)
 {
-    uint8_t buf[65536];
+    uint8_t *buf = NULL;
+    uint8_t buffer[0x600];
     unsigned len = GET_FIELD(tx->len_flags, TXD_LEN);
     unsigned tx_len = len;
 
@@ -496,6 +498,11 @@ static void open_eth_start_xmit(OpenEthState *s, desc *tx)
 
     trace_open_eth_start_xmit(tx->buf_ptr, len, tx_len);
 
+    if (tx_len > sizeof(buffer)) {
+        buf = g_new(uint8_t, tx_len);
+    } else {
+        buf = buffer;
+    }
     if (len > tx_len) {
         len = tx_len;
     }
@@ -504,6 +511,9 @@ static void open_eth_start_xmit(OpenEthState *s, desc *tx)
         memset(buf + len, 0, tx_len - len);
     }
     qemu_send_packet(qemu_get_queue(s->nic), buf, tx_len);
+    if (tx_len > sizeof(buffer)) {
+        g_free(buf);
+    }
 
     if (tx->len_flags & TXD_WR) {
         s->tx_desc = 0;
@@ -551,6 +561,15 @@ static uint64_t open_eth_reg_read(void *opaque,
     return v;
 }
 
+static void open_eth_notify_can_receive(OpenEthState *s)
+{
+    NetClientState *nc = qemu_get_queue(s->nic);
+
+    if (open_eth_can_receive(nc)) {
+        qemu_flush_queued_packets(nc);
+    }
+}
+
 static void open_eth_ro(OpenEthState *s, uint32_t val)
 {
 }
@@ -567,6 +586,7 @@ static void open_eth_moder_host_write(OpenEthState *s, uint32_t val)
 
     if (set & MODER_RXEN) {
         s->rx_desc = s->regs[TX_BD_NUM];
+        open_eth_notify_can_receive(s);
     }
     if (set & MODER_TXEN) {
         s->tx_desc = 0;
@@ -592,6 +612,18 @@ static void open_eth_int_mask_host_write(OpenEthState *s, uint32_t val)
             s->regs[INT_SOURCE] & s->regs[INT_MASK]);
 }
 
+static void open_eth_tx_bd_num_host_write(OpenEthState *s, uint32_t val)
+{
+    if (val < 0x80) {
+        bool enable = s->regs[TX_BD_NUM] == 0x80;
+
+        s->regs[TX_BD_NUM] = val;
+        if (enable) {
+            open_eth_notify_can_receive(s);
+        }
+    }
+}
+
 static void open_eth_mii_command_host_write(OpenEthState *s, uint32_t val)
 {
     unsigned fiad = GET_REGFIELD(s, MIIADDRESS, FIAD);
@@ -630,6 +662,7 @@ static void open_eth_reg_write(void *opaque,
         [MODER] = open_eth_moder_host_write,
         [INT_SOURCE] = open_eth_int_source_host_write,
         [INT_MASK] = open_eth_int_mask_host_write,
+        [TX_BD_NUM] = open_eth_tx_bd_num_host_write,
         [MIICOMMAND] = open_eth_mii_command_host_write,
         [MIITX_DATA] = open_eth_mii_tx_host_write,
         [MIISTATUS] = open_eth_ro,
This page took 0.030333 seconds and 4 git commands to generate.