Statistics
| Branch: | Revision:

root / hw / dp8393x.c @ ee2479d3

History | View | Annotate | Download (26.4 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 05f41fe3 Mark McLoughlin
    NICConf conf;
158 05f41fe3 Mark McLoughlin
    NICState *nic;
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 c227f099 Anthony Liguori
    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 6ee093c9 Juan Quintela
    delay = get_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 665a3b07 Mark McLoughlin
            if (s->nic->nc.info->can_receive(&s->nic->nc)) {
411 a65f56ee aurel32
                s->loopback_packet = 1;
412 665a3b07 Mark McLoughlin
                s->nic->nc.info->receive(&s->nic->nc, s->tx_buffer, tx_len);
413 a65f56ee aurel32
            }
414 a65f56ee aurel32
        } else {
415 a65f56ee aurel32
            /* Transmit packet */
416 05f41fe3 Mark McLoughlin
            qemu_send_packet(&s->nic->nc, 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 c227f099 Anthony Liguori
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 c227f099 Anthony Liguori
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 c227f099 Anthony Liguori
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 c227f099 Anthony Liguori
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 c227f099 Anthony Liguori
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 c227f099 Anthony Liguori
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 d60efc6b Blue Swirl
static CPUReadMemoryFunc * const 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 d60efc6b Blue Swirl
static CPUWriteMemoryFunc * const 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 05f41fe3 Mark McLoughlin
static int nic_can_receive(VLANClientState *nc)
680 a65f56ee aurel32
{
681 05f41fe3 Mark McLoughlin
    dp8393xState *s = DO_UPCAST(NICState, nc, nc)->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 05f41fe3 Mark McLoughlin
static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size)
729 a65f56ee aurel32
{
730 05f41fe3 Mark McLoughlin
    dp8393xState *s = DO_UPCAST(NICState, nc, nc)->opaque;
731 a65f56ee aurel32
    uint16_t data[10];
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 4f1c942b Mark McLoughlin
        return -1;
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 4f1c942b Mark McLoughlin
            return -1;
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 4f1c942b Mark McLoughlin
837 4f1c942b Mark McLoughlin
    return size;
838 a65f56ee aurel32
}
839 a65f56ee aurel32
840 a65f56ee aurel32
static void nic_reset(void *opaque)
841 a65f56ee aurel32
{
842 a65f56ee aurel32
    dp8393xState *s = opaque;
843 a65f56ee aurel32
    qemu_del_timer(s->watchdog);
844 a65f56ee aurel32
845 a65f56ee aurel32
    s->regs[SONIC_CR] = SONIC_CR_RST | SONIC_CR_STP | SONIC_CR_RXDIS;
846 a65f56ee aurel32
    s->regs[SONIC_DCR] &= ~(SONIC_DCR_EXBUS | SONIC_DCR_LBR);
847 a65f56ee aurel32
    s->regs[SONIC_RCR] &= ~(SONIC_RCR_LB0 | SONIC_RCR_LB1 | SONIC_RCR_BRD | SONIC_RCR_RNT);
848 a65f56ee aurel32
    s->regs[SONIC_TCR] |= SONIC_TCR_NCRS | SONIC_TCR_PTX;
849 a65f56ee aurel32
    s->regs[SONIC_TCR] &= ~SONIC_TCR_BCM;
850 a65f56ee aurel32
    s->regs[SONIC_IMR] = 0;
851 a65f56ee aurel32
    s->regs[SONIC_ISR] = 0;
852 a65f56ee aurel32
    s->regs[SONIC_DCR2] = 0;
853 a65f56ee aurel32
    s->regs[SONIC_EOBC] = 0x02F8;
854 a65f56ee aurel32
    s->regs[SONIC_RSC] = 0;
855 a65f56ee aurel32
    s->regs[SONIC_CE] = 0;
856 a65f56ee aurel32
    s->regs[SONIC_RSC] = 0;
857 a65f56ee aurel32
858 a65f56ee aurel32
    /* Network cable is connected */
859 a65f56ee aurel32
    s->regs[SONIC_RCR] |= SONIC_RCR_CRS;
860 a65f56ee aurel32
861 a65f56ee aurel32
    dp8393x_update_irq(s);
862 a65f56ee aurel32
}
863 a65f56ee aurel32
864 05f41fe3 Mark McLoughlin
static void nic_cleanup(VLANClientState *nc)
865 b946a153 aliguori
{
866 05f41fe3 Mark McLoughlin
    dp8393xState *s = DO_UPCAST(NICState, nc, nc)->opaque;
867 b946a153 aliguori
868 b946a153 aliguori
    cpu_unregister_io_memory(s->mmio_index);
869 b946a153 aliguori
870 b946a153 aliguori
    qemu_del_timer(s->watchdog);
871 b946a153 aliguori
    qemu_free_timer(s->watchdog);
872 b946a153 aliguori
873 b946a153 aliguori
    qemu_free(s);
874 b946a153 aliguori
}
875 b946a153 aliguori
876 05f41fe3 Mark McLoughlin
static NetClientInfo net_dp83932_info = {
877 05f41fe3 Mark McLoughlin
    .type = NET_CLIENT_TYPE_NIC,
878 05f41fe3 Mark McLoughlin
    .size = sizeof(NICState),
879 05f41fe3 Mark McLoughlin
    .can_receive = nic_can_receive,
880 05f41fe3 Mark McLoughlin
    .receive = nic_receive,
881 05f41fe3 Mark McLoughlin
    .cleanup = nic_cleanup,
882 05f41fe3 Mark McLoughlin
};
883 05f41fe3 Mark McLoughlin
884 c227f099 Anthony Liguori
void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift,
885 a65f56ee aurel32
                  qemu_irq irq, void* mem_opaque,
886 c227f099 Anthony Liguori
                  void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write))
887 a65f56ee aurel32
{
888 a65f56ee aurel32
    dp8393xState *s;
889 a65f56ee aurel32
890 a65f56ee aurel32
    qemu_check_nic_model(nd, "dp83932");
891 a65f56ee aurel32
892 a65f56ee aurel32
    s = qemu_mallocz(sizeof(dp8393xState));
893 a65f56ee aurel32
894 a65f56ee aurel32
    s->mem_opaque = mem_opaque;
895 a65f56ee aurel32
    s->memory_rw = memory_rw;
896 a65f56ee aurel32
    s->it_shift = it_shift;
897 a65f56ee aurel32
    s->irq = irq;
898 a65f56ee aurel32
    s->watchdog = qemu_new_timer(vm_clock, dp8393x_watchdog, s);
899 a65f56ee aurel32
    s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
900 a65f56ee aurel32
901 05f41fe3 Mark McLoughlin
    memcpy(s->conf.macaddr.a, nd->macaddr, sizeof(s->conf.macaddr));
902 05f41fe3 Mark McLoughlin
    s->conf.vlan = nd->vlan;
903 05f41fe3 Mark McLoughlin
    s->conf.peer = nd->netdev;
904 05f41fe3 Mark McLoughlin
905 05f41fe3 Mark McLoughlin
    s->nic = qemu_new_nic(&net_dp83932_info, &s->conf, nd->model, nd->name, s);
906 a65f56ee aurel32
907 05f41fe3 Mark McLoughlin
    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
908 a08d4367 Jan Kiszka
    qemu_register_reset(nic_reset, s);
909 a65f56ee aurel32
    nic_reset(s);
910 a65f56ee aurel32
911 2507c12a Alexander Graf
    s->mmio_index = cpu_register_io_memory(dp8393x_read, dp8393x_write, s,
912 2507c12a Alexander Graf
                                           DEVICE_NATIVE_ENDIAN);
913 b946a153 aliguori
    cpu_register_physical_memory(base, 0x40 << it_shift, s->mmio_index);
914 a65f56ee aurel32
}