aboutsummaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/qemu/qemu/smc91c111_fix.patch
blob: e37e7773475ca72305a21c705cbc67aafaf192cb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
The smc91c111.c driver appears to have several issues. The can_receive()
function can return that the driver is ready when rx_fifo has not been 
freed yet. There is also no sanity check of rx_fifo() in _receive() which
can lead to corruption of the rx_fifo array.

release_packet() can also call qemu_flush_queued_packets() before rx_fifo 
has been cleaned up, resulting in cases where packets are submitted
for which there is not yet any space.

This patch therefore:

* fixes the logic in can_receive()
* adds logic to receive() as a sanity check
* moves the flush() calls to the correct places where data is ready
  to be received

Upstream-Status: Pending [discussion in progress on mailing list]
RP 2015/9/7

Index: qemu-2.4.0/hw/net/smc91c111.c
===================================================================
--- qemu-2.4.0.orig/hw/net/smc91c111.c
+++ qemu-2.4.0/hw/net/smc91c111.c
@@ -185,7 +185,6 @@ static void smc91c111_release_packet(smc
     s->allocated &= ~(1 << packet);
     if (s->tx_alloc == 0x80)
         smc91c111_tx_alloc(s);
-    qemu_flush_queued_packets(qemu_get_queue(s->nic));
 }
 
 /* Flush the TX FIFO.  */
@@ -237,9 +236,11 @@ static void smc91c111_do_tx(smc91c111_st
             }
         }
 #endif
-        if (s->ctr & CTR_AUTO_RELEASE)
+        if (s->ctr & CTR_AUTO_RELEASE) {
             /* Race?  */
             smc91c111_release_packet(s, packetnum);
+            qemu_flush_queued_packets(qemu_get_queue(s->nic));
+        }
         else if (s->tx_fifo_done_len < NUM_PACKETS)
             s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
         qemu_send_packet(qemu_get_queue(s->nic), p, len);
@@ -379,9 +380,11 @@ static void smc91c111_writeb(void *opaqu
                     smc91c111_release_packet(s, s->rx_fifo[0]);
                 }
                 smc91c111_pop_rx_fifo(s);
+                qemu_flush_queued_packets(qemu_get_queue(s->nic));
                 break;
             case 5: /* Release.  */
                 smc91c111_release_packet(s, s->packet_num);
+                qemu_flush_queued_packets(qemu_get_queue(s->nic));
                 break;
             case 6: /* Add to TX FIFO.  */
                 smc91c111_queue_tx(s, s->packet_num);
@@ -642,7 +642,7 @@ static int smc91c111_can_receive(NetClie
 
     if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
         return 1;
-    if (s->allocated == (1 << NUM_PACKETS) - 1)
+    if ((s->allocated == (1 << NUM_PACKETS) - 1) || (s->rx_fifo_len == NUM_PACKETS))
         return 0;
     return 1;
 }
@@ -671,6 +671,8 @@ static ssize_t smc91c111_receive(NetClie
     /* TODO: Flag overrun and receive errors.  */
     if (packetsize > 2048)
         return -1;
+    if  (s->rx_fifo_len == NUM_PACKETS)
+        return -1;    
     packetnum = smc91c111_allocate_packet(s);
     if (packetnum == 0x80)
         return -1;