Statistics
| Branch: | Revision:

root / hw / dp8393x.c @ cda9046b

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