Statistics
| Branch: | Revision:

root / hw / dp8393x.c @ 57c83dac

History | View | Annotate | Download (26.5 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 024e5bb6 Avi Kivity
    MemoryRegion *address_space;
160 024e5bb6 Avi Kivity
    MemoryRegion mmio;
161 a65f56ee aurel32
162 a65f56ee aurel32
    /* Registers */
163 a65f56ee aurel32
    uint8_t cam[16][6];
164 a65f56ee aurel32
    uint16_t regs[0x40];
165 a65f56ee aurel32
166 a65f56ee aurel32
    /* Temporaries */
167 a65f56ee aurel32
    uint8_t tx_buffer[0x10000];
168 a65f56ee aurel32
    int loopback_packet;
169 a65f56ee aurel32
170 a65f56ee aurel32
    /* Memory access */
171 c227f099 Anthony Liguori
    void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write);
172 a65f56ee aurel32
    void* mem_opaque;
173 a65f56ee aurel32
} dp8393xState;
174 a65f56ee aurel32
175 a65f56ee aurel32
static void dp8393x_update_irq(dp8393xState *s)
176 a65f56ee aurel32
{
177 a65f56ee aurel32
    int level = (s->regs[SONIC_IMR] & s->regs[SONIC_ISR]) ? 1 : 0;
178 a65f56ee aurel32
179 a65f56ee aurel32
#ifdef DEBUG_SONIC
180 a65f56ee aurel32
    if (level != s->irq_level) {
181 a65f56ee aurel32
        s->irq_level = level;
182 a65f56ee aurel32
        if (level) {
183 a65f56ee aurel32
            DPRINTF("raise irq, isr is 0x%04x\n", s->regs[SONIC_ISR]);
184 a65f56ee aurel32
        } else {
185 a65f56ee aurel32
            DPRINTF("lower irq\n");
186 a65f56ee aurel32
        }
187 a65f56ee aurel32
    }
188 a65f56ee aurel32
#endif
189 a65f56ee aurel32
190 a65f56ee aurel32
    qemu_set_irq(s->irq, level);
191 a65f56ee aurel32
}
192 a65f56ee aurel32
193 a65f56ee aurel32
static void do_load_cam(dp8393xState *s)
194 a65f56ee aurel32
{
195 a65f56ee aurel32
    uint16_t data[8];
196 a65f56ee aurel32
    int width, size;
197 a65f56ee aurel32
    uint16_t index = 0;
198 a65f56ee aurel32
199 a65f56ee aurel32
    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
200 a65f56ee aurel32
    size = sizeof(uint16_t) * 4 * width;
201 a65f56ee aurel32
202 a65f56ee aurel32
    while (s->regs[SONIC_CDC] & 0x1f) {
203 a65f56ee aurel32
        /* Fill current entry */
204 a65f56ee aurel32
        s->memory_rw(s->mem_opaque,
205 a65f56ee aurel32
            (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
206 a65f56ee aurel32
            (uint8_t *)data, size, 0);
207 a65f56ee aurel32
        s->cam[index][0] = data[1 * width] & 0xff;
208 a65f56ee aurel32
        s->cam[index][1] = data[1 * width] >> 8;
209 a65f56ee aurel32
        s->cam[index][2] = data[2 * width] & 0xff;
210 a65f56ee aurel32
        s->cam[index][3] = data[2 * width] >> 8;
211 a65f56ee aurel32
        s->cam[index][4] = data[3 * width] & 0xff;
212 a65f56ee aurel32
        s->cam[index][5] = data[3 * width] >> 8;
213 a65f56ee aurel32
        DPRINTF("load cam[%d] with %02x%02x%02x%02x%02x%02x\n", index,
214 a65f56ee aurel32
            s->cam[index][0], s->cam[index][1], s->cam[index][2],
215 a65f56ee aurel32
            s->cam[index][3], s->cam[index][4], s->cam[index][5]);
216 a65f56ee aurel32
        /* Move to next entry */
217 a65f56ee aurel32
        s->regs[SONIC_CDC]--;
218 a65f56ee aurel32
        s->regs[SONIC_CDP] += size;
219 a65f56ee aurel32
        index++;
220 a65f56ee aurel32
    }
221 a65f56ee aurel32
222 a65f56ee aurel32
    /* Read CAM enable */
223 a65f56ee aurel32
    s->memory_rw(s->mem_opaque,
224 a65f56ee aurel32
        (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
225 a65f56ee aurel32
        (uint8_t *)data, size, 0);
226 a65f56ee aurel32
    s->regs[SONIC_CE] = data[0 * width];
227 a65f56ee aurel32
    DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]);
228 a65f56ee aurel32
229 a65f56ee aurel32
    /* Done */
230 a65f56ee aurel32
    s->regs[SONIC_CR] &= ~SONIC_CR_LCAM;
231 a65f56ee aurel32
    s->regs[SONIC_ISR] |= SONIC_ISR_LCD;
232 a65f56ee aurel32
    dp8393x_update_irq(s);
233 a65f56ee aurel32
}
234 a65f56ee aurel32
235 a65f56ee aurel32
static void do_read_rra(dp8393xState *s)
236 a65f56ee aurel32
{
237 a65f56ee aurel32
    uint16_t data[8];
238 a65f56ee aurel32
    int width, size;
239 a65f56ee aurel32
240 a65f56ee aurel32
    /* Read memory */
241 a65f56ee aurel32
    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
242 a65f56ee aurel32
    size = sizeof(uint16_t) * 4 * width;
243 a65f56ee aurel32
    s->memory_rw(s->mem_opaque,
244 a65f56ee aurel32
        (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP],
245 a65f56ee aurel32
        (uint8_t *)data, size, 0);
246 a65f56ee aurel32
247 a65f56ee aurel32
    /* Update SONIC registers */
248 a65f56ee aurel32
    s->regs[SONIC_CRBA0] = data[0 * width];
249 a65f56ee aurel32
    s->regs[SONIC_CRBA1] = data[1 * width];
250 a65f56ee aurel32
    s->regs[SONIC_RBWC0] = data[2 * width];
251 a65f56ee aurel32
    s->regs[SONIC_RBWC1] = data[3 * width];
252 a65f56ee aurel32
    DPRINTF("CRBA0/1: 0x%04x/0x%04x, RBWC0/1: 0x%04x/0x%04x\n",
253 a65f56ee aurel32
        s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1],
254 a65f56ee aurel32
        s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]);
255 a65f56ee aurel32
256 a65f56ee aurel32
    /* Go to next entry */
257 a65f56ee aurel32
    s->regs[SONIC_RRP] += size;
258 a65f56ee aurel32
259 a65f56ee aurel32
    /* Handle wrap */
260 a65f56ee aurel32
    if (s->regs[SONIC_RRP] == s->regs[SONIC_REA]) {
261 a65f56ee aurel32
        s->regs[SONIC_RRP] = s->regs[SONIC_RSA];
262 a65f56ee aurel32
    }
263 a65f56ee aurel32
264 a65f56ee aurel32
    /* Check resource exhaustion */
265 a65f56ee aurel32
    if (s->regs[SONIC_RRP] == s->regs[SONIC_RWP])
266 a65f56ee aurel32
    {
267 a65f56ee aurel32
        s->regs[SONIC_ISR] |= SONIC_ISR_RBE;
268 a65f56ee aurel32
        dp8393x_update_irq(s);
269 a65f56ee aurel32
    }
270 a65f56ee aurel32
271 a65f56ee aurel32
    /* Done */
272 a65f56ee aurel32
    s->regs[SONIC_CR] &= ~SONIC_CR_RRRA;
273 a65f56ee aurel32
}
274 a65f56ee aurel32
275 a65f56ee aurel32
static void do_software_reset(dp8393xState *s)
276 a65f56ee aurel32
{
277 a65f56ee aurel32
    qemu_del_timer(s->watchdog);
278 a65f56ee aurel32
279 a65f56ee aurel32
    s->regs[SONIC_CR] &= ~(SONIC_CR_LCAM | SONIC_CR_RRRA | SONIC_CR_TXP | SONIC_CR_HTX);
280 a65f56ee aurel32
    s->regs[SONIC_CR] |= SONIC_CR_RST | SONIC_CR_RXDIS;
281 a65f56ee aurel32
}
282 a65f56ee aurel32
283 a65f56ee aurel32
static void set_next_tick(dp8393xState *s)
284 a65f56ee aurel32
{
285 a65f56ee aurel32
    uint32_t ticks;
286 a65f56ee aurel32
    int64_t delay;
287 a65f56ee aurel32
288 a65f56ee aurel32
    if (s->regs[SONIC_CR] & SONIC_CR_STP) {
289 a65f56ee aurel32
        qemu_del_timer(s->watchdog);
290 a65f56ee aurel32
        return;
291 a65f56ee aurel32
    }
292 a65f56ee aurel32
293 a65f56ee aurel32
    ticks = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
294 74475455 Paolo Bonzini
    s->wt_last_update = qemu_get_clock_ns(vm_clock);
295 6ee093c9 Juan Quintela
    delay = get_ticks_per_sec() * ticks / 5000000;
296 a65f56ee aurel32
    qemu_mod_timer(s->watchdog, s->wt_last_update + delay);
297 a65f56ee aurel32
}
298 a65f56ee aurel32
299 a65f56ee aurel32
static void update_wt_regs(dp8393xState *s)
300 a65f56ee aurel32
{
301 a65f56ee aurel32
    int64_t elapsed;
302 a65f56ee aurel32
    uint32_t val;
303 a65f56ee aurel32
304 a65f56ee aurel32
    if (s->regs[SONIC_CR] & SONIC_CR_STP) {
305 a65f56ee aurel32
        qemu_del_timer(s->watchdog);
306 a65f56ee aurel32
        return;
307 a65f56ee aurel32
    }
308 a65f56ee aurel32
309 74475455 Paolo Bonzini
    elapsed = s->wt_last_update - qemu_get_clock_ns(vm_clock);
310 a65f56ee aurel32
    val = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
311 a65f56ee aurel32
    val -= elapsed / 5000000;
312 a65f56ee aurel32
    s->regs[SONIC_WT1] = (val >> 16) & 0xffff;
313 a65f56ee aurel32
    s->regs[SONIC_WT0] = (val >> 0)  & 0xffff;
314 a65f56ee aurel32
    set_next_tick(s);
315 a65f56ee aurel32
316 a65f56ee aurel32
}
317 a65f56ee aurel32
318 a65f56ee aurel32
static void do_start_timer(dp8393xState *s)
319 a65f56ee aurel32
{
320 a65f56ee aurel32
    s->regs[SONIC_CR] &= ~SONIC_CR_STP;
321 a65f56ee aurel32
    set_next_tick(s);
322 a65f56ee aurel32
}
323 a65f56ee aurel32
324 a65f56ee aurel32
static void do_stop_timer(dp8393xState *s)
325 a65f56ee aurel32
{
326 a65f56ee aurel32
    s->regs[SONIC_CR] &= ~SONIC_CR_ST;
327 a65f56ee aurel32
    update_wt_regs(s);
328 a65f56ee aurel32
}
329 a65f56ee aurel32
330 a65f56ee aurel32
static void do_receiver_enable(dp8393xState *s)
331 a65f56ee aurel32
{
332 a65f56ee aurel32
    s->regs[SONIC_CR] &= ~SONIC_CR_RXDIS;
333 a65f56ee aurel32
}
334 a65f56ee aurel32
335 a65f56ee aurel32
static void do_receiver_disable(dp8393xState *s)
336 a65f56ee aurel32
{
337 a65f56ee aurel32
    s->regs[SONIC_CR] &= ~SONIC_CR_RXEN;
338 a65f56ee aurel32
}
339 a65f56ee aurel32
340 a65f56ee aurel32
static void do_transmit_packets(dp8393xState *s)
341 a65f56ee aurel32
{
342 a65f56ee aurel32
    uint16_t data[12];
343 a65f56ee aurel32
    int width, size;
344 a65f56ee aurel32
    int tx_len, len;
345 a65f56ee aurel32
    uint16_t i;
346 a65f56ee aurel32
347 a65f56ee aurel32
    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
348 a65f56ee aurel32
349 a65f56ee aurel32
    while (1) {
350 a65f56ee aurel32
        /* Read memory */
351 a65f56ee aurel32
        DPRINTF("Transmit packet at %08x\n",
352 a65f56ee aurel32
                (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_CTDA]);
353 a65f56ee aurel32
        size = sizeof(uint16_t) * 6 * width;
354 a65f56ee aurel32
        s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA];
355 a65f56ee aurel32
        s->memory_rw(s->mem_opaque,
356 a65f56ee aurel32
            ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * width,
357 a65f56ee aurel32
            (uint8_t *)data, size, 0);
358 a65f56ee aurel32
        tx_len = 0;
359 a65f56ee aurel32
360 a65f56ee aurel32
        /* Update registers */
361 a65f56ee aurel32
        s->regs[SONIC_TCR] = data[0 * width] & 0xf000;
362 a65f56ee aurel32
        s->regs[SONIC_TPS] = data[1 * width];
363 a65f56ee aurel32
        s->regs[SONIC_TFC] = data[2 * width];
364 a65f56ee aurel32
        s->regs[SONIC_TSA0] = data[3 * width];
365 a65f56ee aurel32
        s->regs[SONIC_TSA1] = data[4 * width];
366 a65f56ee aurel32
        s->regs[SONIC_TFS] = data[5 * width];
367 a65f56ee aurel32
368 a65f56ee aurel32
        /* Handle programmable interrupt */
369 a65f56ee aurel32
        if (s->regs[SONIC_TCR] & SONIC_TCR_PINT) {
370 a65f56ee aurel32
            s->regs[SONIC_ISR] |= SONIC_ISR_PINT;
371 a65f56ee aurel32
        } else {
372 a65f56ee aurel32
            s->regs[SONIC_ISR] &= ~SONIC_ISR_PINT;
373 a65f56ee aurel32
        }
374 a65f56ee aurel32
375 a65f56ee aurel32
        for (i = 0; i < s->regs[SONIC_TFC]; ) {
376 a65f56ee aurel32
            /* Append fragment */
377 a65f56ee aurel32
            len = s->regs[SONIC_TFS];
378 a65f56ee aurel32
            if (tx_len + len > sizeof(s->tx_buffer)) {
379 a65f56ee aurel32
                len = sizeof(s->tx_buffer) - tx_len;
380 a65f56ee aurel32
            }
381 a65f56ee aurel32
            s->memory_rw(s->mem_opaque,
382 a65f56ee aurel32
                (s->regs[SONIC_TSA1] << 16) | s->regs[SONIC_TSA0],
383 a65f56ee aurel32
                &s->tx_buffer[tx_len], len, 0);
384 a65f56ee aurel32
            tx_len += len;
385 a65f56ee aurel32
386 a65f56ee aurel32
            i++;
387 a65f56ee aurel32
            if (i != s->regs[SONIC_TFC]) {
388 a65f56ee aurel32
                /* Read next fragment details */
389 a65f56ee aurel32
                size = sizeof(uint16_t) * 3 * width;
390 a65f56ee aurel32
                s->memory_rw(s->mem_opaque,
391 a65f56ee aurel32
                    ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * i) * width,
392 a65f56ee aurel32
                    (uint8_t *)data, size, 0);
393 a65f56ee aurel32
                s->regs[SONIC_TSA0] = data[0 * width];
394 a65f56ee aurel32
                s->regs[SONIC_TSA1] = data[1 * width];
395 a65f56ee aurel32
                s->regs[SONIC_TFS] = data[2 * width];
396 a65f56ee aurel32
            }
397 a65f56ee aurel32
        }
398 a65f56ee aurel32
399 a65f56ee aurel32
        /* Handle Ethernet checksum */
400 a65f56ee aurel32
        if (!(s->regs[SONIC_TCR] & SONIC_TCR_CRCI)) {
401 a65f56ee aurel32
            /* Don't append FCS there, to look like slirp packets
402 a65f56ee aurel32
             * which don't have one */
403 a65f56ee aurel32
        } else {
404 a65f56ee aurel32
            /* Remove existing FCS */
405 a65f56ee aurel32
            tx_len -= 4;
406 a65f56ee aurel32
        }
407 a65f56ee aurel32
408 a65f56ee aurel32
        if (s->regs[SONIC_RCR] & (SONIC_RCR_LB1 | SONIC_RCR_LB0)) {
409 a65f56ee aurel32
            /* Loopback */
410 a65f56ee aurel32
            s->regs[SONIC_TCR] |= SONIC_TCR_CRSL;
411 665a3b07 Mark McLoughlin
            if (s->nic->nc.info->can_receive(&s->nic->nc)) {
412 a65f56ee aurel32
                s->loopback_packet = 1;
413 665a3b07 Mark McLoughlin
                s->nic->nc.info->receive(&s->nic->nc, s->tx_buffer, tx_len);
414 a65f56ee aurel32
            }
415 a65f56ee aurel32
        } else {
416 a65f56ee aurel32
            /* Transmit packet */
417 05f41fe3 Mark McLoughlin
            qemu_send_packet(&s->nic->nc, s->tx_buffer, tx_len);
418 a65f56ee aurel32
        }
419 a65f56ee aurel32
        s->regs[SONIC_TCR] |= SONIC_TCR_PTX;
420 a65f56ee aurel32
421 a65f56ee aurel32
        /* Write status */
422 a65f56ee aurel32
        data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */
423 a65f56ee aurel32
        size = sizeof(uint16_t) * width;
424 a65f56ee aurel32
        s->memory_rw(s->mem_opaque,
425 a65f56ee aurel32
            (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA],
426 a65f56ee aurel32
            (uint8_t *)data, size, 1);
427 a65f56ee aurel32
428 a65f56ee aurel32
        if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) {
429 a65f56ee aurel32
            /* Read footer of packet */
430 a65f56ee aurel32
            size = sizeof(uint16_t) * width;
431 a65f56ee aurel32
            s->memory_rw(s->mem_opaque,
432 a65f56ee aurel32
                ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width,
433 a65f56ee aurel32
                (uint8_t *)data, size, 0);
434 a65f56ee aurel32
            s->regs[SONIC_CTDA] = data[0 * width] & ~0x1;
435 a65f56ee aurel32
            if (data[0 * width] & 0x1) {
436 a65f56ee aurel32
                /* EOL detected */
437 a65f56ee aurel32
                break;
438 a65f56ee aurel32
            }
439 a65f56ee aurel32
        }
440 a65f56ee aurel32
    }
441 a65f56ee aurel32
442 a65f56ee aurel32
    /* Done */
443 a65f56ee aurel32
    s->regs[SONIC_CR] &= ~SONIC_CR_TXP;
444 a65f56ee aurel32
    s->regs[SONIC_ISR] |= SONIC_ISR_TXDN;
445 a65f56ee aurel32
    dp8393x_update_irq(s);
446 a65f56ee aurel32
}
447 a65f56ee aurel32
448 a65f56ee aurel32
static void do_halt_transmission(dp8393xState *s)
449 a65f56ee aurel32
{
450 a65f56ee aurel32
    /* Nothing to do */
451 a65f56ee aurel32
}
452 a65f56ee aurel32
453 a65f56ee aurel32
static void do_command(dp8393xState *s, uint16_t command)
454 a65f56ee aurel32
{
455 a65f56ee aurel32
    if ((s->regs[SONIC_CR] & SONIC_CR_RST) && !(command & SONIC_CR_RST)) {
456 a65f56ee aurel32
        s->regs[SONIC_CR] &= ~SONIC_CR_RST;
457 a65f56ee aurel32
        return;
458 a65f56ee aurel32
    }
459 a65f56ee aurel32
460 a65f56ee aurel32
    s->regs[SONIC_CR] |= (command & SONIC_CR_MASK);
461 a65f56ee aurel32
462 a65f56ee aurel32
    if (command & SONIC_CR_HTX)
463 a65f56ee aurel32
        do_halt_transmission(s);
464 a65f56ee aurel32
    if (command & SONIC_CR_TXP)
465 a65f56ee aurel32
        do_transmit_packets(s);
466 a65f56ee aurel32
    if (command & SONIC_CR_RXDIS)
467 a65f56ee aurel32
        do_receiver_disable(s);
468 a65f56ee aurel32
    if (command & SONIC_CR_RXEN)
469 a65f56ee aurel32
        do_receiver_enable(s);
470 a65f56ee aurel32
    if (command & SONIC_CR_STP)
471 a65f56ee aurel32
        do_stop_timer(s);
472 a65f56ee aurel32
    if (command & SONIC_CR_ST)
473 a65f56ee aurel32
        do_start_timer(s);
474 a65f56ee aurel32
    if (command & SONIC_CR_RST)
475 a65f56ee aurel32
        do_software_reset(s);
476 a65f56ee aurel32
    if (command & SONIC_CR_RRRA)
477 a65f56ee aurel32
        do_read_rra(s);
478 a65f56ee aurel32
    if (command & SONIC_CR_LCAM)
479 a65f56ee aurel32
        do_load_cam(s);
480 a65f56ee aurel32
}
481 a65f56ee aurel32
482 a65f56ee aurel32
static uint16_t read_register(dp8393xState *s, int reg)
483 a65f56ee aurel32
{
484 a65f56ee aurel32
    uint16_t val = 0;
485 a65f56ee aurel32
486 a65f56ee aurel32
    switch (reg) {
487 a65f56ee aurel32
        /* Update data before reading it */
488 a65f56ee aurel32
        case SONIC_WT0:
489 a65f56ee aurel32
        case SONIC_WT1:
490 a65f56ee aurel32
            update_wt_regs(s);
491 a65f56ee aurel32
            val = s->regs[reg];
492 a65f56ee aurel32
            break;
493 a65f56ee aurel32
        /* Accept read to some registers only when in reset mode */
494 a65f56ee aurel32
        case SONIC_CAP2:
495 a65f56ee aurel32
        case SONIC_CAP1:
496 a65f56ee aurel32
        case SONIC_CAP0:
497 a65f56ee aurel32
            if (s->regs[SONIC_CR] & SONIC_CR_RST) {
498 a65f56ee aurel32
                val = s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg) + 1] << 8;
499 a65f56ee aurel32
                val |= s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg)];
500 a65f56ee aurel32
            }
501 a65f56ee aurel32
            break;
502 a65f56ee aurel32
        /* All other registers have no special contrainst */
503 a65f56ee aurel32
        default:
504 a65f56ee aurel32
            val = s->regs[reg];
505 a65f56ee aurel32
    }
506 a65f56ee aurel32
507 a65f56ee aurel32
    DPRINTF("read 0x%04x from reg %s\n", val, reg_names[reg]);
508 a65f56ee aurel32
509 a65f56ee aurel32
    return val;
510 a65f56ee aurel32
}
511 a65f56ee aurel32
512 a65f56ee aurel32
static void write_register(dp8393xState *s, int reg, uint16_t val)
513 a65f56ee aurel32
{
514 a65f56ee aurel32
    DPRINTF("write 0x%04x to reg %s\n", val, reg_names[reg]);
515 a65f56ee aurel32
516 a65f56ee aurel32
    switch (reg) {
517 a65f56ee aurel32
        /* Command register */
518 a65f56ee aurel32
        case SONIC_CR:
519 d1805896 Hervรฉ Poussineau
            do_command(s, val);
520 a65f56ee aurel32
            break;
521 a65f56ee aurel32
        /* Prevent write to read-only registers */
522 a65f56ee aurel32
        case SONIC_CAP2:
523 a65f56ee aurel32
        case SONIC_CAP1:
524 a65f56ee aurel32
        case SONIC_CAP0:
525 a65f56ee aurel32
        case SONIC_SR:
526 a65f56ee aurel32
        case SONIC_MDT:
527 a65f56ee aurel32
            DPRINTF("writing to reg %d invalid\n", reg);
528 a65f56ee aurel32
            break;
529 a65f56ee aurel32
        /* Accept write to some registers only when in reset mode */
530 a65f56ee aurel32
        case SONIC_DCR:
531 a65f56ee aurel32
            if (s->regs[SONIC_CR] & SONIC_CR_RST) {
532 a65f56ee aurel32
                s->regs[reg] = val & 0xbfff;
533 a65f56ee aurel32
            } else {
534 a65f56ee aurel32
                DPRINTF("writing to DCR invalid\n");
535 a65f56ee aurel32
            }
536 a65f56ee aurel32
            break;
537 a65f56ee aurel32
        case SONIC_DCR2:
538 a65f56ee aurel32
            if (s->regs[SONIC_CR] & SONIC_CR_RST) {
539 a65f56ee aurel32
                s->regs[reg] = val & 0xf017;
540 a65f56ee aurel32
            } else {
541 a65f56ee aurel32
                DPRINTF("writing to DCR2 invalid\n");
542 a65f56ee aurel32
            }
543 a65f56ee aurel32
            break;
544 a65f56ee aurel32
        /* 12 lower bytes are Read Only */
545 a65f56ee aurel32
        case SONIC_TCR:
546 a65f56ee aurel32
            s->regs[reg] = val & 0xf000;
547 a65f56ee aurel32
            break;
548 a65f56ee aurel32
        /* 9 lower bytes are Read Only */
549 a65f56ee aurel32
        case SONIC_RCR:
550 a65f56ee aurel32
            s->regs[reg] = val & 0xffe0;
551 a65f56ee aurel32
            break;
552 a65f56ee aurel32
        /* Ignore most significant bit */
553 a65f56ee aurel32
        case SONIC_IMR:
554 a65f56ee aurel32
            s->regs[reg] = val & 0x7fff;
555 a65f56ee aurel32
            dp8393x_update_irq(s);
556 a65f56ee aurel32
            break;
557 a65f56ee aurel32
        /* Clear bits by writing 1 to them */
558 a65f56ee aurel32
        case SONIC_ISR:
559 a65f56ee aurel32
            val &= s->regs[reg];
560 a65f56ee aurel32
            s->regs[reg] &= ~val;
561 a65f56ee aurel32
            if (val & SONIC_ISR_RBE) {
562 a65f56ee aurel32
                do_read_rra(s);
563 a65f56ee aurel32
            }
564 a65f56ee aurel32
            dp8393x_update_irq(s);
565 a65f56ee aurel32
            break;
566 a65f56ee aurel32
        /* Ignore least significant bit */
567 a65f56ee aurel32
        case SONIC_RSA:
568 a65f56ee aurel32
        case SONIC_REA:
569 a65f56ee aurel32
        case SONIC_RRP:
570 a65f56ee aurel32
        case SONIC_RWP:
571 a65f56ee aurel32
            s->regs[reg] = val & 0xfffe;
572 a65f56ee aurel32
            break;
573 a65f56ee aurel32
        /* Invert written value for some registers */
574 a65f56ee aurel32
        case SONIC_CRCT:
575 a65f56ee aurel32
        case SONIC_FAET:
576 a65f56ee aurel32
        case SONIC_MPT:
577 a65f56ee aurel32
            s->regs[reg] = val ^ 0xffff;
578 a65f56ee aurel32
            break;
579 a65f56ee aurel32
        /* All other registers have no special contrainst */
580 a65f56ee aurel32
        default:
581 a65f56ee aurel32
            s->regs[reg] = val;
582 a65f56ee aurel32
    }
583 a65f56ee aurel32
584 a65f56ee aurel32
    if (reg == SONIC_WT0 || reg == SONIC_WT1) {
585 a65f56ee aurel32
        set_next_tick(s);
586 a65f56ee aurel32
    }
587 a65f56ee aurel32
}
588 a65f56ee aurel32
589 a65f56ee aurel32
static void dp8393x_watchdog(void *opaque)
590 a65f56ee aurel32
{
591 a65f56ee aurel32
    dp8393xState *s = opaque;
592 a65f56ee aurel32
593 a65f56ee aurel32
    if (s->regs[SONIC_CR] & SONIC_CR_STP) {
594 a65f56ee aurel32
        return;
595 a65f56ee aurel32
    }
596 a65f56ee aurel32
597 a65f56ee aurel32
    s->regs[SONIC_WT1] = 0xffff;
598 a65f56ee aurel32
    s->regs[SONIC_WT0] = 0xffff;
599 a65f56ee aurel32
    set_next_tick(s);
600 a65f56ee aurel32
601 a65f56ee aurel32
    /* Signal underflow */
602 a65f56ee aurel32
    s->regs[SONIC_ISR] |= SONIC_ISR_TC;
603 a65f56ee aurel32
    dp8393x_update_irq(s);
604 a65f56ee aurel32
}
605 a65f56ee aurel32
606 c227f099 Anthony Liguori
static uint32_t dp8393x_readw(void *opaque, target_phys_addr_t addr)
607 a65f56ee aurel32
{
608 a65f56ee aurel32
    dp8393xState *s = opaque;
609 a65f56ee aurel32
    int reg;
610 a65f56ee aurel32
611 a65f56ee aurel32
    if ((addr & ((1 << s->it_shift) - 1)) != 0) {
612 a65f56ee aurel32
        return 0;
613 a65f56ee aurel32
    }
614 a65f56ee aurel32
615 a65f56ee aurel32
    reg = addr >> s->it_shift;
616 a65f56ee aurel32
    return read_register(s, reg);
617 a65f56ee aurel32
}
618 a65f56ee aurel32
619 c227f099 Anthony Liguori
static uint32_t dp8393x_readb(void *opaque, target_phys_addr_t addr)
620 a65f56ee aurel32
{
621 a65f56ee aurel32
    uint16_t v = dp8393x_readw(opaque, addr & ~0x1);
622 a65f56ee aurel32
    return (v >> (8 * (addr & 0x1))) & 0xff;
623 a65f56ee aurel32
}
624 a65f56ee aurel32
625 c227f099 Anthony Liguori
static uint32_t dp8393x_readl(void *opaque, target_phys_addr_t addr)
626 a65f56ee aurel32
{
627 a65f56ee aurel32
    uint32_t v;
628 a65f56ee aurel32
    v = dp8393x_readw(opaque, addr);
629 a65f56ee aurel32
    v |= dp8393x_readw(opaque, addr + 2) << 16;
630 a65f56ee aurel32
    return v;
631 a65f56ee aurel32
}
632 a65f56ee aurel32
633 c227f099 Anthony Liguori
static void dp8393x_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
634 a65f56ee aurel32
{
635 a65f56ee aurel32
    dp8393xState *s = opaque;
636 a65f56ee aurel32
    int reg;
637 a65f56ee aurel32
638 a65f56ee aurel32
    if ((addr & ((1 << s->it_shift) - 1)) != 0) {
639 a65f56ee aurel32
        return;
640 a65f56ee aurel32
    }
641 a65f56ee aurel32
642 a65f56ee aurel32
    reg = addr >> s->it_shift;
643 a65f56ee aurel32
644 a65f56ee aurel32
    write_register(s, reg, (uint16_t)val);
645 a65f56ee aurel32
}
646 a65f56ee aurel32
647 c227f099 Anthony Liguori
static void dp8393x_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
648 a65f56ee aurel32
{
649 a65f56ee aurel32
    uint16_t old_val = dp8393x_readw(opaque, addr & ~0x1);
650 a65f56ee aurel32
651 a65f56ee aurel32
    switch (addr & 3) {
652 a65f56ee aurel32
    case 0:
653 a65f56ee aurel32
        val = val | (old_val & 0xff00);
654 a65f56ee aurel32
        break;
655 a65f56ee aurel32
    case 1:
656 a65f56ee aurel32
        val = (val << 8) | (old_val & 0x00ff);
657 a65f56ee aurel32
        break;
658 a65f56ee aurel32
    }
659 a65f56ee aurel32
    dp8393x_writew(opaque, addr & ~0x1, val);
660 a65f56ee aurel32
}
661 a65f56ee aurel32
662 c227f099 Anthony Liguori
static void dp8393x_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
663 a65f56ee aurel32
{
664 a65f56ee aurel32
    dp8393x_writew(opaque, addr, val & 0xffff);
665 a65f56ee aurel32
    dp8393x_writew(opaque, addr + 2, (val >> 16) & 0xffff);
666 a65f56ee aurel32
}
667 a65f56ee aurel32
668 024e5bb6 Avi Kivity
static const MemoryRegionOps dp8393x_ops = {
669 024e5bb6 Avi Kivity
    .old_mmio = {
670 024e5bb6 Avi Kivity
        .read = { dp8393x_readb, dp8393x_readw, dp8393x_readl, },
671 024e5bb6 Avi Kivity
        .write = { dp8393x_writeb, dp8393x_writew, dp8393x_writel, },
672 024e5bb6 Avi Kivity
    },
673 024e5bb6 Avi Kivity
    .endianness = DEVICE_NATIVE_ENDIAN,
674 a65f56ee aurel32
};
675 a65f56ee aurel32
676 05f41fe3 Mark McLoughlin
static int nic_can_receive(VLANClientState *nc)
677 a65f56ee aurel32
{
678 05f41fe3 Mark McLoughlin
    dp8393xState *s = DO_UPCAST(NICState, nc, nc)->opaque;
679 a65f56ee aurel32
680 a65f56ee aurel32
    if (!(s->regs[SONIC_CR] & SONIC_CR_RXEN))
681 a65f56ee aurel32
        return 0;
682 a65f56ee aurel32
    if (s->regs[SONIC_ISR] & SONIC_ISR_RBE)
683 a65f56ee aurel32
        return 0;
684 a65f56ee aurel32
    return 1;
685 a65f56ee aurel32
}
686 a65f56ee aurel32
687 a65f56ee aurel32
static int receive_filter(dp8393xState *s, const uint8_t * buf, int size)
688 a65f56ee aurel32
{
689 a65f56ee aurel32
    static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
690 a65f56ee aurel32
    int i;
691 a65f56ee aurel32
692 a65f56ee aurel32
    /* Check for runt packet (remember that checksum is not there) */
693 a65f56ee aurel32
    if (size < 64 - 4) {
694 a65f56ee aurel32
        return (s->regs[SONIC_RCR] & SONIC_RCR_RNT) ? 0 : -1;
695 a65f56ee aurel32
    }
696 a65f56ee aurel32
697 a65f56ee aurel32
    /* Check promiscuous mode */
698 a65f56ee aurel32
    if ((s->regs[SONIC_RCR] & SONIC_RCR_PRO) && (buf[0] & 1) == 0) {
699 a65f56ee aurel32
        return 0;
700 a65f56ee aurel32
    }
701 a65f56ee aurel32
702 a65f56ee aurel32
    /* Check multicast packets */
703 a65f56ee aurel32
    if ((s->regs[SONIC_RCR] & SONIC_RCR_AMC) && (buf[0] & 1) == 1) {
704 a65f56ee aurel32
        return SONIC_RCR_MC;
705 a65f56ee aurel32
    }
706 a65f56ee aurel32
707 a65f56ee aurel32
    /* Check broadcast */
708 a65f56ee aurel32
    if ((s->regs[SONIC_RCR] & SONIC_RCR_BRD) && !memcmp(buf, bcast, sizeof(bcast))) {
709 a65f56ee aurel32
        return SONIC_RCR_BC;
710 a65f56ee aurel32
    }
711 a65f56ee aurel32
712 a65f56ee aurel32
    /* Check CAM */
713 a65f56ee aurel32
    for (i = 0; i < 16; i++) {
714 a65f56ee aurel32
        if (s->regs[SONIC_CE] & (1 << i)) {
715 a65f56ee aurel32
             /* Entry enabled */
716 a65f56ee aurel32
             if (!memcmp(buf, s->cam[i], sizeof(s->cam[i]))) {
717 a65f56ee aurel32
                 return 0;
718 a65f56ee aurel32
             }
719 a65f56ee aurel32
        }
720 a65f56ee aurel32
    }
721 a65f56ee aurel32
722 a65f56ee aurel32
    return -1;
723 a65f56ee aurel32
}
724 a65f56ee aurel32
725 05f41fe3 Mark McLoughlin
static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size)
726 a65f56ee aurel32
{
727 05f41fe3 Mark McLoughlin
    dp8393xState *s = DO_UPCAST(NICState, nc, nc)->opaque;
728 a65f56ee aurel32
    uint16_t data[10];
729 a65f56ee aurel32
    int packet_type;
730 a65f56ee aurel32
    uint32_t available, address;
731 a65f56ee aurel32
    int width, rx_len = size;
732 a65f56ee aurel32
    uint32_t checksum;
733 a65f56ee aurel32
734 a65f56ee aurel32
    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
735 a65f56ee aurel32
736 a65f56ee aurel32
    s->regs[SONIC_RCR] &= ~(SONIC_RCR_PRX | SONIC_RCR_LBK | SONIC_RCR_FAER |
737 a65f56ee aurel32
        SONIC_RCR_CRCR | SONIC_RCR_LPKT | SONIC_RCR_BC | SONIC_RCR_MC);
738 a65f56ee aurel32
739 a65f56ee aurel32
    packet_type = receive_filter(s, buf, size);
740 a65f56ee aurel32
    if (packet_type < 0) {
741 a65f56ee aurel32
        DPRINTF("packet not for netcard\n");
742 4f1c942b Mark McLoughlin
        return -1;
743 a65f56ee aurel32
    }
744 a65f56ee aurel32
745 a65f56ee aurel32
    /* XXX: Check byte ordering */
746 a65f56ee aurel32
747 a65f56ee aurel32
    /* Check for EOL */
748 a65f56ee aurel32
    if (s->regs[SONIC_LLFA] & 0x1) {
749 a65f56ee aurel32
        /* Are we still in resource exhaustion? */
750 a65f56ee aurel32
        size = sizeof(uint16_t) * 1 * width;
751 a65f56ee aurel32
        address = ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width;
752 a65f56ee aurel32
        s->memory_rw(s->mem_opaque, address, (uint8_t*)data, size, 0);
753 a65f56ee aurel32
        if (data[0 * width] & 0x1) {
754 a65f56ee aurel32
            /* Still EOL ; stop reception */
755 4f1c942b Mark McLoughlin
            return -1;
756 a65f56ee aurel32
        } else {
757 a65f56ee aurel32
            s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
758 a65f56ee aurel32
        }
759 a65f56ee aurel32
    }
760 a65f56ee aurel32
761 a65f56ee aurel32
    /* Save current position */
762 a65f56ee aurel32
    s->regs[SONIC_TRBA1] = s->regs[SONIC_CRBA1];
763 a65f56ee aurel32
    s->regs[SONIC_TRBA0] = s->regs[SONIC_CRBA0];
764 a65f56ee aurel32
765 a65f56ee aurel32
    /* Calculate the ethernet checksum */
766 a65f56ee aurel32
#ifdef SONIC_CALCULATE_RXCRC
767 a65f56ee aurel32
    checksum = cpu_to_le32(crc32(0, buf, rx_len));
768 a65f56ee aurel32
#else
769 a65f56ee aurel32
    checksum = 0;
770 a65f56ee aurel32
#endif
771 a65f56ee aurel32
772 a65f56ee aurel32
    /* Put packet into RBA */
773 a65f56ee aurel32
    DPRINTF("Receive packet at %08x\n", (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]);
774 a65f56ee aurel32
    address = (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0];
775 a65f56ee aurel32
    s->memory_rw(s->mem_opaque, address, (uint8_t*)buf, rx_len, 1);
776 a65f56ee aurel32
    address += rx_len;
777 a65f56ee aurel32
    s->memory_rw(s->mem_opaque, address, (uint8_t*)&checksum, 4, 1);
778 a65f56ee aurel32
    rx_len += 4;
779 a65f56ee aurel32
    s->regs[SONIC_CRBA1] = address >> 16;
780 a65f56ee aurel32
    s->regs[SONIC_CRBA0] = address & 0xffff;
781 a65f56ee aurel32
    available = (s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0];
782 a65f56ee aurel32
    available -= rx_len / 2;
783 a65f56ee aurel32
    s->regs[SONIC_RBWC1] = available >> 16;
784 a65f56ee aurel32
    s->regs[SONIC_RBWC0] = available & 0xffff;
785 a65f56ee aurel32
786 a65f56ee aurel32
    /* Update status */
787 a65f56ee aurel32
    if (((s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0]) < s->regs[SONIC_EOBC]) {
788 a65f56ee aurel32
        s->regs[SONIC_RCR] |= SONIC_RCR_LPKT;
789 a65f56ee aurel32
    }
790 a65f56ee aurel32
    s->regs[SONIC_RCR] |= packet_type;
791 a65f56ee aurel32
    s->regs[SONIC_RCR] |= SONIC_RCR_PRX;
792 a65f56ee aurel32
    if (s->loopback_packet) {
793 a65f56ee aurel32
        s->regs[SONIC_RCR] |= SONIC_RCR_LBK;
794 a65f56ee aurel32
        s->loopback_packet = 0;
795 a65f56ee aurel32
    }
796 a65f56ee aurel32
797 a65f56ee aurel32
    /* Write status to memory */
798 a65f56ee aurel32
    DPRINTF("Write status at %08x\n", (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]);
799 a65f56ee aurel32
    data[0 * width] = s->regs[SONIC_RCR]; /* status */
800 a65f56ee aurel32
    data[1 * width] = rx_len; /* byte count */
801 a65f56ee aurel32
    data[2 * width] = s->regs[SONIC_TRBA0]; /* pkt_ptr0 */
802 a65f56ee aurel32
    data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */
803 a65f56ee aurel32
    data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */
804 a65f56ee aurel32
    size = sizeof(uint16_t) * 5 * width;
805 a65f56ee aurel32
    s->memory_rw(s->mem_opaque, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA], (uint8_t *)data, size, 1);
806 a65f56ee aurel32
807 a65f56ee aurel32
    /* Move to next descriptor */
808 a65f56ee aurel32
    size = sizeof(uint16_t) * width;
809 a65f56ee aurel32
    s->memory_rw(s->mem_opaque,
810 a65f56ee aurel32
        ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width,
811 a65f56ee aurel32
        (uint8_t *)data, size, 0);
812 a65f56ee aurel32
    s->regs[SONIC_LLFA] = data[0 * width];
813 a65f56ee aurel32
    if (s->regs[SONIC_LLFA] & 0x1) {
814 a65f56ee aurel32
        /* EOL detected */
815 a65f56ee aurel32
        s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
816 a65f56ee aurel32
    } else {
817 a65f56ee aurel32
        data[0 * width] = 0; /* in_use */
818 a65f56ee aurel32
        s->memory_rw(s->mem_opaque,
819 a65f56ee aurel32
            ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 6 * width,
820 a65f56ee aurel32
            (uint8_t *)data, size, 1);
821 a65f56ee aurel32
        s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
822 a65f56ee aurel32
        s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
823 a65f56ee aurel32
        s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff);
824 a65f56ee aurel32
825 a65f56ee aurel32
        if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) {
826 a65f56ee aurel32
            /* Read next RRA */
827 a65f56ee aurel32
            do_read_rra(s);
828 a65f56ee aurel32
        }
829 a65f56ee aurel32
    }
830 a65f56ee aurel32
831 a65f56ee aurel32
    /* Done */
832 a65f56ee aurel32
    dp8393x_update_irq(s);
833 4f1c942b Mark McLoughlin
834 4f1c942b Mark McLoughlin
    return size;
835 a65f56ee aurel32
}
836 a65f56ee aurel32
837 a65f56ee aurel32
static void nic_reset(void *opaque)
838 a65f56ee aurel32
{
839 a65f56ee aurel32
    dp8393xState *s = opaque;
840 a65f56ee aurel32
    qemu_del_timer(s->watchdog);
841 a65f56ee aurel32
842 a65f56ee aurel32
    s->regs[SONIC_CR] = SONIC_CR_RST | SONIC_CR_STP | SONIC_CR_RXDIS;
843 a65f56ee aurel32
    s->regs[SONIC_DCR] &= ~(SONIC_DCR_EXBUS | SONIC_DCR_LBR);
844 a65f56ee aurel32
    s->regs[SONIC_RCR] &= ~(SONIC_RCR_LB0 | SONIC_RCR_LB1 | SONIC_RCR_BRD | SONIC_RCR_RNT);
845 a65f56ee aurel32
    s->regs[SONIC_TCR] |= SONIC_TCR_NCRS | SONIC_TCR_PTX;
846 a65f56ee aurel32
    s->regs[SONIC_TCR] &= ~SONIC_TCR_BCM;
847 a65f56ee aurel32
    s->regs[SONIC_IMR] = 0;
848 a65f56ee aurel32
    s->regs[SONIC_ISR] = 0;
849 a65f56ee aurel32
    s->regs[SONIC_DCR2] = 0;
850 a65f56ee aurel32
    s->regs[SONIC_EOBC] = 0x02F8;
851 a65f56ee aurel32
    s->regs[SONIC_RSC] = 0;
852 a65f56ee aurel32
    s->regs[SONIC_CE] = 0;
853 a65f56ee aurel32
    s->regs[SONIC_RSC] = 0;
854 a65f56ee aurel32
855 a65f56ee aurel32
    /* Network cable is connected */
856 a65f56ee aurel32
    s->regs[SONIC_RCR] |= SONIC_RCR_CRS;
857 a65f56ee aurel32
858 a65f56ee aurel32
    dp8393x_update_irq(s);
859 a65f56ee aurel32
}
860 a65f56ee aurel32
861 05f41fe3 Mark McLoughlin
static void nic_cleanup(VLANClientState *nc)
862 b946a153 aliguori
{
863 05f41fe3 Mark McLoughlin
    dp8393xState *s = DO_UPCAST(NICState, nc, nc)->opaque;
864 b946a153 aliguori
865 024e5bb6 Avi Kivity
    memory_region_del_subregion(s->address_space, &s->mmio);
866 024e5bb6 Avi Kivity
    memory_region_destroy(&s->mmio);
867 b946a153 aliguori
868 b946a153 aliguori
    qemu_del_timer(s->watchdog);
869 b946a153 aliguori
    qemu_free_timer(s->watchdog);
870 b946a153 aliguori
871 7267c094 Anthony Liguori
    g_free(s);
872 b946a153 aliguori
}
873 b946a153 aliguori
874 05f41fe3 Mark McLoughlin
static NetClientInfo net_dp83932_info = {
875 05f41fe3 Mark McLoughlin
    .type = NET_CLIENT_TYPE_NIC,
876 05f41fe3 Mark McLoughlin
    .size = sizeof(NICState),
877 05f41fe3 Mark McLoughlin
    .can_receive = nic_can_receive,
878 05f41fe3 Mark McLoughlin
    .receive = nic_receive,
879 05f41fe3 Mark McLoughlin
    .cleanup = nic_cleanup,
880 05f41fe3 Mark McLoughlin
};
881 05f41fe3 Mark McLoughlin
882 c227f099 Anthony Liguori
void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift,
883 024e5bb6 Avi Kivity
                  MemoryRegion *address_space,
884 a65f56ee aurel32
                  qemu_irq irq, void* mem_opaque,
885 c227f099 Anthony Liguori
                  void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write))
886 a65f56ee aurel32
{
887 a65f56ee aurel32
    dp8393xState *s;
888 a65f56ee aurel32
889 a65f56ee aurel32
    qemu_check_nic_model(nd, "dp83932");
890 a65f56ee aurel32
891 7267c094 Anthony Liguori
    s = g_malloc0(sizeof(dp8393xState));
892 a65f56ee aurel32
893 024e5bb6 Avi Kivity
    s->address_space = address_space;
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 74475455 Paolo Bonzini
    s->watchdog = qemu_new_timer_ns(vm_clock, dp8393x_watchdog, s);
899 a65f56ee aurel32
    s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
900 a65f56ee aurel32
901 6eed1856 Jan Kiszka
    s->conf.macaddr = nd->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 024e5bb6 Avi Kivity
    memory_region_init_io(&s->mmio, &dp8393x_ops, s,
912 024e5bb6 Avi Kivity
                          "dp8393x", 0x40 << it_shift);
913 024e5bb6 Avi Kivity
    memory_region_add_subregion(address_space, base, &s->mmio);
914 a65f56ee aurel32
}