Statistics
| Branch: | Revision:

root / hw / net / etraxfs_eth.c @ 1b111dc1

History | View | Annotate | Download (16.8 kB)

1 a3ea5df5 edgar_igl
/*
2 a3ea5df5 edgar_igl
 * QEMU ETRAX Ethernet Controller.
3 a3ea5df5 edgar_igl
 *
4 a3ea5df5 edgar_igl
 * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
5 a3ea5df5 edgar_igl
 *
6 a3ea5df5 edgar_igl
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 a3ea5df5 edgar_igl
 * of this software and associated documentation files (the "Software"), to deal
8 a3ea5df5 edgar_igl
 * in the Software without restriction, including without limitation the rights
9 a3ea5df5 edgar_igl
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 a3ea5df5 edgar_igl
 * copies of the Software, and to permit persons to whom the Software is
11 a3ea5df5 edgar_igl
 * furnished to do so, subject to the following conditions:
12 a3ea5df5 edgar_igl
 *
13 a3ea5df5 edgar_igl
 * The above copyright notice and this permission notice shall be included in
14 a3ea5df5 edgar_igl
 * all copies or substantial portions of the Software.
15 a3ea5df5 edgar_igl
 *
16 a3ea5df5 edgar_igl
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 a3ea5df5 edgar_igl
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 a3ea5df5 edgar_igl
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 a3ea5df5 edgar_igl
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 a3ea5df5 edgar_igl
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 a3ea5df5 edgar_igl
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 a3ea5df5 edgar_igl
 * THE SOFTWARE.
23 a3ea5df5 edgar_igl
 */
24 a3ea5df5 edgar_igl
25 a3ea5df5 edgar_igl
#include <stdio.h>
26 83c9f4ca Paolo Bonzini
#include "hw/sysbus.h"
27 1422e32d Paolo Bonzini
#include "net/net.h"
28 0d09e41a Paolo Bonzini
#include "hw/cris/etraxfs.h"
29 a3ea5df5 edgar_igl
30 a3ea5df5 edgar_igl
#define D(x)
31 a3ea5df5 edgar_igl
32 c6488268 edgar_igl
/* Advertisement control register. */
33 c6488268 edgar_igl
#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
34 c6488268 edgar_igl
#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
35 c6488268 edgar_igl
#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
36 c6488268 edgar_igl
#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
37 c6488268 edgar_igl
38 9fc7577a Grant Likely
/*
39 9fc7577a Grant Likely
 * The MDIO extensions in the TDK PHY model were reversed engineered from the
40 2e56350e edgar_igl
 * linux driver (PHYID and Diagnostics reg).
41 2e56350e edgar_igl
 * TODO: Add friendly names for the register nums.
42 2e56350e edgar_igl
 */
43 a3ea5df5 edgar_igl
struct qemu_phy
44 a3ea5df5 edgar_igl
{
45 9fc7577a Grant Likely
    uint32_t regs[32];
46 a3ea5df5 edgar_igl
47 9fc7577a Grant Likely
    int link;
48 94410b78 edgar_igl
49 9fc7577a Grant Likely
    unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
50 9fc7577a Grant Likely
    void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data);
51 a3ea5df5 edgar_igl
};
52 a3ea5df5 edgar_igl
53 a3ea5df5 edgar_igl
static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
54 a3ea5df5 edgar_igl
{
55 9fc7577a Grant Likely
    int regnum;
56 9fc7577a Grant Likely
    unsigned r = 0;
57 9fc7577a Grant Likely
58 9fc7577a Grant Likely
    regnum = req & 0x1f;
59 9fc7577a Grant Likely
60 9fc7577a Grant Likely
    switch (regnum) {
61 9fc7577a Grant Likely
    case 1:
62 9fc7577a Grant Likely
        if (!phy->link) {
63 9fc7577a Grant Likely
            break;
64 9fc7577a Grant Likely
        }
65 9fc7577a Grant Likely
        /* MR1.     */
66 9fc7577a Grant Likely
        /* Speeds and modes.  */
67 9fc7577a Grant Likely
        r |= (1 << 13) | (1 << 14);
68 9fc7577a Grant Likely
        r |= (1 << 11) | (1 << 12);
69 9fc7577a Grant Likely
        r |= (1 << 5); /* Autoneg complete.  */
70 9fc7577a Grant Likely
        r |= (1 << 3); /* Autoneg able.     */
71 9fc7577a Grant Likely
        r |= (1 << 2); /* link.     */
72 9fc7577a Grant Likely
        break;
73 9fc7577a Grant Likely
    case 5:
74 9fc7577a Grant Likely
        /* Link partner ability.
75 9fc7577a Grant Likely
           We are kind; always agree with whatever best mode
76 9fc7577a Grant Likely
           the guest advertises.  */
77 9fc7577a Grant Likely
        r = 1 << 14; /* Success.  */
78 9fc7577a Grant Likely
        /* Copy advertised modes.  */
79 9fc7577a Grant Likely
        r |= phy->regs[4] & (15 << 5);
80 9fc7577a Grant Likely
        /* Autoneg support.  */
81 9fc7577a Grant Likely
        r |= 1;
82 9fc7577a Grant Likely
        break;
83 9fc7577a Grant Likely
    case 18:
84 9fc7577a Grant Likely
    {
85 9fc7577a Grant Likely
        /* Diagnostics reg.  */
86 9fc7577a Grant Likely
        int duplex = 0;
87 9fc7577a Grant Likely
        int speed_100 = 0;
88 9fc7577a Grant Likely
89 9fc7577a Grant Likely
        if (!phy->link) {
90 9fc7577a Grant Likely
            break;
91 9fc7577a Grant Likely
        }
92 9fc7577a Grant Likely
93 9fc7577a Grant Likely
        /* Are we advertising 100 half or 100 duplex ? */
94 9fc7577a Grant Likely
        speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
95 9fc7577a Grant Likely
        speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
96 9fc7577a Grant Likely
97 9fc7577a Grant Likely
        /* Are we advertising 10 duplex or 100 duplex ? */
98 9fc7577a Grant Likely
        duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
99 9fc7577a Grant Likely
        duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
100 9fc7577a Grant Likely
        r = (speed_100 << 10) | (duplex << 11);
101 9fc7577a Grant Likely
    }
102 9fc7577a Grant Likely
    break;
103 9fc7577a Grant Likely
104 9fc7577a Grant Likely
    default:
105 9fc7577a Grant Likely
        r = phy->regs[regnum];
106 9fc7577a Grant Likely
        break;
107 9fc7577a Grant Likely
    }
108 9fc7577a Grant Likely
    D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum));
109 9fc7577a Grant Likely
    return r;
110 a3ea5df5 edgar_igl
}
111 a3ea5df5 edgar_igl
112 9fc7577a Grant Likely
static void
113 a3ea5df5 edgar_igl
tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
114 a3ea5df5 edgar_igl
{
115 9fc7577a Grant Likely
    int regnum;
116 9fc7577a Grant Likely
117 9fc7577a Grant Likely
    regnum = req & 0x1f;
118 9fc7577a Grant Likely
    D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
119 9fc7577a Grant Likely
    switch (regnum) {
120 9fc7577a Grant Likely
    default:
121 9fc7577a Grant Likely
        phy->regs[regnum] = data;
122 9fc7577a Grant Likely
        break;
123 9fc7577a Grant Likely
    }
124 a3ea5df5 edgar_igl
}
125 a3ea5df5 edgar_igl
126 9fc7577a Grant Likely
static void
127 a3ea5df5 edgar_igl
tdk_init(struct qemu_phy *phy)
128 a3ea5df5 edgar_igl
{
129 9fc7577a Grant Likely
    phy->regs[0] = 0x3100;
130 9fc7577a Grant Likely
    /* PHY Id.  */
131 9fc7577a Grant Likely
    phy->regs[2] = 0x0300;
132 9fc7577a Grant Likely
    phy->regs[3] = 0xe400;
133 9fc7577a Grant Likely
    /* Autonegotiation advertisement reg.  */
134 9fc7577a Grant Likely
    phy->regs[4] = 0x01E1;
135 9fc7577a Grant Likely
    phy->link = 1;
136 9fc7577a Grant Likely
137 9fc7577a Grant Likely
    phy->read = tdk_read;
138 9fc7577a Grant Likely
    phy->write = tdk_write;
139 a3ea5df5 edgar_igl
}
140 a3ea5df5 edgar_igl
141 a3ea5df5 edgar_igl
struct qemu_mdio
142 a3ea5df5 edgar_igl
{
143 9fc7577a Grant Likely
    /* bus.     */
144 9fc7577a Grant Likely
    int mdc;
145 9fc7577a Grant Likely
    int mdio;
146 9fc7577a Grant Likely
147 9fc7577a Grant Likely
    /* decoder.  */
148 9fc7577a Grant Likely
    enum {
149 9fc7577a Grant Likely
        PREAMBLE,
150 9fc7577a Grant Likely
        SOF,
151 9fc7577a Grant Likely
        OPC,
152 9fc7577a Grant Likely
        ADDR,
153 9fc7577a Grant Likely
        REQ,
154 9fc7577a Grant Likely
        TURNAROUND,
155 9fc7577a Grant Likely
        DATA
156 9fc7577a Grant Likely
    } state;
157 9fc7577a Grant Likely
    unsigned int drive;
158 9fc7577a Grant Likely
159 9fc7577a Grant Likely
    unsigned int cnt;
160 9fc7577a Grant Likely
    unsigned int addr;
161 9fc7577a Grant Likely
    unsigned int opc;
162 9fc7577a Grant Likely
    unsigned int req;
163 9fc7577a Grant Likely
    unsigned int data;
164 9fc7577a Grant Likely
165 9fc7577a Grant Likely
    struct qemu_phy *devs[32];
166 a3ea5df5 edgar_igl
};
167 a3ea5df5 edgar_igl
168 9fc7577a Grant Likely
static void
169 a3ea5df5 edgar_igl
mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
170 a3ea5df5 edgar_igl
{
171 9fc7577a Grant Likely
    bus->devs[addr & 0x1f] = phy;
172 a3ea5df5 edgar_igl
}
173 a3ea5df5 edgar_igl
174 d297f464 edgar_igl
#ifdef USE_THIS_DEAD_CODE
175 9fc7577a Grant Likely
static void
176 a3ea5df5 edgar_igl
mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
177 a3ea5df5 edgar_igl
{
178 9fc7577a Grant Likely
    bus->devs[addr & 0x1f] = NULL;
179 a3ea5df5 edgar_igl
}
180 d297f464 edgar_igl
#endif
181 a3ea5df5 edgar_igl
182 a3ea5df5 edgar_igl
static void mdio_read_req(struct qemu_mdio *bus)
183 a3ea5df5 edgar_igl
{
184 9fc7577a Grant Likely
    struct qemu_phy *phy;
185 9fc7577a Grant Likely
186 9fc7577a Grant Likely
    phy = bus->devs[bus->addr];
187 9fc7577a Grant Likely
    if (phy && phy->read) {
188 9fc7577a Grant Likely
        bus->data = phy->read(phy, bus->req);
189 9fc7577a Grant Likely
    } else {
190 9fc7577a Grant Likely
        bus->data = 0xffff;
191 9fc7577a Grant Likely
    }
192 a3ea5df5 edgar_igl
}
193 a3ea5df5 edgar_igl
194 a3ea5df5 edgar_igl
static void mdio_write_req(struct qemu_mdio *bus)
195 a3ea5df5 edgar_igl
{
196 9fc7577a Grant Likely
    struct qemu_phy *phy;
197 a3ea5df5 edgar_igl
198 9fc7577a Grant Likely
    phy = bus->devs[bus->addr];
199 9fc7577a Grant Likely
    if (phy && phy->write) {
200 9fc7577a Grant Likely
        phy->write(phy, bus->req, bus->data);
201 9fc7577a Grant Likely
    }
202 a3ea5df5 edgar_igl
}
203 a3ea5df5 edgar_igl
204 a3ea5df5 edgar_igl
static void mdio_cycle(struct qemu_mdio *bus)
205 a3ea5df5 edgar_igl
{
206 9fc7577a Grant Likely
    bus->cnt++;
207 a3ea5df5 edgar_igl
208 9fc7577a Grant Likely
    D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n",
209 9fc7577a Grant Likely
        bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive));
210 a3ea5df5 edgar_igl
#if 0
211 9fc7577a Grant Likely
    if (bus->mdc) {
212 9fc7577a Grant Likely
        printf("%d", bus->mdio);
213 9fc7577a Grant Likely
    }
214 a3ea5df5 edgar_igl
#endif
215 9fc7577a Grant Likely
    switch (bus->state) {
216 9fc7577a Grant Likely
    case PREAMBLE:
217 9fc7577a Grant Likely
        if (bus->mdc) {
218 9fc7577a Grant Likely
            if (bus->cnt >= (32 * 2) && !bus->mdio) {
219 9fc7577a Grant Likely
                bus->cnt = 0;
220 9fc7577a Grant Likely
                bus->state = SOF;
221 9fc7577a Grant Likely
                bus->data = 0;
222 9fc7577a Grant Likely
            }
223 9fc7577a Grant Likely
        }
224 9fc7577a Grant Likely
        break;
225 9fc7577a Grant Likely
    case SOF:
226 9fc7577a Grant Likely
        if (bus->mdc) {
227 9fc7577a Grant Likely
            if (bus->mdio != 1) {
228 9fc7577a Grant Likely
                printf("WARNING: no SOF\n");
229 9fc7577a Grant Likely
            }
230 9fc7577a Grant Likely
            if (bus->cnt == 1*2) {
231 9fc7577a Grant Likely
                bus->cnt = 0;
232 9fc7577a Grant Likely
                bus->opc = 0;
233 9fc7577a Grant Likely
                bus->state = OPC;
234 9fc7577a Grant Likely
            }
235 9fc7577a Grant Likely
        }
236 9fc7577a Grant Likely
        break;
237 9fc7577a Grant Likely
    case OPC:
238 9fc7577a Grant Likely
        if (bus->mdc) {
239 9fc7577a Grant Likely
            bus->opc <<= 1;
240 9fc7577a Grant Likely
            bus->opc |= bus->mdio & 1;
241 9fc7577a Grant Likely
            if (bus->cnt == 2*2) {
242 9fc7577a Grant Likely
                bus->cnt = 0;
243 9fc7577a Grant Likely
                bus->addr = 0;
244 9fc7577a Grant Likely
                bus->state = ADDR;
245 9fc7577a Grant Likely
            }
246 9fc7577a Grant Likely
        }
247 9fc7577a Grant Likely
        break;
248 9fc7577a Grant Likely
    case ADDR:
249 9fc7577a Grant Likely
        if (bus->mdc) {
250 9fc7577a Grant Likely
            bus->addr <<= 1;
251 9fc7577a Grant Likely
            bus->addr |= bus->mdio & 1;
252 9fc7577a Grant Likely
253 9fc7577a Grant Likely
            if (bus->cnt == 5*2) {
254 9fc7577a Grant Likely
                bus->cnt = 0;
255 9fc7577a Grant Likely
                bus->req = 0;
256 9fc7577a Grant Likely
                bus->state = REQ;
257 9fc7577a Grant Likely
            }
258 9fc7577a Grant Likely
        }
259 9fc7577a Grant Likely
        break;
260 9fc7577a Grant Likely
    case REQ:
261 9fc7577a Grant Likely
        if (bus->mdc) {
262 9fc7577a Grant Likely
            bus->req <<= 1;
263 9fc7577a Grant Likely
            bus->req |= bus->mdio & 1;
264 9fc7577a Grant Likely
            if (bus->cnt == 5*2) {
265 9fc7577a Grant Likely
                bus->cnt = 0;
266 9fc7577a Grant Likely
                bus->state = TURNAROUND;
267 9fc7577a Grant Likely
            }
268 9fc7577a Grant Likely
        }
269 9fc7577a Grant Likely
        break;
270 9fc7577a Grant Likely
    case TURNAROUND:
271 9fc7577a Grant Likely
        if (bus->mdc && bus->cnt == 2*2) {
272 9fc7577a Grant Likely
            bus->mdio = 0;
273 9fc7577a Grant Likely
            bus->cnt = 0;
274 9fc7577a Grant Likely
275 9fc7577a Grant Likely
            if (bus->opc == 2) {
276 9fc7577a Grant Likely
                bus->drive = 1;
277 9fc7577a Grant Likely
                mdio_read_req(bus);
278 9fc7577a Grant Likely
                bus->mdio = bus->data & 1;
279 9fc7577a Grant Likely
            }
280 9fc7577a Grant Likely
            bus->state = DATA;
281 9fc7577a Grant Likely
        }
282 9fc7577a Grant Likely
        break;
283 9fc7577a Grant Likely
    case DATA:
284 9fc7577a Grant Likely
        if (!bus->mdc) {
285 9fc7577a Grant Likely
            if (bus->drive) {
286 9fc7577a Grant Likely
                bus->mdio = !!(bus->data & (1 << 15));
287 9fc7577a Grant Likely
                bus->data <<= 1;
288 9fc7577a Grant Likely
            }
289 9fc7577a Grant Likely
        } else {
290 9fc7577a Grant Likely
            if (!bus->drive) {
291 9fc7577a Grant Likely
                bus->data <<= 1;
292 9fc7577a Grant Likely
                bus->data |= bus->mdio;
293 9fc7577a Grant Likely
            }
294 9fc7577a Grant Likely
            if (bus->cnt == 16 * 2) {
295 9fc7577a Grant Likely
                bus->cnt = 0;
296 9fc7577a Grant Likely
                bus->state = PREAMBLE;
297 9fc7577a Grant Likely
                if (!bus->drive) {
298 9fc7577a Grant Likely
                    mdio_write_req(bus);
299 9fc7577a Grant Likely
                }
300 9fc7577a Grant Likely
                bus->drive = 0;
301 9fc7577a Grant Likely
            }
302 9fc7577a Grant Likely
        }
303 9fc7577a Grant Likely
        break;
304 9fc7577a Grant Likely
    default:
305 9fc7577a Grant Likely
        break;
306 9fc7577a Grant Likely
    }
307 a3ea5df5 edgar_igl
}
308 a3ea5df5 edgar_igl
309 2e56350e edgar_igl
/* ETRAX-FS Ethernet MAC block starts here.  */
310 2e56350e edgar_igl
311 9fc7577a Grant Likely
#define RW_MA0_LO      0x00
312 9fc7577a Grant Likely
#define RW_MA0_HI      0x01
313 9fc7577a Grant Likely
#define RW_MA1_LO      0x02
314 9fc7577a Grant Likely
#define RW_MA1_HI      0x03
315 9fc7577a Grant Likely
#define RW_GA_LO      0x04
316 9fc7577a Grant Likely
#define RW_GA_HI      0x05
317 9fc7577a Grant Likely
#define RW_GEN_CTRL      0x06
318 9fc7577a Grant Likely
#define RW_REC_CTRL      0x07
319 9fc7577a Grant Likely
#define RW_TR_CTRL      0x08
320 9fc7577a Grant Likely
#define RW_CLR_ERR      0x09
321 9fc7577a Grant Likely
#define RW_MGM_CTRL      0x0a
322 9fc7577a Grant Likely
#define R_STAT          0x0b
323 9fc7577a Grant Likely
#define FS_ETH_MAX_REGS      0x17
324 a3ea5df5 edgar_igl
325 8784dfa4 Andreas Färber
#define TYPE_ETRAX_FS_ETH "etraxfs-eth"
326 8784dfa4 Andreas Färber
#define ETRAX_FS_ETH(obj) \
327 58076497 Andreas Färber
    OBJECT_CHECK(ETRAXFSEthState, (obj), TYPE_ETRAX_FS_ETH)
328 8784dfa4 Andreas Färber
329 58076497 Andreas Färber
typedef struct ETRAXFSEthState
330 a3ea5df5 edgar_igl
{
331 8784dfa4 Andreas Färber
    SysBusDevice parent_obj;
332 8784dfa4 Andreas Färber
333 9fc7577a Grant Likely
    MemoryRegion mmio;
334 9fc7577a Grant Likely
    NICState *nic;
335 9fc7577a Grant Likely
    NICConf conf;
336 9fc7577a Grant Likely
337 9fc7577a Grant Likely
    /* Two addrs in the filter.  */
338 9fc7577a Grant Likely
    uint8_t macaddr[2][6];
339 9fc7577a Grant Likely
    uint32_t regs[FS_ETH_MAX_REGS];
340 9fc7577a Grant Likely
341 9fc7577a Grant Likely
    union {
342 9fc7577a Grant Likely
        void *vdma_out;
343 9fc7577a Grant Likely
        struct etraxfs_dma_client *dma_out;
344 9fc7577a Grant Likely
    };
345 9fc7577a Grant Likely
    union {
346 9fc7577a Grant Likely
        void *vdma_in;
347 9fc7577a Grant Likely
        struct etraxfs_dma_client *dma_in;
348 9fc7577a Grant Likely
    };
349 9fc7577a Grant Likely
350 9fc7577a Grant Likely
    /* MDIO bus.  */
351 9fc7577a Grant Likely
    struct qemu_mdio mdio_bus;
352 9fc7577a Grant Likely
    unsigned int phyaddr;
353 9fc7577a Grant Likely
    int duplex_mismatch;
354 9fc7577a Grant Likely
355 9fc7577a Grant Likely
    /* PHY.     */
356 9fc7577a Grant Likely
    struct qemu_phy phy;
357 58076497 Andreas Färber
} ETRAXFSEthState;
358 a3ea5df5 edgar_igl
359 58076497 Andreas Färber
static void eth_validate_duplex(ETRAXFSEthState *eth)
360 c6488268 edgar_igl
{
361 9fc7577a Grant Likely
    struct qemu_phy *phy;
362 9fc7577a Grant Likely
    unsigned int phy_duplex;
363 9fc7577a Grant Likely
    unsigned int mac_duplex;
364 9fc7577a Grant Likely
    int new_mm = 0;
365 9fc7577a Grant Likely
366 9fc7577a Grant Likely
    phy = eth->mdio_bus.devs[eth->phyaddr];
367 9fc7577a Grant Likely
    phy_duplex = !!(phy->read(phy, 18) & (1 << 11));
368 9fc7577a Grant Likely
    mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128);
369 9fc7577a Grant Likely
370 9fc7577a Grant Likely
    if (mac_duplex != phy_duplex) {
371 9fc7577a Grant Likely
        new_mm = 1;
372 9fc7577a Grant Likely
    }
373 9fc7577a Grant Likely
374 9fc7577a Grant Likely
    if (eth->regs[RW_GEN_CTRL] & 1) {
375 9fc7577a Grant Likely
        if (new_mm != eth->duplex_mismatch) {
376 9fc7577a Grant Likely
            if (new_mm) {
377 9fc7577a Grant Likely
                printf("HW: WARNING ETH duplex mismatch MAC=%d PHY=%d\n",
378 9fc7577a Grant Likely
                       mac_duplex, phy_duplex);
379 9fc7577a Grant Likely
            } else {
380 9fc7577a Grant Likely
                printf("HW: ETH duplex ok.\n");
381 9fc7577a Grant Likely
            }
382 9fc7577a Grant Likely
        }
383 9fc7577a Grant Likely
        eth->duplex_mismatch = new_mm;
384 9fc7577a Grant Likely
    }
385 c6488268 edgar_igl
}
386 c6488268 edgar_igl
387 06dccb82 Edgar E. Iglesias
static uint64_t
388 a8170e5e Avi Kivity
eth_read(void *opaque, hwaddr addr, unsigned int size)
389 a3ea5df5 edgar_igl
{
390 58076497 Andreas Färber
    ETRAXFSEthState *eth = opaque;
391 9fc7577a Grant Likely
    uint32_t r = 0;
392 9fc7577a Grant Likely
393 9fc7577a Grant Likely
    addr >>= 2;
394 9fc7577a Grant Likely
395 9fc7577a Grant Likely
    switch (addr) {
396 9fc7577a Grant Likely
    case R_STAT:
397 9fc7577a Grant Likely
        r = eth->mdio_bus.mdio & 1;
398 9fc7577a Grant Likely
        break;
399 9fc7577a Grant Likely
    default:
400 9fc7577a Grant Likely
        r = eth->regs[addr];
401 9fc7577a Grant Likely
        D(printf("%s %x\n", __func__, addr * 4));
402 9fc7577a Grant Likely
        break;
403 9fc7577a Grant Likely
    }
404 9fc7577a Grant Likely
    return r;
405 a3ea5df5 edgar_igl
}
406 a3ea5df5 edgar_igl
407 58076497 Andreas Färber
static void eth_update_ma(ETRAXFSEthState *eth, int ma)
408 f6953f13 edgar_igl
{
409 9fc7577a Grant Likely
    int reg;
410 9fc7577a Grant Likely
    int i = 0;
411 9fc7577a Grant Likely
412 9fc7577a Grant Likely
    ma &= 1;
413 9fc7577a Grant Likely
414 9fc7577a Grant Likely
    reg = RW_MA0_LO;
415 9fc7577a Grant Likely
    if (ma) {
416 9fc7577a Grant Likely
        reg = RW_MA1_LO;
417 9fc7577a Grant Likely
    }
418 9fc7577a Grant Likely
419 9fc7577a Grant Likely
    eth->macaddr[ma][i++] = eth->regs[reg];
420 9fc7577a Grant Likely
    eth->macaddr[ma][i++] = eth->regs[reg] >> 8;
421 9fc7577a Grant Likely
    eth->macaddr[ma][i++] = eth->regs[reg] >> 16;
422 9fc7577a Grant Likely
    eth->macaddr[ma][i++] = eth->regs[reg] >> 24;
423 9fc7577a Grant Likely
    eth->macaddr[ma][i++] = eth->regs[reg + 1];
424 9fc7577a Grant Likely
    eth->macaddr[ma][i] = eth->regs[reg + 1] >> 8;
425 9fc7577a Grant Likely
426 9fc7577a Grant Likely
    D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma,
427 9fc7577a Grant Likely
             eth->macaddr[ma][0], eth->macaddr[ma][1],
428 9fc7577a Grant Likely
             eth->macaddr[ma][2], eth->macaddr[ma][3],
429 9fc7577a Grant Likely
             eth->macaddr[ma][4], eth->macaddr[ma][5]));
430 a3ea5df5 edgar_igl
}
431 a3ea5df5 edgar_igl
432 a3ea5df5 edgar_igl
static void
433 a8170e5e Avi Kivity
eth_write(void *opaque, hwaddr addr,
434 06dccb82 Edgar E. Iglesias
          uint64_t val64, unsigned int size)
435 a3ea5df5 edgar_igl
{
436 58076497 Andreas Färber
    ETRAXFSEthState *eth = opaque;
437 9fc7577a Grant Likely
    uint32_t value = val64;
438 9fc7577a Grant Likely
439 9fc7577a Grant Likely
    addr >>= 2;
440 9fc7577a Grant Likely
    switch (addr) {
441 9fc7577a Grant Likely
    case RW_MA0_LO:
442 9fc7577a Grant Likely
    case RW_MA0_HI:
443 9fc7577a Grant Likely
        eth->regs[addr] = value;
444 9fc7577a Grant Likely
        eth_update_ma(eth, 0);
445 9fc7577a Grant Likely
        break;
446 9fc7577a Grant Likely
    case RW_MA1_LO:
447 9fc7577a Grant Likely
    case RW_MA1_HI:
448 9fc7577a Grant Likely
        eth->regs[addr] = value;
449 9fc7577a Grant Likely
        eth_update_ma(eth, 1);
450 9fc7577a Grant Likely
        break;
451 9fc7577a Grant Likely
452 9fc7577a Grant Likely
    case RW_MGM_CTRL:
453 9fc7577a Grant Likely
        /* Attach an MDIO/PHY abstraction.  */
454 9fc7577a Grant Likely
        if (value & 2) {
455 9fc7577a Grant Likely
            eth->mdio_bus.mdio = value & 1;
456 9fc7577a Grant Likely
        }
457 9fc7577a Grant Likely
        if (eth->mdio_bus.mdc != (value & 4)) {
458 9fc7577a Grant Likely
            mdio_cycle(&eth->mdio_bus);
459 9fc7577a Grant Likely
            eth_validate_duplex(eth);
460 9fc7577a Grant Likely
        }
461 9fc7577a Grant Likely
        eth->mdio_bus.mdc = !!(value & 4);
462 9fc7577a Grant Likely
        eth->regs[addr] = value;
463 9fc7577a Grant Likely
        break;
464 9fc7577a Grant Likely
465 9fc7577a Grant Likely
    case RW_REC_CTRL:
466 9fc7577a Grant Likely
        eth->regs[addr] = value;
467 9fc7577a Grant Likely
        eth_validate_duplex(eth);
468 9fc7577a Grant Likely
        break;
469 9fc7577a Grant Likely
470 9fc7577a Grant Likely
    default:
471 9fc7577a Grant Likely
        eth->regs[addr] = value;
472 9fc7577a Grant Likely
        D(printf("%s %x %x\n", __func__, addr, value));
473 9fc7577a Grant Likely
        break;
474 9fc7577a Grant Likely
    }
475 f6953f13 edgar_igl
}
476 f6953f13 edgar_igl
477 f6953f13 edgar_igl
/* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom
478 9fc7577a Grant Likely
   filter dropping group addresses we have not joined.    The filter has 64
479 9fc7577a Grant Likely
   bits (m). The has function is a simple nible xor of the group addr.    */
480 58076497 Andreas Färber
static int eth_match_groupaddr(ETRAXFSEthState *eth, const unsigned char *sa)
481 f6953f13 edgar_igl
{
482 9fc7577a Grant Likely
    unsigned int hsh;
483 9fc7577a Grant Likely
    int m_individual = eth->regs[RW_REC_CTRL] & 4;
484 9fc7577a Grant Likely
    int match;
485 9fc7577a Grant Likely
486 9fc7577a Grant Likely
    /* First bit on the wire of a MAC address signals multicast or
487 9fc7577a Grant Likely
       physical address.  */
488 9fc7577a Grant Likely
    if (!m_individual && !(sa[0] & 1)) {
489 9fc7577a Grant Likely
        return 0;
490 9fc7577a Grant Likely
    }
491 9fc7577a Grant Likely
492 9fc7577a Grant Likely
    /* Calculate the hash index for the GA registers. */
493 9fc7577a Grant Likely
    hsh = 0;
494 9fc7577a Grant Likely
    hsh ^= (*sa) & 0x3f;
495 9fc7577a Grant Likely
    hsh ^= ((*sa) >> 6) & 0x03;
496 9fc7577a Grant Likely
    ++sa;
497 9fc7577a Grant Likely
    hsh ^= ((*sa) << 2) & 0x03c;
498 9fc7577a Grant Likely
    hsh ^= ((*sa) >> 4) & 0xf;
499 9fc7577a Grant Likely
    ++sa;
500 9fc7577a Grant Likely
    hsh ^= ((*sa) << 4) & 0x30;
501 9fc7577a Grant Likely
    hsh ^= ((*sa) >> 2) & 0x3f;
502 9fc7577a Grant Likely
    ++sa;
503 9fc7577a Grant Likely
    hsh ^= (*sa) & 0x3f;
504 9fc7577a Grant Likely
    hsh ^= ((*sa) >> 6) & 0x03;
505 9fc7577a Grant Likely
    ++sa;
506 9fc7577a Grant Likely
    hsh ^= ((*sa) << 2) & 0x03c;
507 9fc7577a Grant Likely
    hsh ^= ((*sa) >> 4) & 0xf;
508 9fc7577a Grant Likely
    ++sa;
509 9fc7577a Grant Likely
    hsh ^= ((*sa) << 4) & 0x30;
510 9fc7577a Grant Likely
    hsh ^= ((*sa) >> 2) & 0x3f;
511 9fc7577a Grant Likely
512 9fc7577a Grant Likely
    hsh &= 63;
513 9fc7577a Grant Likely
    if (hsh > 31) {
514 9fc7577a Grant Likely
        match = eth->regs[RW_GA_HI] & (1 << (hsh - 32));
515 9fc7577a Grant Likely
    } else {
516 9fc7577a Grant Likely
        match = eth->regs[RW_GA_LO] & (1 << hsh);
517 9fc7577a Grant Likely
    }
518 9fc7577a Grant Likely
    D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh,
519 9fc7577a Grant Likely
             eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match));
520 9fc7577a Grant Likely
    return match;
521 a3ea5df5 edgar_igl
}
522 a3ea5df5 edgar_igl
523 4e68f7a0 Stefan Hajnoczi
static int eth_can_receive(NetClientState *nc)
524 a3ea5df5 edgar_igl
{
525 9fc7577a Grant Likely
    return 1;
526 a3ea5df5 edgar_igl
}
527 a3ea5df5 edgar_igl
528 4e68f7a0 Stefan Hajnoczi
static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size)
529 a3ea5df5 edgar_igl
{
530 9fc7577a Grant Likely
    unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
531 58076497 Andreas Färber
    ETRAXFSEthState *eth = qemu_get_nic_opaque(nc);
532 9fc7577a Grant Likely
    int use_ma0 = eth->regs[RW_REC_CTRL] & 1;
533 9fc7577a Grant Likely
    int use_ma1 = eth->regs[RW_REC_CTRL] & 2;
534 9fc7577a Grant Likely
    int r_bcast = eth->regs[RW_REC_CTRL] & 8;
535 9fc7577a Grant Likely
536 9fc7577a Grant Likely
    if (size < 12) {
537 9fc7577a Grant Likely
        return -1;
538 9fc7577a Grant Likely
    }
539 9fc7577a Grant Likely
540 9fc7577a Grant Likely
    D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n",
541 9fc7577a Grant Likely
         buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
542 9fc7577a Grant Likely
         use_ma0, use_ma1, r_bcast));
543 9fc7577a Grant Likely
544 9fc7577a Grant Likely
    /* Does the frame get through the address filters?  */
545 9fc7577a Grant Likely
    if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6))
546 9fc7577a Grant Likely
        && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6))
547 9fc7577a Grant Likely
        && (!r_bcast || memcmp(buf, sa_bcast, 6))
548 9fc7577a Grant Likely
        && !eth_match_groupaddr(eth, buf)) {
549 9fc7577a Grant Likely
        return size;
550 9fc7577a Grant Likely
    }
551 9fc7577a Grant Likely
552 9fc7577a Grant Likely
    /* FIXME: Find another way to pass on the fake csum.  */
553 9fc7577a Grant Likely
    etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1);
554 4f1c942b Mark McLoughlin
555 58076497 Andreas Färber
    return size;
556 a3ea5df5 edgar_igl
}
557 a3ea5df5 edgar_igl
558 73a511de Lars Persson
static int eth_tx_push(void *opaque, unsigned char *buf, int len, bool eop)
559 a3ea5df5 edgar_igl
{
560 58076497 Andreas Färber
    ETRAXFSEthState *eth = opaque;
561 a3ea5df5 edgar_igl
562 9fc7577a Grant Likely
    D(printf("%s buf=%p len=%d\n", __func__, buf, len));
563 b356f76d Jason Wang
    qemu_send_packet(qemu_get_queue(eth->nic), buf, len);
564 9fc7577a Grant Likely
    return len;
565 a3ea5df5 edgar_igl
}
566 a3ea5df5 edgar_igl
567 4e68f7a0 Stefan Hajnoczi
static void eth_set_link(NetClientState *nc)
568 94410b78 edgar_igl
{
569 58076497 Andreas Färber
    ETRAXFSEthState *eth = qemu_get_nic_opaque(nc);
570 9fc7577a Grant Likely
    D(printf("%s %d\n", __func__, nc->link_down));
571 9fc7577a Grant Likely
    eth->phy.link = !nc->link_down;
572 94410b78 edgar_igl
}
573 94410b78 edgar_igl
574 06dccb82 Edgar E. Iglesias
static const MemoryRegionOps eth_ops = {
575 9fc7577a Grant Likely
    .read = eth_read,
576 9fc7577a Grant Likely
    .write = eth_write,
577 9fc7577a Grant Likely
    .endianness = DEVICE_LITTLE_ENDIAN,
578 9fc7577a Grant Likely
    .valid = {
579 9fc7577a Grant Likely
        .min_access_size = 4,
580 9fc7577a Grant Likely
        .max_access_size = 4
581 9fc7577a Grant Likely
    }
582 a3ea5df5 edgar_igl
};
583 a3ea5df5 edgar_igl
584 4e68f7a0 Stefan Hajnoczi
static void eth_cleanup(NetClientState *nc)
585 b946a153 aliguori
{
586 58076497 Andreas Färber
    ETRAXFSEthState *eth = qemu_get_nic_opaque(nc);
587 b946a153 aliguori
588 9fc7577a Grant Likely
    /* Disconnect the client.  */
589 9fc7577a Grant Likely
    eth->dma_out->client.push = NULL;
590 9fc7577a Grant Likely
    eth->dma_out->client.opaque = NULL;
591 9fc7577a Grant Likely
    eth->dma_in->client.opaque = NULL;
592 9fc7577a Grant Likely
    eth->dma_in->client.pull = NULL;
593 7267c094 Anthony Liguori
        g_free(eth);
594 b946a153 aliguori
}
595 b946a153 aliguori
596 163bf3a5 Mark McLoughlin
static NetClientInfo net_etraxfs_info = {
597 9fc7577a Grant Likely
    .type = NET_CLIENT_OPTIONS_KIND_NIC,
598 9fc7577a Grant Likely
    .size = sizeof(NICState),
599 9fc7577a Grant Likely
    .can_receive = eth_can_receive,
600 9fc7577a Grant Likely
    .receive = eth_receive,
601 9fc7577a Grant Likely
    .cleanup = eth_cleanup,
602 9fc7577a Grant Likely
    .link_status_changed = eth_set_link,
603 163bf3a5 Mark McLoughlin
};
604 163bf3a5 Mark McLoughlin
605 8784dfa4 Andreas Färber
static int fs_eth_init(SysBusDevice *sbd)
606 a3ea5df5 edgar_igl
{
607 8784dfa4 Andreas Färber
    DeviceState *dev = DEVICE(sbd);
608 58076497 Andreas Färber
    ETRAXFSEthState *s = ETRAX_FS_ETH(dev);
609 a3ea5df5 edgar_igl
610 9fc7577a Grant Likely
    if (!s->dma_out || !s->dma_in) {
611 9fc7577a Grant Likely
        hw_error("Unconnected ETRAX-FS Ethernet MAC.\n");
612 9fc7577a Grant Likely
    }
613 a3ea5df5 edgar_igl
614 9fc7577a Grant Likely
    s->dma_out->client.push = eth_tx_push;
615 9fc7577a Grant Likely
    s->dma_out->client.opaque = s;
616 9fc7577a Grant Likely
    s->dma_in->client.opaque = s;
617 9fc7577a Grant Likely
    s->dma_in->client.pull = NULL;
618 a3ea5df5 edgar_igl
619 eedfac6f Paolo Bonzini
    memory_region_init_io(&s->mmio, OBJECT(dev), &eth_ops, s,
620 eedfac6f Paolo Bonzini
                          "etraxfs-eth", 0x5c);
621 8784dfa4 Andreas Färber
    sysbus_init_mmio(sbd, &s->mmio);
622 a3ea5df5 edgar_igl
623 9fc7577a Grant Likely
    qemu_macaddr_default_if_unset(&s->conf.macaddr);
624 9fc7577a Grant Likely
    s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf,
625 8784dfa4 Andreas Färber
                          object_get_typename(OBJECT(s)), dev->id, s);
626 b356f76d Jason Wang
    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
627 b356f76d Jason Wang
628 a3ea5df5 edgar_igl
629 9fc7577a Grant Likely
    tdk_init(&s->phy);
630 9fc7577a Grant Likely
    mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr);
631 9fc7577a Grant Likely
    return 0;
632 d949396e Edgar E. Iglesias
}
633 a3ea5df5 edgar_igl
634 999e12bb Anthony Liguori
static Property etraxfs_eth_properties[] = {
635 58076497 Andreas Färber
    DEFINE_PROP_UINT32("phyaddr", ETRAXFSEthState, phyaddr, 1),
636 58076497 Andreas Färber
    DEFINE_PROP_PTR("dma_out", ETRAXFSEthState, vdma_out),
637 58076497 Andreas Färber
    DEFINE_PROP_PTR("dma_in", ETRAXFSEthState, vdma_in),
638 58076497 Andreas Färber
    DEFINE_NIC_PROPERTIES(ETRAXFSEthState, conf),
639 999e12bb Anthony Liguori
    DEFINE_PROP_END_OF_LIST(),
640 999e12bb Anthony Liguori
};
641 999e12bb Anthony Liguori
642 999e12bb Anthony Liguori
static void etraxfs_eth_class_init(ObjectClass *klass, void *data)
643 999e12bb Anthony Liguori
{
644 39bffca2 Anthony Liguori
    DeviceClass *dc = DEVICE_CLASS(klass);
645 999e12bb Anthony Liguori
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
646 999e12bb Anthony Liguori
647 999e12bb Anthony Liguori
    k->init = fs_eth_init;
648 39bffca2 Anthony Liguori
    dc->props = etraxfs_eth_properties;
649 1b111dc1 Markus Armbruster
    /* Reason: pointer properties "dma_out", "dma_in" */
650 1b111dc1 Markus Armbruster
    dc->cannot_instantiate_with_device_add_yet = true;
651 999e12bb Anthony Liguori
}
652 999e12bb Anthony Liguori
653 8c43a6f0 Andreas Färber
static const TypeInfo etraxfs_eth_info = {
654 8784dfa4 Andreas Färber
    .name          = TYPE_ETRAX_FS_ETH,
655 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
656 58076497 Andreas Färber
    .instance_size = sizeof(ETRAXFSEthState),
657 39bffca2 Anthony Liguori
    .class_init    = etraxfs_eth_class_init,
658 d949396e Edgar E. Iglesias
};
659 163bf3a5 Mark McLoughlin
660 83f7d43a Andreas Färber
static void etraxfs_eth_register_types(void)
661 d949396e Edgar E. Iglesias
{
662 39bffca2 Anthony Liguori
    type_register_static(&etraxfs_eth_info);
663 a3ea5df5 edgar_igl
}
664 d949396e Edgar E. Iglesias
665 83f7d43a Andreas Färber
type_init(etraxfs_eth_register_types)