Statistics
| Branch: | Revision:

root / hw / dp8393x.c @ bb6e6364

History | View | Annotate | Download (26.1 kB)

1 a65f56ee aurel32
/*
2 a65f56ee aurel32
 * QEMU NS SONIC DP8393x netcard
3 a65f56ee aurel32
 *
4 a65f56ee aurel32
 * Copyright (c) 2008-2009 Herve Poussineau
5 a65f56ee aurel32
 *
6 a65f56ee aurel32
 * This program is free software; you can redistribute it and/or
7 a65f56ee aurel32
 * modify it under the terms of the GNU General Public License as
8 a65f56ee aurel32
 * published by the Free Software Foundation; either version 2 of
9 a65f56ee aurel32
 * the License, or (at your option) any later version.
10 a65f56ee aurel32
 *
11 a65f56ee aurel32
 * This program is distributed in the hope that it will be useful,
12 a65f56ee aurel32
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 a65f56ee aurel32
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 a65f56ee aurel32
 * GNU General Public License for more details.
15 a65f56ee aurel32
 *
16 a65f56ee aurel32
 * You should have received a copy of the GNU General Public License along
17 8167ee88 Blue Swirl
 * with this program; if not, see <http://www.gnu.org/licenses/>.
18 a65f56ee aurel32
 */
19 a65f56ee aurel32
20 a65f56ee aurel32
#include "hw.h"
21 a65f56ee aurel32
#include "qemu-timer.h"
22 a65f56ee aurel32
#include "net.h"
23 a65f56ee aurel32
#include "mips.h"
24 a65f56ee aurel32
25 a65f56ee aurel32
//#define DEBUG_SONIC
26 a65f56ee aurel32
27 a65f56ee aurel32
/* Calculate CRCs properly on Rx packets */
28 a65f56ee aurel32
#define SONIC_CALCULATE_RXCRC
29 a65f56ee aurel32
30 a65f56ee aurel32
#if defined(SONIC_CALCULATE_RXCRC)
31 a65f56ee aurel32
/* For crc32 */
32 a65f56ee aurel32
#include <zlib.h>
33 a65f56ee aurel32
#endif
34 a65f56ee aurel32
35 a65f56ee aurel32
#ifdef DEBUG_SONIC
36 001faf32 Blue Swirl
#define DPRINTF(fmt, ...) \
37 001faf32 Blue Swirl
do { printf("sonic: " fmt , ##  __VA_ARGS__); } while (0)
38 a65f56ee aurel32
static const char* reg_names[] = {
39 a65f56ee aurel32
    "CR", "DCR", "RCR", "TCR", "IMR", "ISR", "UTDA", "CTDA",
40 a65f56ee aurel32
    "TPS", "TFC", "TSA0", "TSA1", "TFS", "URDA", "CRDA", "CRBA0",
41 a65f56ee aurel32
    "CRBA1", "RBWC0", "RBWC1", "EOBC", "URRA", "RSA", "REA", "RRP",
42 a65f56ee aurel32
    "RWP", "TRBA0", "TRBA1", "0x1b", "0x1c", "0x1d", "0x1e", "LLFA",
43 a65f56ee aurel32
    "TTDA", "CEP", "CAP2", "CAP1", "CAP0", "CE", "CDP", "CDC",
44 a65f56ee aurel32
    "SR", "WT0", "WT1", "RSC", "CRCT", "FAET", "MPT", "MDT",
45 a65f56ee aurel32
    "0x30", "0x31", "0x32", "0x33", "0x34", "0x35", "0x36", "0x37",
46 a65f56ee aurel32
    "0x38", "0x39", "0x3a", "0x3b", "0x3c", "0x3d", "0x3e", "DCR2" };
47 a65f56ee aurel32
#else
48 001faf32 Blue Swirl
#define DPRINTF(fmt, ...) do {} while (0)
49 a65f56ee aurel32
#endif
50 a65f56ee aurel32
51 001faf32 Blue Swirl
#define SONIC_ERROR(fmt, ...) \
52 001faf32 Blue Swirl
do { printf("sonic ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
53 a65f56ee aurel32
54 a65f56ee aurel32
#define SONIC_CR     0x00
55 a65f56ee aurel32
#define SONIC_DCR    0x01
56 a65f56ee aurel32
#define SONIC_RCR    0x02
57 a65f56ee aurel32
#define SONIC_TCR    0x03
58 a65f56ee aurel32
#define SONIC_IMR    0x04
59 a65f56ee aurel32
#define SONIC_ISR    0x05
60 a65f56ee aurel32
#define SONIC_UTDA   0x06
61 a65f56ee aurel32
#define SONIC_CTDA   0x07
62 a65f56ee aurel32
#define SONIC_TPS    0x08
63 a65f56ee aurel32
#define SONIC_TFC    0x09
64 a65f56ee aurel32
#define SONIC_TSA0   0x0a
65 a65f56ee aurel32
#define SONIC_TSA1   0x0b
66 a65f56ee aurel32
#define SONIC_TFS    0x0c
67 a65f56ee aurel32
#define SONIC_URDA   0x0d
68 a65f56ee aurel32
#define SONIC_CRDA   0x0e
69 a65f56ee aurel32
#define SONIC_CRBA0  0x0f
70 a65f56ee aurel32
#define SONIC_CRBA1  0x10
71 a65f56ee aurel32
#define SONIC_RBWC0  0x11
72 a65f56ee aurel32
#define SONIC_RBWC1  0x12
73 a65f56ee aurel32
#define SONIC_EOBC   0x13
74 a65f56ee aurel32
#define SONIC_URRA   0x14
75 a65f56ee aurel32
#define SONIC_RSA    0x15
76 a65f56ee aurel32
#define SONIC_REA    0x16
77 a65f56ee aurel32
#define SONIC_RRP    0x17
78 a65f56ee aurel32
#define SONIC_RWP    0x18
79 a65f56ee aurel32
#define SONIC_TRBA0  0x19
80 a65f56ee aurel32
#define SONIC_TRBA1  0x1a
81 a65f56ee aurel32
#define SONIC_LLFA   0x1f
82 a65f56ee aurel32
#define SONIC_TTDA   0x20
83 a65f56ee aurel32
#define SONIC_CEP    0x21
84 a65f56ee aurel32
#define SONIC_CAP2   0x22
85 a65f56ee aurel32
#define SONIC_CAP1   0x23
86 a65f56ee aurel32
#define SONIC_CAP0   0x24
87 a65f56ee aurel32
#define SONIC_CE     0x25
88 a65f56ee aurel32
#define SONIC_CDP    0x26
89 a65f56ee aurel32
#define SONIC_CDC    0x27
90 a65f56ee aurel32
#define SONIC_SR     0x28
91 a65f56ee aurel32
#define SONIC_WT0    0x29
92 a65f56ee aurel32
#define SONIC_WT1    0x2a
93 a65f56ee aurel32
#define SONIC_RSC    0x2b
94 a65f56ee aurel32
#define SONIC_CRCT   0x2c
95 a65f56ee aurel32
#define SONIC_FAET   0x2d
96 a65f56ee aurel32
#define SONIC_MPT    0x2e
97 a65f56ee aurel32
#define SONIC_MDT    0x2f
98 a65f56ee aurel32
#define SONIC_DCR2   0x3f
99 a65f56ee aurel32
100 a65f56ee aurel32
#define SONIC_CR_HTX     0x0001
101 a65f56ee aurel32
#define SONIC_CR_TXP     0x0002
102 a65f56ee aurel32
#define SONIC_CR_RXDIS   0x0004
103 a65f56ee aurel32
#define SONIC_CR_RXEN    0x0008
104 a65f56ee aurel32
#define SONIC_CR_STP     0x0010
105 a65f56ee aurel32
#define SONIC_CR_ST      0x0020
106 a65f56ee aurel32
#define SONIC_CR_RST     0x0080
107 a65f56ee aurel32
#define SONIC_CR_RRRA    0x0100
108 a65f56ee aurel32
#define SONIC_CR_LCAM    0x0200
109 a65f56ee aurel32
#define SONIC_CR_MASK    0x03bf
110 a65f56ee aurel32
111 a65f56ee aurel32
#define SONIC_DCR_DW     0x0020
112 a65f56ee aurel32
#define SONIC_DCR_LBR    0x2000
113 a65f56ee aurel32
#define SONIC_DCR_EXBUS  0x8000
114 a65f56ee aurel32
115 a65f56ee aurel32
#define SONIC_RCR_PRX    0x0001
116 a65f56ee aurel32
#define SONIC_RCR_LBK    0x0002
117 a65f56ee aurel32
#define SONIC_RCR_FAER   0x0004
118 a65f56ee aurel32
#define SONIC_RCR_CRCR   0x0008
119 a65f56ee aurel32
#define SONIC_RCR_CRS    0x0020
120 a65f56ee aurel32
#define SONIC_RCR_LPKT   0x0040
121 a65f56ee aurel32
#define SONIC_RCR_BC     0x0080
122 a65f56ee aurel32
#define SONIC_RCR_MC     0x0100
123 a65f56ee aurel32
#define SONIC_RCR_LB0    0x0200
124 a65f56ee aurel32
#define SONIC_RCR_LB1    0x0400
125 a65f56ee aurel32
#define SONIC_RCR_AMC    0x0800
126 a65f56ee aurel32
#define SONIC_RCR_PRO    0x1000
127 a65f56ee aurel32
#define SONIC_RCR_BRD    0x2000
128 a65f56ee aurel32
#define SONIC_RCR_RNT    0x4000
129 a65f56ee aurel32
130 a65f56ee aurel32
#define SONIC_TCR_PTX    0x0001
131 a65f56ee aurel32
#define SONIC_TCR_BCM    0x0002
132 a65f56ee aurel32
#define SONIC_TCR_FU     0x0004
133 a65f56ee aurel32
#define SONIC_TCR_EXC    0x0040
134 a65f56ee aurel32
#define SONIC_TCR_CRSL   0x0080
135 a65f56ee aurel32
#define SONIC_TCR_NCRS   0x0100
136 a65f56ee aurel32
#define SONIC_TCR_EXD    0x0400
137 a65f56ee aurel32
#define SONIC_TCR_CRCI   0x2000
138 a65f56ee aurel32
#define SONIC_TCR_PINT   0x8000
139 a65f56ee aurel32
140 a65f56ee aurel32
#define SONIC_ISR_RBE    0x0020
141 a65f56ee aurel32
#define SONIC_ISR_RDE    0x0040
142 a65f56ee aurel32
#define SONIC_ISR_TC     0x0080
143 a65f56ee aurel32
#define SONIC_ISR_TXDN   0x0200
144 a65f56ee aurel32
#define SONIC_ISR_PKTRX  0x0400
145 a65f56ee aurel32
#define SONIC_ISR_PINT   0x0800
146 a65f56ee aurel32
#define SONIC_ISR_LCD    0x1000
147 a65f56ee aurel32
148 a65f56ee aurel32
typedef struct dp8393xState {
149 a65f56ee aurel32
    /* Hardware */
150 a65f56ee aurel32
    int it_shift;
151 a65f56ee aurel32
    qemu_irq irq;
152 a65f56ee aurel32
#ifdef DEBUG_SONIC
153 a65f56ee aurel32
    int irq_level;
154 a65f56ee aurel32
#endif
155 a65f56ee aurel32
    QEMUTimer *watchdog;
156 a65f56ee aurel32
    int64_t wt_last_update;
157 a65f56ee aurel32
    VLANClientState *vc;
158 b946a153 aliguori
    int mmio_index;
159 a65f56ee aurel32
160 a65f56ee aurel32
    /* Registers */
161 a65f56ee aurel32
    uint8_t cam[16][6];
162 a65f56ee aurel32
    uint16_t regs[0x40];
163 a65f56ee aurel32
164 a65f56ee aurel32
    /* Temporaries */
165 a65f56ee aurel32
    uint8_t tx_buffer[0x10000];
166 a65f56ee aurel32
    int loopback_packet;
167 a65f56ee aurel32
168 a65f56ee aurel32
    /* Memory access */
169 c227f099 Anthony Liguori
    void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write);
170 a65f56ee aurel32
    void* mem_opaque;
171 a65f56ee aurel32
} dp8393xState;
172 a65f56ee aurel32
173 a65f56ee aurel32
static void dp8393x_update_irq(dp8393xState *s)
174 a65f56ee aurel32
{
175 a65f56ee aurel32
    int level = (s->regs[SONIC_IMR] & s->regs[SONIC_ISR]) ? 1 : 0;
176 a65f56ee aurel32
177 a65f56ee aurel32
#ifdef DEBUG_SONIC
178 a65f56ee aurel32
    if (level != s->irq_level) {
179 a65f56ee aurel32
        s->irq_level = level;
180 a65f56ee aurel32
        if (level) {
181 a65f56ee aurel32
            DPRINTF("raise irq, isr is 0x%04x\n", s->regs[SONIC_ISR]);
182 a65f56ee aurel32
        } else {
183 a65f56ee aurel32
            DPRINTF("lower irq\n");
184 a65f56ee aurel32
        }
185 a65f56ee aurel32
    }
186 a65f56ee aurel32
#endif
187 a65f56ee aurel32
188 a65f56ee aurel32
    qemu_set_irq(s->irq, level);
189 a65f56ee aurel32
}
190 a65f56ee aurel32
191 a65f56ee aurel32
static void do_load_cam(dp8393xState *s)
192 a65f56ee aurel32
{
193 a65f56ee aurel32
    uint16_t data[8];
194 a65f56ee aurel32
    int width, size;
195 a65f56ee aurel32
    uint16_t index = 0;
196 a65f56ee aurel32
197 a65f56ee aurel32
    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
198 a65f56ee aurel32
    size = sizeof(uint16_t) * 4 * width;
199 a65f56ee aurel32
200 a65f56ee aurel32
    while (s->regs[SONIC_CDC] & 0x1f) {
201 a65f56ee aurel32
        /* Fill current entry */
202 a65f56ee aurel32
        s->memory_rw(s->mem_opaque,
203 a65f56ee aurel32
            (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
204 a65f56ee aurel32
            (uint8_t *)data, size, 0);
205 a65f56ee aurel32
        s->cam[index][0] = data[1 * width] & 0xff;
206 a65f56ee aurel32
        s->cam[index][1] = data[1 * width] >> 8;
207 a65f56ee aurel32
        s->cam[index][2] = data[2 * width] & 0xff;
208 a65f56ee aurel32
        s->cam[index][3] = data[2 * width] >> 8;
209 a65f56ee aurel32
        s->cam[index][4] = data[3 * width] & 0xff;
210 a65f56ee aurel32
        s->cam[index][5] = data[3 * width] >> 8;
211 a65f56ee aurel32
        DPRINTF("load cam[%d] with %02x%02x%02x%02x%02x%02x\n", index,
212 a65f56ee aurel32
            s->cam[index][0], s->cam[index][1], s->cam[index][2],
213 a65f56ee aurel32
            s->cam[index][3], s->cam[index][4], s->cam[index][5]);
214 a65f56ee aurel32
        /* Move to next entry */
215 a65f56ee aurel32
        s->regs[SONIC_CDC]--;
216 a65f56ee aurel32
        s->regs[SONIC_CDP] += size;
217 a65f56ee aurel32
        index++;
218 a65f56ee aurel32
    }
219 a65f56ee aurel32
220 a65f56ee aurel32
    /* Read CAM enable */
221 a65f56ee aurel32
    s->memory_rw(s->mem_opaque,
222 a65f56ee aurel32
        (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
223 a65f56ee aurel32
        (uint8_t *)data, size, 0);
224 a65f56ee aurel32
    s->regs[SONIC_CE] = data[0 * width];
225 a65f56ee aurel32
    DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]);
226 a65f56ee aurel32
227 a65f56ee aurel32
    /* Done */
228 a65f56ee aurel32
    s->regs[SONIC_CR] &= ~SONIC_CR_LCAM;
229 a65f56ee aurel32
    s->regs[SONIC_ISR] |= SONIC_ISR_LCD;
230 a65f56ee aurel32
    dp8393x_update_irq(s);
231 a65f56ee aurel32
}
232 a65f56ee aurel32
233 a65f56ee aurel32
static void do_read_rra(dp8393xState *s)
234 a65f56ee aurel32
{
235 a65f56ee aurel32
    uint16_t data[8];
236 a65f56ee aurel32
    int width, size;
237 a65f56ee aurel32
238 a65f56ee aurel32
    /* Read memory */
239 a65f56ee aurel32
    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
240 a65f56ee aurel32
    size = sizeof(uint16_t) * 4 * width;
241 a65f56ee aurel32
    s->memory_rw(s->mem_opaque,
242 a65f56ee aurel32
        (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP],
243 a65f56ee aurel32
        (uint8_t *)data, size, 0);
244 a65f56ee aurel32
245 a65f56ee aurel32
    /* Update SONIC registers */
246 a65f56ee aurel32
    s->regs[SONIC_CRBA0] = data[0 * width];
247 a65f56ee aurel32
    s->regs[SONIC_CRBA1] = data[1 * width];
248 a65f56ee aurel32
    s->regs[SONIC_RBWC0] = data[2 * width];
249 a65f56ee aurel32
    s->regs[SONIC_RBWC1] = data[3 * width];
250 a65f56ee aurel32
    DPRINTF("CRBA0/1: 0x%04x/0x%04x, RBWC0/1: 0x%04x/0x%04x\n",
251 a65f56ee aurel32
        s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1],
252 a65f56ee aurel32
        s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]);
253 a65f56ee aurel32
254 a65f56ee aurel32
    /* Go to next entry */
255 a65f56ee aurel32
    s->regs[SONIC_RRP] += size;
256 a65f56ee aurel32
257 a65f56ee aurel32
    /* Handle wrap */
258 a65f56ee aurel32
    if (s->regs[SONIC_RRP] == s->regs[SONIC_REA]) {
259 a65f56ee aurel32
        s->regs[SONIC_RRP] = s->regs[SONIC_RSA];
260 a65f56ee aurel32
    }
261 a65f56ee aurel32
262 a65f56ee aurel32
    /* Check resource exhaustion */
263 a65f56ee aurel32
    if (s->regs[SONIC_RRP] == s->regs[SONIC_RWP])
264 a65f56ee aurel32
    {
265 a65f56ee aurel32
        s->regs[SONIC_ISR] |= SONIC_ISR_RBE;
266 a65f56ee aurel32
        dp8393x_update_irq(s);
267 a65f56ee aurel32
    }
268 a65f56ee aurel32
269 a65f56ee aurel32
    /* Done */
270 a65f56ee aurel32
    s->regs[SONIC_CR] &= ~SONIC_CR_RRRA;
271 a65f56ee aurel32
}
272 a65f56ee aurel32
273 a65f56ee aurel32
static void do_software_reset(dp8393xState *s)
274 a65f56ee aurel32
{
275 a65f56ee aurel32
    qemu_del_timer(s->watchdog);
276 a65f56ee aurel32
277 a65f56ee aurel32
    s->regs[SONIC_CR] &= ~(SONIC_CR_LCAM | SONIC_CR_RRRA | SONIC_CR_TXP | SONIC_CR_HTX);
278 a65f56ee aurel32
    s->regs[SONIC_CR] |= SONIC_CR_RST | SONIC_CR_RXDIS;
279 a65f56ee aurel32
}
280 a65f56ee aurel32
281 a65f56ee aurel32
static void set_next_tick(dp8393xState *s)
282 a65f56ee aurel32
{
283 a65f56ee aurel32
    uint32_t ticks;
284 a65f56ee aurel32
    int64_t delay;
285 a65f56ee aurel32
286 a65f56ee aurel32
    if (s->regs[SONIC_CR] & SONIC_CR_STP) {
287 a65f56ee aurel32
        qemu_del_timer(s->watchdog);
288 a65f56ee aurel32
        return;
289 a65f56ee aurel32
    }
290 a65f56ee aurel32
291 a65f56ee aurel32
    ticks = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
292 a65f56ee aurel32
    s->wt_last_update = qemu_get_clock(vm_clock);
293 6ee093c9 Juan Quintela
    delay = get_ticks_per_sec() * ticks / 5000000;
294 a65f56ee aurel32
    qemu_mod_timer(s->watchdog, s->wt_last_update + delay);
295 a65f56ee aurel32
}
296 a65f56ee aurel32
297 a65f56ee aurel32
static void update_wt_regs(dp8393xState *s)
298 a65f56ee aurel32
{
299 a65f56ee aurel32
    int64_t elapsed;
300 a65f56ee aurel32
    uint32_t val;
301 a65f56ee aurel32
302 a65f56ee aurel32
    if (s->regs[SONIC_CR] & SONIC_CR_STP) {
303 a65f56ee aurel32
        qemu_del_timer(s->watchdog);
304 a65f56ee aurel32
        return;
305 a65f56ee aurel32
    }
306 a65f56ee aurel32
307 a65f56ee aurel32
    elapsed = s->wt_last_update - qemu_get_clock(vm_clock);
308 a65f56ee aurel32
    val = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
309 a65f56ee aurel32
    val -= elapsed / 5000000;
310 a65f56ee aurel32
    s->regs[SONIC_WT1] = (val >> 16) & 0xffff;
311 a65f56ee aurel32
    s->regs[SONIC_WT0] = (val >> 0)  & 0xffff;
312 a65f56ee aurel32
    set_next_tick(s);
313 a65f56ee aurel32
314 a65f56ee aurel32
}
315 a65f56ee aurel32
316 a65f56ee aurel32
static void do_start_timer(dp8393xState *s)
317 a65f56ee aurel32
{
318 a65f56ee aurel32
    s->regs[SONIC_CR] &= ~SONIC_CR_STP;
319 a65f56ee aurel32
    set_next_tick(s);
320 a65f56ee aurel32
}
321 a65f56ee aurel32
322 a65f56ee aurel32
static void do_stop_timer(dp8393xState *s)
323 a65f56ee aurel32
{
324 a65f56ee aurel32
    s->regs[SONIC_CR] &= ~SONIC_CR_ST;
325 a65f56ee aurel32
    update_wt_regs(s);
326 a65f56ee aurel32
}
327 a65f56ee aurel32
328 a65f56ee aurel32
static void do_receiver_enable(dp8393xState *s)
329 a65f56ee aurel32
{
330 a65f56ee aurel32
    s->regs[SONIC_CR] &= ~SONIC_CR_RXDIS;
331 a65f56ee aurel32
}
332 a65f56ee aurel32
333 a65f56ee aurel32
static void do_receiver_disable(dp8393xState *s)
334 a65f56ee aurel32
{
335 a65f56ee aurel32
    s->regs[SONIC_CR] &= ~SONIC_CR_RXEN;
336 a65f56ee aurel32
}
337 a65f56ee aurel32
338 a65f56ee aurel32
static void do_transmit_packets(dp8393xState *s)
339 a65f56ee aurel32
{
340 a65f56ee aurel32
    uint16_t data[12];
341 a65f56ee aurel32
    int width, size;
342 a65f56ee aurel32
    int tx_len, len;
343 a65f56ee aurel32
    uint16_t i;
344 a65f56ee aurel32
345 a65f56ee aurel32
    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
346 a65f56ee aurel32
347 a65f56ee aurel32
    while (1) {
348 a65f56ee aurel32
        /* Read memory */
349 a65f56ee aurel32
        DPRINTF("Transmit packet at %08x\n",
350 a65f56ee aurel32
                (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_CTDA]);
351 a65f56ee aurel32
        size = sizeof(uint16_t) * 6 * width;
352 a65f56ee aurel32
        s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA];
353 a65f56ee aurel32
        s->memory_rw(s->mem_opaque,
354 a65f56ee aurel32
            ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * width,
355 a65f56ee aurel32
            (uint8_t *)data, size, 0);
356 a65f56ee aurel32
        tx_len = 0;
357 a65f56ee aurel32
358 a65f56ee aurel32
        /* Update registers */
359 a65f56ee aurel32
        s->regs[SONIC_TCR] = data[0 * width] & 0xf000;
360 a65f56ee aurel32
        s->regs[SONIC_TPS] = data[1 * width];
361 a65f56ee aurel32
        s->regs[SONIC_TFC] = data[2 * width];
362 a65f56ee aurel32
        s->regs[SONIC_TSA0] = data[3 * width];
363 a65f56ee aurel32
        s->regs[SONIC_TSA1] = data[4 * width];
364 a65f56ee aurel32
        s->regs[SONIC_TFS] = data[5 * width];
365 a65f56ee aurel32
366 a65f56ee aurel32
        /* Handle programmable interrupt */
367 a65f56ee aurel32
        if (s->regs[SONIC_TCR] & SONIC_TCR_PINT) {
368 a65f56ee aurel32
            s->regs[SONIC_ISR] |= SONIC_ISR_PINT;
369 a65f56ee aurel32
        } else {
370 a65f56ee aurel32
            s->regs[SONIC_ISR] &= ~SONIC_ISR_PINT;
371 a65f56ee aurel32
        }
372 a65f56ee aurel32
373 a65f56ee aurel32
        for (i = 0; i < s->regs[SONIC_TFC]; ) {
374 a65f56ee aurel32
            /* Append fragment */
375 a65f56ee aurel32
            len = s->regs[SONIC_TFS];
376 a65f56ee aurel32
            if (tx_len + len > sizeof(s->tx_buffer)) {
377 a65f56ee aurel32
                len = sizeof(s->tx_buffer) - tx_len;
378 a65f56ee aurel32
            }
379 a65f56ee aurel32
            s->memory_rw(s->mem_opaque,
380 a65f56ee aurel32
                (s->regs[SONIC_TSA1] << 16) | s->regs[SONIC_TSA0],
381 a65f56ee aurel32
                &s->tx_buffer[tx_len], len, 0);
382 a65f56ee aurel32
            tx_len += len;
383 a65f56ee aurel32
384 a65f56ee aurel32
            i++;
385 a65f56ee aurel32
            if (i != s->regs[SONIC_TFC]) {
386 a65f56ee aurel32
                /* Read next fragment details */
387 a65f56ee aurel32
                size = sizeof(uint16_t) * 3 * width;
388 a65f56ee aurel32
                s->memory_rw(s->mem_opaque,
389 a65f56ee aurel32
                    ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * i) * width,
390 a65f56ee aurel32
                    (uint8_t *)data, size, 0);
391 a65f56ee aurel32
                s->regs[SONIC_TSA0] = data[0 * width];
392 a65f56ee aurel32
                s->regs[SONIC_TSA1] = data[1 * width];
393 a65f56ee aurel32
                s->regs[SONIC_TFS] = data[2 * width];
394 a65f56ee aurel32
            }
395 a65f56ee aurel32
        }
396 a65f56ee aurel32
397 a65f56ee aurel32
        /* Handle Ethernet checksum */
398 a65f56ee aurel32
        if (!(s->regs[SONIC_TCR] & SONIC_TCR_CRCI)) {
399 a65f56ee aurel32
            /* Don't append FCS there, to look like slirp packets
400 a65f56ee aurel32
             * which don't have one */
401 a65f56ee aurel32
        } else {
402 a65f56ee aurel32
            /* Remove existing FCS */
403 a65f56ee aurel32
            tx_len -= 4;
404 a65f56ee aurel32
        }
405 a65f56ee aurel32
406 a65f56ee aurel32
        if (s->regs[SONIC_RCR] & (SONIC_RCR_LB1 | SONIC_RCR_LB0)) {
407 a65f56ee aurel32
            /* Loopback */
408 a65f56ee aurel32
            s->regs[SONIC_TCR] |= SONIC_TCR_CRSL;
409 e3f5ec2b Mark McLoughlin
            if (s->vc->can_receive(s->vc)) {
410 a65f56ee aurel32
                s->loopback_packet = 1;
411 e3f5ec2b Mark McLoughlin
                s->vc->receive(s->vc, s->tx_buffer, tx_len);
412 a65f56ee aurel32
            }
413 a65f56ee aurel32
        } else {
414 a65f56ee aurel32
            /* Transmit packet */
415 a65f56ee aurel32
            qemu_send_packet(s->vc, s->tx_buffer, tx_len);
416 a65f56ee aurel32
        }
417 a65f56ee aurel32
        s->regs[SONIC_TCR] |= SONIC_TCR_PTX;
418 a65f56ee aurel32
419 a65f56ee aurel32
        /* Write status */
420 a65f56ee aurel32
        data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */
421 a65f56ee aurel32
        size = sizeof(uint16_t) * width;
422 a65f56ee aurel32
        s->memory_rw(s->mem_opaque,
423 a65f56ee aurel32
            (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA],
424 a65f56ee aurel32
            (uint8_t *)data, size, 1);
425 a65f56ee aurel32
426 a65f56ee aurel32
        if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) {
427 a65f56ee aurel32
            /* Read footer of packet */
428 a65f56ee aurel32
            size = sizeof(uint16_t) * width;
429 a65f56ee aurel32
            s->memory_rw(s->mem_opaque,
430 a65f56ee aurel32
                ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width,
431 a65f56ee aurel32
                (uint8_t *)data, size, 0);
432 a65f56ee aurel32
            s->regs[SONIC_CTDA] = data[0 * width] & ~0x1;
433 a65f56ee aurel32
            if (data[0 * width] & 0x1) {
434 a65f56ee aurel32
                /* EOL detected */
435 a65f56ee aurel32
                break;
436 a65f56ee aurel32
            }
437 a65f56ee aurel32
        }
438 a65f56ee aurel32
    }
439 a65f56ee aurel32
440 a65f56ee aurel32
    /* Done */
441 a65f56ee aurel32
    s->regs[SONIC_CR] &= ~SONIC_CR_TXP;
442 a65f56ee aurel32
    s->regs[SONIC_ISR] |= SONIC_ISR_TXDN;
443 a65f56ee aurel32
    dp8393x_update_irq(s);
444 a65f56ee aurel32
}
445 a65f56ee aurel32
446 a65f56ee aurel32
static void do_halt_transmission(dp8393xState *s)
447 a65f56ee aurel32
{
448 a65f56ee aurel32
    /* Nothing to do */
449 a65f56ee aurel32
}
450 a65f56ee aurel32
451 a65f56ee aurel32
static void do_command(dp8393xState *s, uint16_t command)
452 a65f56ee aurel32
{
453 a65f56ee aurel32
    if ((s->regs[SONIC_CR] & SONIC_CR_RST) && !(command & SONIC_CR_RST)) {
454 a65f56ee aurel32
        s->regs[SONIC_CR] &= ~SONIC_CR_RST;
455 a65f56ee aurel32
        return;
456 a65f56ee aurel32
    }
457 a65f56ee aurel32
458 a65f56ee aurel32
    s->regs[SONIC_CR] |= (command & SONIC_CR_MASK);
459 a65f56ee aurel32
460 a65f56ee aurel32
    if (command & SONIC_CR_HTX)
461 a65f56ee aurel32
        do_halt_transmission(s);
462 a65f56ee aurel32
    if (command & SONIC_CR_TXP)
463 a65f56ee aurel32
        do_transmit_packets(s);
464 a65f56ee aurel32
    if (command & SONIC_CR_RXDIS)
465 a65f56ee aurel32
        do_receiver_disable(s);
466 a65f56ee aurel32
    if (command & SONIC_CR_RXEN)
467 a65f56ee aurel32
        do_receiver_enable(s);
468 a65f56ee aurel32
    if (command & SONIC_CR_STP)
469 a65f56ee aurel32
        do_stop_timer(s);
470 a65f56ee aurel32
    if (command & SONIC_CR_ST)
471 a65f56ee aurel32
        do_start_timer(s);
472 a65f56ee aurel32
    if (command & SONIC_CR_RST)
473 a65f56ee aurel32
        do_software_reset(s);
474 a65f56ee aurel32
    if (command & SONIC_CR_RRRA)
475 a65f56ee aurel32
        do_read_rra(s);
476 a65f56ee aurel32
    if (command & SONIC_CR_LCAM)
477 a65f56ee aurel32
        do_load_cam(s);
478 a65f56ee aurel32
}
479 a65f56ee aurel32
480 a65f56ee aurel32
static uint16_t read_register(dp8393xState *s, int reg)
481 a65f56ee aurel32
{
482 a65f56ee aurel32
    uint16_t val = 0;
483 a65f56ee aurel32
484 a65f56ee aurel32
    switch (reg) {
485 a65f56ee aurel32
        /* Update data before reading it */
486 a65f56ee aurel32
        case SONIC_WT0:
487 a65f56ee aurel32
        case SONIC_WT1:
488 a65f56ee aurel32
            update_wt_regs(s);
489 a65f56ee aurel32
            val = s->regs[reg];
490 a65f56ee aurel32
            break;
491 a65f56ee aurel32
        /* Accept read to some registers only when in reset mode */
492 a65f56ee aurel32
        case SONIC_CAP2:
493 a65f56ee aurel32
        case SONIC_CAP1:
494 a65f56ee aurel32
        case SONIC_CAP0:
495 a65f56ee aurel32
            if (s->regs[SONIC_CR] & SONIC_CR_RST) {
496 a65f56ee aurel32
                val = s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg) + 1] << 8;
497 a65f56ee aurel32
                val |= s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg)];
498 a65f56ee aurel32
            }
499 a65f56ee aurel32
            break;
500 a65f56ee aurel32
        /* All other registers have no special contrainst */
501 a65f56ee aurel32
        default:
502 a65f56ee aurel32
            val = s->regs[reg];
503 a65f56ee aurel32
    }
504 a65f56ee aurel32
505 a65f56ee aurel32
    DPRINTF("read 0x%04x from reg %s\n", val, reg_names[reg]);
506 a65f56ee aurel32
507 a65f56ee aurel32
    return val;
508 a65f56ee aurel32
}
509 a65f56ee aurel32
510 a65f56ee aurel32
static void write_register(dp8393xState *s, int reg, uint16_t val)
511 a65f56ee aurel32
{
512 a65f56ee aurel32
    DPRINTF("write 0x%04x to reg %s\n", val, reg_names[reg]);
513 a65f56ee aurel32
514 a65f56ee aurel32
    switch (reg) {
515 a65f56ee aurel32
        /* Command register */
516 a65f56ee aurel32
        case SONIC_CR:
517 a65f56ee aurel32
            do_command(s, val);;
518 a65f56ee aurel32
            break;
519 a65f56ee aurel32
        /* Prevent write to read-only registers */
520 a65f56ee aurel32
        case SONIC_CAP2:
521 a65f56ee aurel32
        case SONIC_CAP1:
522 a65f56ee aurel32
        case SONIC_CAP0:
523 a65f56ee aurel32
        case SONIC_SR:
524 a65f56ee aurel32
        case SONIC_MDT:
525 a65f56ee aurel32
            DPRINTF("writing to reg %d invalid\n", reg);
526 a65f56ee aurel32
            break;
527 a65f56ee aurel32
        /* Accept write to some registers only when in reset mode */
528 a65f56ee aurel32
        case SONIC_DCR:
529 a65f56ee aurel32
            if (s->regs[SONIC_CR] & SONIC_CR_RST) {
530 a65f56ee aurel32
                s->regs[reg] = val & 0xbfff;
531 a65f56ee aurel32
            } else {
532 a65f56ee aurel32
                DPRINTF("writing to DCR invalid\n");
533 a65f56ee aurel32
            }
534 a65f56ee aurel32
            break;
535 a65f56ee aurel32
        case SONIC_DCR2:
536 a65f56ee aurel32
            if (s->regs[SONIC_CR] & SONIC_CR_RST) {
537 a65f56ee aurel32
                s->regs[reg] = val & 0xf017;
538 a65f56ee aurel32
            } else {
539 a65f56ee aurel32
                DPRINTF("writing to DCR2 invalid\n");
540 a65f56ee aurel32
            }
541 a65f56ee aurel32
            break;
542 a65f56ee aurel32
        /* 12 lower bytes are Read Only */
543 a65f56ee aurel32
        case SONIC_TCR:
544 a65f56ee aurel32
            s->regs[reg] = val & 0xf000;
545 a65f56ee aurel32
            break;
546 a65f56ee aurel32
        /* 9 lower bytes are Read Only */
547 a65f56ee aurel32
        case SONIC_RCR:
548 a65f56ee aurel32
            s->regs[reg] = val & 0xffe0;
549 a65f56ee aurel32
            break;
550 a65f56ee aurel32
        /* Ignore most significant bit */
551 a65f56ee aurel32
        case SONIC_IMR:
552 a65f56ee aurel32
            s->regs[reg] = val & 0x7fff;
553 a65f56ee aurel32
            dp8393x_update_irq(s);
554 a65f56ee aurel32
            break;
555 a65f56ee aurel32
        /* Clear bits by writing 1 to them */
556 a65f56ee aurel32
        case SONIC_ISR:
557 a65f56ee aurel32
            val &= s->regs[reg];
558 a65f56ee aurel32
            s->regs[reg] &= ~val;
559 a65f56ee aurel32
            if (val & SONIC_ISR_RBE) {
560 a65f56ee aurel32
                do_read_rra(s);
561 a65f56ee aurel32
            }
562 a65f56ee aurel32
            dp8393x_update_irq(s);
563 a65f56ee aurel32
            break;
564 a65f56ee aurel32
        /* Ignore least significant bit */
565 a65f56ee aurel32
        case SONIC_RSA:
566 a65f56ee aurel32
        case SONIC_REA:
567 a65f56ee aurel32
        case SONIC_RRP:
568 a65f56ee aurel32
        case SONIC_RWP:
569 a65f56ee aurel32
            s->regs[reg] = val & 0xfffe;
570 a65f56ee aurel32
            break;
571 a65f56ee aurel32
        /* Invert written value for some registers */
572 a65f56ee aurel32
        case SONIC_CRCT:
573 a65f56ee aurel32
        case SONIC_FAET:
574 a65f56ee aurel32
        case SONIC_MPT:
575 a65f56ee aurel32
            s->regs[reg] = val ^ 0xffff;
576 a65f56ee aurel32
            break;
577 a65f56ee aurel32
        /* All other registers have no special contrainst */
578 a65f56ee aurel32
        default:
579 a65f56ee aurel32
            s->regs[reg] = val;
580 a65f56ee aurel32
    }
581 a65f56ee aurel32
582 a65f56ee aurel32
    if (reg == SONIC_WT0 || reg == SONIC_WT1) {
583 a65f56ee aurel32
        set_next_tick(s);
584 a65f56ee aurel32
    }
585 a65f56ee aurel32
}
586 a65f56ee aurel32
587 a65f56ee aurel32
static void dp8393x_watchdog(void *opaque)
588 a65f56ee aurel32
{
589 a65f56ee aurel32
    dp8393xState *s = opaque;
590 a65f56ee aurel32
591 a65f56ee aurel32
    if (s->regs[SONIC_CR] & SONIC_CR_STP) {
592 a65f56ee aurel32
        return;
593 a65f56ee aurel32
    }
594 a65f56ee aurel32
595 a65f56ee aurel32
    s->regs[SONIC_WT1] = 0xffff;
596 a65f56ee aurel32
    s->regs[SONIC_WT0] = 0xffff;
597 a65f56ee aurel32
    set_next_tick(s);
598 a65f56ee aurel32
599 a65f56ee aurel32
    /* Signal underflow */
600 a65f56ee aurel32
    s->regs[SONIC_ISR] |= SONIC_ISR_TC;
601 a65f56ee aurel32
    dp8393x_update_irq(s);
602 a65f56ee aurel32
}
603 a65f56ee aurel32
604 c227f099 Anthony Liguori
static uint32_t dp8393x_readw(void *opaque, target_phys_addr_t addr)
605 a65f56ee aurel32
{
606 a65f56ee aurel32
    dp8393xState *s = opaque;
607 a65f56ee aurel32
    int reg;
608 a65f56ee aurel32
609 a65f56ee aurel32
    if ((addr & ((1 << s->it_shift) - 1)) != 0) {
610 a65f56ee aurel32
        return 0;
611 a65f56ee aurel32
    }
612 a65f56ee aurel32
613 a65f56ee aurel32
    reg = addr >> s->it_shift;
614 a65f56ee aurel32
    return read_register(s, reg);
615 a65f56ee aurel32
}
616 a65f56ee aurel32
617 c227f099 Anthony Liguori
static uint32_t dp8393x_readb(void *opaque, target_phys_addr_t addr)
618 a65f56ee aurel32
{
619 a65f56ee aurel32
    uint16_t v = dp8393x_readw(opaque, addr & ~0x1);
620 a65f56ee aurel32
    return (v >> (8 * (addr & 0x1))) & 0xff;
621 a65f56ee aurel32
}
622 a65f56ee aurel32
623 c227f099 Anthony Liguori
static uint32_t dp8393x_readl(void *opaque, target_phys_addr_t addr)
624 a65f56ee aurel32
{
625 a65f56ee aurel32
    uint32_t v;
626 a65f56ee aurel32
    v = dp8393x_readw(opaque, addr);
627 a65f56ee aurel32
    v |= dp8393x_readw(opaque, addr + 2) << 16;
628 a65f56ee aurel32
    return v;
629 a65f56ee aurel32
}
630 a65f56ee aurel32
631 c227f099 Anthony Liguori
static void dp8393x_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
632 a65f56ee aurel32
{
633 a65f56ee aurel32
    dp8393xState *s = opaque;
634 a65f56ee aurel32
    int reg;
635 a65f56ee aurel32
636 a65f56ee aurel32
    if ((addr & ((1 << s->it_shift) - 1)) != 0) {
637 a65f56ee aurel32
        return;
638 a65f56ee aurel32
    }
639 a65f56ee aurel32
640 a65f56ee aurel32
    reg = addr >> s->it_shift;
641 a65f56ee aurel32
642 a65f56ee aurel32
    write_register(s, reg, (uint16_t)val);
643 a65f56ee aurel32
}
644 a65f56ee aurel32
645 c227f099 Anthony Liguori
static void dp8393x_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
646 a65f56ee aurel32
{
647 a65f56ee aurel32
    uint16_t old_val = dp8393x_readw(opaque, addr & ~0x1);
648 a65f56ee aurel32
649 a65f56ee aurel32
    switch (addr & 3) {
650 a65f56ee aurel32
    case 0:
651 a65f56ee aurel32
        val = val | (old_val & 0xff00);
652 a65f56ee aurel32
        break;
653 a65f56ee aurel32
    case 1:
654 a65f56ee aurel32
        val = (val << 8) | (old_val & 0x00ff);
655 a65f56ee aurel32
        break;
656 a65f56ee aurel32
    }
657 a65f56ee aurel32
    dp8393x_writew(opaque, addr & ~0x1, val);
658 a65f56ee aurel32
}
659 a65f56ee aurel32
660 c227f099 Anthony Liguori
static void dp8393x_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
661 a65f56ee aurel32
{
662 a65f56ee aurel32
    dp8393x_writew(opaque, addr, val & 0xffff);
663 a65f56ee aurel32
    dp8393x_writew(opaque, addr + 2, (val >> 16) & 0xffff);
664 a65f56ee aurel32
}
665 a65f56ee aurel32
666 d60efc6b Blue Swirl
static CPUReadMemoryFunc * const dp8393x_read[3] = {
667 a65f56ee aurel32
    dp8393x_readb,
668 a65f56ee aurel32
    dp8393x_readw,
669 a65f56ee aurel32
    dp8393x_readl,
670 a65f56ee aurel32
};
671 a65f56ee aurel32
672 d60efc6b Blue Swirl
static CPUWriteMemoryFunc * const dp8393x_write[3] = {
673 a65f56ee aurel32
    dp8393x_writeb,
674 a65f56ee aurel32
    dp8393x_writew,
675 a65f56ee aurel32
    dp8393x_writel,
676 a65f56ee aurel32
};
677 a65f56ee aurel32
678 e3f5ec2b Mark McLoughlin
static int nic_can_receive(VLANClientState *vc)
679 a65f56ee aurel32
{
680 e3f5ec2b Mark McLoughlin
    dp8393xState *s = vc->opaque;
681 a65f56ee aurel32
682 a65f56ee aurel32
    if (!(s->regs[SONIC_CR] & SONIC_CR_RXEN))
683 a65f56ee aurel32
        return 0;
684 a65f56ee aurel32
    if (s->regs[SONIC_ISR] & SONIC_ISR_RBE)
685 a65f56ee aurel32
        return 0;
686 a65f56ee aurel32
    return 1;
687 a65f56ee aurel32
}
688 a65f56ee aurel32
689 a65f56ee aurel32
static int receive_filter(dp8393xState *s, const uint8_t * buf, int size)
690 a65f56ee aurel32
{
691 a65f56ee aurel32
    static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
692 a65f56ee aurel32
    int i;
693 a65f56ee aurel32
694 a65f56ee aurel32
    /* Check for runt packet (remember that checksum is not there) */
695 a65f56ee aurel32
    if (size < 64 - 4) {
696 a65f56ee aurel32
        return (s->regs[SONIC_RCR] & SONIC_RCR_RNT) ? 0 : -1;
697 a65f56ee aurel32
    }
698 a65f56ee aurel32
699 a65f56ee aurel32
    /* Check promiscuous mode */
700 a65f56ee aurel32
    if ((s->regs[SONIC_RCR] & SONIC_RCR_PRO) && (buf[0] & 1) == 0) {
701 a65f56ee aurel32
        return 0;
702 a65f56ee aurel32
    }
703 a65f56ee aurel32
704 a65f56ee aurel32
    /* Check multicast packets */
705 a65f56ee aurel32
    if ((s->regs[SONIC_RCR] & SONIC_RCR_AMC) && (buf[0] & 1) == 1) {
706 a65f56ee aurel32
        return SONIC_RCR_MC;
707 a65f56ee aurel32
    }
708 a65f56ee aurel32
709 a65f56ee aurel32
    /* Check broadcast */
710 a65f56ee aurel32
    if ((s->regs[SONIC_RCR] & SONIC_RCR_BRD) && !memcmp(buf, bcast, sizeof(bcast))) {
711 a65f56ee aurel32
        return SONIC_RCR_BC;
712 a65f56ee aurel32
    }
713 a65f56ee aurel32
714 a65f56ee aurel32
    /* Check CAM */
715 a65f56ee aurel32
    for (i = 0; i < 16; i++) {
716 a65f56ee aurel32
        if (s->regs[SONIC_CE] & (1 << i)) {
717 a65f56ee aurel32
             /* Entry enabled */
718 a65f56ee aurel32
             if (!memcmp(buf, s->cam[i], sizeof(s->cam[i]))) {
719 a65f56ee aurel32
                 return 0;
720 a65f56ee aurel32
             }
721 a65f56ee aurel32
        }
722 a65f56ee aurel32
    }
723 a65f56ee aurel32
724 a65f56ee aurel32
    return -1;
725 a65f56ee aurel32
}
726 a65f56ee aurel32
727 4f1c942b Mark McLoughlin
static ssize_t nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size)
728 a65f56ee aurel32
{
729 a65f56ee aurel32
    uint16_t data[10];
730 e3f5ec2b Mark McLoughlin
    dp8393xState *s = vc->opaque;
731 a65f56ee aurel32
    int packet_type;
732 a65f56ee aurel32
    uint32_t available, address;
733 a65f56ee aurel32
    int width, rx_len = size;
734 a65f56ee aurel32
    uint32_t checksum;
735 a65f56ee aurel32
736 a65f56ee aurel32
    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
737 a65f56ee aurel32
738 a65f56ee aurel32
    s->regs[SONIC_RCR] &= ~(SONIC_RCR_PRX | SONIC_RCR_LBK | SONIC_RCR_FAER |
739 a65f56ee aurel32
        SONIC_RCR_CRCR | SONIC_RCR_LPKT | SONIC_RCR_BC | SONIC_RCR_MC);
740 a65f56ee aurel32
741 a65f56ee aurel32
    packet_type = receive_filter(s, buf, size);
742 a65f56ee aurel32
    if (packet_type < 0) {
743 a65f56ee aurel32
        DPRINTF("packet not for netcard\n");
744 4f1c942b Mark McLoughlin
        return -1;
745 a65f56ee aurel32
    }
746 a65f56ee aurel32
747 a65f56ee aurel32
    /* XXX: Check byte ordering */
748 a65f56ee aurel32
749 a65f56ee aurel32
    /* Check for EOL */
750 a65f56ee aurel32
    if (s->regs[SONIC_LLFA] & 0x1) {
751 a65f56ee aurel32
        /* Are we still in resource exhaustion? */
752 a65f56ee aurel32
        size = sizeof(uint16_t) * 1 * width;
753 a65f56ee aurel32
        address = ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width;
754 a65f56ee aurel32
        s->memory_rw(s->mem_opaque, address, (uint8_t*)data, size, 0);
755 a65f56ee aurel32
        if (data[0 * width] & 0x1) {
756 a65f56ee aurel32
            /* Still EOL ; stop reception */
757 4f1c942b Mark McLoughlin
            return -1;
758 a65f56ee aurel32
        } else {
759 a65f56ee aurel32
            s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
760 a65f56ee aurel32
        }
761 a65f56ee aurel32
    }
762 a65f56ee aurel32
763 a65f56ee aurel32
    /* Save current position */
764 a65f56ee aurel32
    s->regs[SONIC_TRBA1] = s->regs[SONIC_CRBA1];
765 a65f56ee aurel32
    s->regs[SONIC_TRBA0] = s->regs[SONIC_CRBA0];
766 a65f56ee aurel32
767 a65f56ee aurel32
    /* Calculate the ethernet checksum */
768 a65f56ee aurel32
#ifdef SONIC_CALCULATE_RXCRC
769 a65f56ee aurel32
    checksum = cpu_to_le32(crc32(0, buf, rx_len));
770 a65f56ee aurel32
#else
771 a65f56ee aurel32
    checksum = 0;
772 a65f56ee aurel32
#endif
773 a65f56ee aurel32
774 a65f56ee aurel32
    /* Put packet into RBA */
775 a65f56ee aurel32
    DPRINTF("Receive packet at %08x\n", (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]);
776 a65f56ee aurel32
    address = (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0];
777 a65f56ee aurel32
    s->memory_rw(s->mem_opaque, address, (uint8_t*)buf, rx_len, 1);
778 a65f56ee aurel32
    address += rx_len;
779 a65f56ee aurel32
    s->memory_rw(s->mem_opaque, address, (uint8_t*)&checksum, 4, 1);
780 a65f56ee aurel32
    rx_len += 4;
781 a65f56ee aurel32
    s->regs[SONIC_CRBA1] = address >> 16;
782 a65f56ee aurel32
    s->regs[SONIC_CRBA0] = address & 0xffff;
783 a65f56ee aurel32
    available = (s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0];
784 a65f56ee aurel32
    available -= rx_len / 2;
785 a65f56ee aurel32
    s->regs[SONIC_RBWC1] = available >> 16;
786 a65f56ee aurel32
    s->regs[SONIC_RBWC0] = available & 0xffff;
787 a65f56ee aurel32
788 a65f56ee aurel32
    /* Update status */
789 a65f56ee aurel32
    if (((s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0]) < s->regs[SONIC_EOBC]) {
790 a65f56ee aurel32
        s->regs[SONIC_RCR] |= SONIC_RCR_LPKT;
791 a65f56ee aurel32
    }
792 a65f56ee aurel32
    s->regs[SONIC_RCR] |= packet_type;
793 a65f56ee aurel32
    s->regs[SONIC_RCR] |= SONIC_RCR_PRX;
794 a65f56ee aurel32
    if (s->loopback_packet) {
795 a65f56ee aurel32
        s->regs[SONIC_RCR] |= SONIC_RCR_LBK;
796 a65f56ee aurel32
        s->loopback_packet = 0;
797 a65f56ee aurel32
    }
798 a65f56ee aurel32
799 a65f56ee aurel32
    /* Write status to memory */
800 a65f56ee aurel32
    DPRINTF("Write status at %08x\n", (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]);
801 a65f56ee aurel32
    data[0 * width] = s->regs[SONIC_RCR]; /* status */
802 a65f56ee aurel32
    data[1 * width] = rx_len; /* byte count */
803 a65f56ee aurel32
    data[2 * width] = s->regs[SONIC_TRBA0]; /* pkt_ptr0 */
804 a65f56ee aurel32
    data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */
805 a65f56ee aurel32
    data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */
806 a65f56ee aurel32
    size = sizeof(uint16_t) * 5 * width;
807 a65f56ee aurel32
    s->memory_rw(s->mem_opaque, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA], (uint8_t *)data, size, 1);
808 a65f56ee aurel32
809 a65f56ee aurel32
    /* Move to next descriptor */
810 a65f56ee aurel32
    size = sizeof(uint16_t) * width;
811 a65f56ee aurel32
    s->memory_rw(s->mem_opaque,
812 a65f56ee aurel32
        ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width,
813 a65f56ee aurel32
        (uint8_t *)data, size, 0);
814 a65f56ee aurel32
    s->regs[SONIC_LLFA] = data[0 * width];
815 a65f56ee aurel32
    if (s->regs[SONIC_LLFA] & 0x1) {
816 a65f56ee aurel32
        /* EOL detected */
817 a65f56ee aurel32
        s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
818 a65f56ee aurel32
    } else {
819 a65f56ee aurel32
        data[0 * width] = 0; /* in_use */
820 a65f56ee aurel32
        s->memory_rw(s->mem_opaque,
821 a65f56ee aurel32
            ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 6 * width,
822 a65f56ee aurel32
            (uint8_t *)data, size, 1);
823 a65f56ee aurel32
        s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
824 a65f56ee aurel32
        s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
825 a65f56ee aurel32
        s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff);
826 a65f56ee aurel32
827 a65f56ee aurel32
        if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) {
828 a65f56ee aurel32
            /* Read next RRA */
829 a65f56ee aurel32
            do_read_rra(s);
830 a65f56ee aurel32
        }
831 a65f56ee aurel32
    }
832 a65f56ee aurel32
833 a65f56ee aurel32
    /* Done */
834 a65f56ee aurel32
    dp8393x_update_irq(s);
835 4f1c942b Mark McLoughlin
836 4f1c942b Mark McLoughlin
    return size;
837 a65f56ee aurel32
}
838 a65f56ee aurel32
839 a65f56ee aurel32
static void nic_reset(void *opaque)
840 a65f56ee aurel32
{
841 a65f56ee aurel32
    dp8393xState *s = opaque;
842 a65f56ee aurel32
    qemu_del_timer(s->watchdog);
843 a65f56ee aurel32
844 a65f56ee aurel32
    s->regs[SONIC_CR] = SONIC_CR_RST | SONIC_CR_STP | SONIC_CR_RXDIS;
845 a65f56ee aurel32
    s->regs[SONIC_DCR] &= ~(SONIC_DCR_EXBUS | SONIC_DCR_LBR);
846 a65f56ee aurel32
    s->regs[SONIC_RCR] &= ~(SONIC_RCR_LB0 | SONIC_RCR_LB1 | SONIC_RCR_BRD | SONIC_RCR_RNT);
847 a65f56ee aurel32
    s->regs[SONIC_TCR] |= SONIC_TCR_NCRS | SONIC_TCR_PTX;
848 a65f56ee aurel32
    s->regs[SONIC_TCR] &= ~SONIC_TCR_BCM;
849 a65f56ee aurel32
    s->regs[SONIC_IMR] = 0;
850 a65f56ee aurel32
    s->regs[SONIC_ISR] = 0;
851 a65f56ee aurel32
    s->regs[SONIC_DCR2] = 0;
852 a65f56ee aurel32
    s->regs[SONIC_EOBC] = 0x02F8;
853 a65f56ee aurel32
    s->regs[SONIC_RSC] = 0;
854 a65f56ee aurel32
    s->regs[SONIC_CE] = 0;
855 a65f56ee aurel32
    s->regs[SONIC_RSC] = 0;
856 a65f56ee aurel32
857 a65f56ee aurel32
    /* Network cable is connected */
858 a65f56ee aurel32
    s->regs[SONIC_RCR] |= SONIC_RCR_CRS;
859 a65f56ee aurel32
860 a65f56ee aurel32
    dp8393x_update_irq(s);
861 a65f56ee aurel32
}
862 a65f56ee aurel32
863 b946a153 aliguori
static void nic_cleanup(VLANClientState *vc)
864 b946a153 aliguori
{
865 b946a153 aliguori
    dp8393xState *s = vc->opaque;
866 b946a153 aliguori
867 b946a153 aliguori
    cpu_unregister_io_memory(s->mmio_index);
868 b946a153 aliguori
869 b946a153 aliguori
    qemu_del_timer(s->watchdog);
870 b946a153 aliguori
    qemu_free_timer(s->watchdog);
871 b946a153 aliguori
872 b946a153 aliguori
    qemu_free(s);
873 b946a153 aliguori
}
874 b946a153 aliguori
875 c227f099 Anthony Liguori
void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift,
876 a65f56ee aurel32
                  qemu_irq irq, void* mem_opaque,
877 c227f099 Anthony Liguori
                  void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write))
878 a65f56ee aurel32
{
879 a65f56ee aurel32
    dp8393xState *s;
880 a65f56ee aurel32
881 a65f56ee aurel32
    qemu_check_nic_model(nd, "dp83932");
882 a65f56ee aurel32
883 a65f56ee aurel32
    s = qemu_mallocz(sizeof(dp8393xState));
884 a65f56ee aurel32
885 a65f56ee aurel32
    s->mem_opaque = mem_opaque;
886 a65f56ee aurel32
    s->memory_rw = memory_rw;
887 a65f56ee aurel32
    s->it_shift = it_shift;
888 a65f56ee aurel32
    s->irq = irq;
889 a65f56ee aurel32
    s->watchdog = qemu_new_timer(vm_clock, dp8393x_watchdog, s);
890 a65f56ee aurel32
    s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
891 a65f56ee aurel32
892 bb6e6364 Mark McLoughlin
    s->vc = nd->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC,
893 bb6e6364 Mark McLoughlin
                                          nd->vlan, nd->netdev,
894 283c7c63 Mark McLoughlin
                                          nd->model, nd->name,
895 ae50b274 Mark McLoughlin
                                          nic_can_receive, nic_receive, NULL,
896 ae50b274 Mark McLoughlin
                                          nic_cleanup, s);
897 a65f56ee aurel32
898 a65f56ee aurel32
    qemu_format_nic_info_str(s->vc, nd->macaddr);
899 a08d4367 Jan Kiszka
    qemu_register_reset(nic_reset, s);
900 a65f56ee aurel32
    nic_reset(s);
901 a65f56ee aurel32
902 1eed09cb Avi Kivity
    s->mmio_index = cpu_register_io_memory(dp8393x_read, dp8393x_write, s);
903 b946a153 aliguori
    cpu_register_physical_memory(base, 0x40 << it_shift, s->mmio_index);
904 a65f56ee aurel32
}