Statistics
| Branch: | Revision:

root / hw / etraxfs_eth.c @ 818220f5

History | View | Annotate | Download (14.3 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 a3ea5df5 edgar_igl
#include "hw.h"
27 a3ea5df5 edgar_igl
#include "net.h"
28 a3ea5df5 edgar_igl
29 a3ea5df5 edgar_igl
#include "etraxfs_dma.h"
30 a3ea5df5 edgar_igl
31 a3ea5df5 edgar_igl
#define D(x)
32 a3ea5df5 edgar_igl
33 c6488268 edgar_igl
/* Advertisement control register. */
34 c6488268 edgar_igl
#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
35 c6488268 edgar_igl
#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
36 c6488268 edgar_igl
#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
37 c6488268 edgar_igl
#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
38 c6488268 edgar_igl
39 2e56350e edgar_igl
/* 
40 2e56350e edgar_igl
 * The MDIO extensions in the TDK PHY model were reversed engineered from the 
41 2e56350e edgar_igl
 * linux driver (PHYID and Diagnostics reg).
42 2e56350e edgar_igl
 * TODO: Add friendly names for the register nums.
43 2e56350e edgar_igl
 */
44 a3ea5df5 edgar_igl
struct qemu_phy
45 a3ea5df5 edgar_igl
{
46 a3ea5df5 edgar_igl
        uint32_t regs[32];
47 a3ea5df5 edgar_igl
48 a3ea5df5 edgar_igl
        unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
49 2e56350e edgar_igl
        void (*write)(struct qemu_phy *phy, unsigned int req, 
50 2e56350e edgar_igl
                      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 a3ea5df5 edgar_igl
        int regnum;
56 a3ea5df5 edgar_igl
        unsigned r = 0;
57 a3ea5df5 edgar_igl
58 a3ea5df5 edgar_igl
        regnum = req & 0x1f;
59 a3ea5df5 edgar_igl
60 a3ea5df5 edgar_igl
        switch (regnum) {
61 a3ea5df5 edgar_igl
                case 1:
62 f6953f13 edgar_igl
                        /* MR1.         */
63 a3ea5df5 edgar_igl
                        /* Speeds and modes.  */
64 a3ea5df5 edgar_igl
                        r |= (1 << 13) | (1 << 14);
65 a3ea5df5 edgar_igl
                        r |= (1 << 11) | (1 << 12);
66 a3ea5df5 edgar_igl
                        r |= (1 << 5); /* Autoneg complete.  */
67 f6953f13 edgar_igl
                        r |= (1 << 3); /* Autoneg able.         */
68 f6953f13 edgar_igl
                        r |= (1 << 2); /* Link.         */
69 a3ea5df5 edgar_igl
                        break;
70 2e56350e edgar_igl
                case 5:
71 2e56350e edgar_igl
                        /* Link partner ability.
72 2e56350e edgar_igl
                           We are kind; always agree with whatever best mode
73 2e56350e edgar_igl
                           the guest advertises.  */
74 2e56350e edgar_igl
                        r = 1 << 14; /* Success.  */
75 2e56350e edgar_igl
                        /* Copy advertised modes.  */
76 2e56350e edgar_igl
                        r |= phy->regs[4] & (15 << 5);
77 2e56350e edgar_igl
                        /* Autoneg support.  */
78 2e56350e edgar_igl
                        r |= 1;
79 2e56350e edgar_igl
                        break;
80 2e56350e edgar_igl
                case 18:
81 2e56350e edgar_igl
                {
82 2e56350e edgar_igl
                        /* Diagnostics reg.  */
83 2e56350e edgar_igl
                        int duplex = 0;
84 2e56350e edgar_igl
                        int speed_100 = 0;
85 2e56350e edgar_igl
86 2e56350e edgar_igl
                        /* Are we advertising 100 half or 100 duplex ? */
87 c6488268 edgar_igl
                        speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
88 c6488268 edgar_igl
                        speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
89 c6488268 edgar_igl
90 2e56350e edgar_igl
                        /* Are we advertising 10 duplex or 100 duplex ? */
91 c6488268 edgar_igl
                        duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
92 c6488268 edgar_igl
                        duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
93 2e56350e edgar_igl
                        r = (speed_100 << 10) | (duplex << 11);
94 2e56350e edgar_igl
                }
95 2e56350e edgar_igl
                break;
96 2e56350e edgar_igl
97 a3ea5df5 edgar_igl
                default:
98 a3ea5df5 edgar_igl
                        r = phy->regs[regnum];
99 a3ea5df5 edgar_igl
                        break;
100 a3ea5df5 edgar_igl
        }
101 2e56350e edgar_igl
        D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum));
102 a3ea5df5 edgar_igl
        return r;
103 a3ea5df5 edgar_igl
}
104 a3ea5df5 edgar_igl
105 a3ea5df5 edgar_igl
static void 
106 a3ea5df5 edgar_igl
tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
107 a3ea5df5 edgar_igl
{
108 a3ea5df5 edgar_igl
        int regnum;
109 a3ea5df5 edgar_igl
110 a3ea5df5 edgar_igl
        regnum = req & 0x1f;
111 a3ea5df5 edgar_igl
        D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
112 a3ea5df5 edgar_igl
        switch (regnum) {
113 a3ea5df5 edgar_igl
                default:
114 a3ea5df5 edgar_igl
                        phy->regs[regnum] = data;
115 a3ea5df5 edgar_igl
                        break;
116 a3ea5df5 edgar_igl
        }
117 a3ea5df5 edgar_igl
}
118 a3ea5df5 edgar_igl
119 a3ea5df5 edgar_igl
static void 
120 a3ea5df5 edgar_igl
tdk_init(struct qemu_phy *phy)
121 a3ea5df5 edgar_igl
{
122 2e56350e edgar_igl
        phy->regs[0] = 0x3100;
123 2e56350e edgar_igl
        /* PHY Id.  */
124 2e56350e edgar_igl
        phy->regs[2] = 0x0300;
125 2e56350e edgar_igl
        phy->regs[3] = 0xe400;
126 2e56350e edgar_igl
        /* Autonegotiation advertisement reg.  */
127 2e56350e edgar_igl
        phy->regs[4] = 0x01E1;
128 2e56350e edgar_igl
129 a3ea5df5 edgar_igl
        phy->read = tdk_read;
130 a3ea5df5 edgar_igl
        phy->write = tdk_write;
131 a3ea5df5 edgar_igl
}
132 a3ea5df5 edgar_igl
133 a3ea5df5 edgar_igl
struct qemu_mdio
134 a3ea5df5 edgar_igl
{
135 f6953f13 edgar_igl
        /* bus.         */
136 a3ea5df5 edgar_igl
        int mdc;
137 a3ea5df5 edgar_igl
        int mdio;
138 a3ea5df5 edgar_igl
139 a3ea5df5 edgar_igl
        /* decoder.  */
140 a3ea5df5 edgar_igl
        enum {
141 a3ea5df5 edgar_igl
                PREAMBLE,
142 a3ea5df5 edgar_igl
                SOF,
143 a3ea5df5 edgar_igl
                OPC,
144 a3ea5df5 edgar_igl
                ADDR,
145 a3ea5df5 edgar_igl
                REQ,
146 a3ea5df5 edgar_igl
                TURNAROUND,
147 a3ea5df5 edgar_igl
                DATA
148 a3ea5df5 edgar_igl
        } state;
149 a3ea5df5 edgar_igl
        unsigned int drive;
150 a3ea5df5 edgar_igl
151 a3ea5df5 edgar_igl
        unsigned int cnt;
152 a3ea5df5 edgar_igl
        unsigned int addr;
153 a3ea5df5 edgar_igl
        unsigned int opc;
154 a3ea5df5 edgar_igl
        unsigned int req;
155 a3ea5df5 edgar_igl
        unsigned int data;
156 a3ea5df5 edgar_igl
157 a3ea5df5 edgar_igl
        struct qemu_phy *devs[32];
158 a3ea5df5 edgar_igl
};
159 a3ea5df5 edgar_igl
160 a3ea5df5 edgar_igl
static void 
161 a3ea5df5 edgar_igl
mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
162 a3ea5df5 edgar_igl
{
163 a3ea5df5 edgar_igl
        bus->devs[addr & 0x1f] = phy;
164 a3ea5df5 edgar_igl
}
165 a3ea5df5 edgar_igl
166 d297f464 edgar_igl
#ifdef USE_THIS_DEAD_CODE
167 a3ea5df5 edgar_igl
static void 
168 a3ea5df5 edgar_igl
mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
169 a3ea5df5 edgar_igl
{
170 a3ea5df5 edgar_igl
        bus->devs[addr & 0x1f] = NULL;        
171 a3ea5df5 edgar_igl
}
172 d297f464 edgar_igl
#endif
173 a3ea5df5 edgar_igl
174 a3ea5df5 edgar_igl
static void mdio_read_req(struct qemu_mdio *bus)
175 a3ea5df5 edgar_igl
{
176 a3ea5df5 edgar_igl
        struct qemu_phy *phy;
177 a3ea5df5 edgar_igl
178 a3ea5df5 edgar_igl
        phy = bus->devs[bus->addr];
179 a3ea5df5 edgar_igl
        if (phy && phy->read)
180 a3ea5df5 edgar_igl
                bus->data = phy->read(phy, bus->req);
181 a3ea5df5 edgar_igl
        else 
182 a3ea5df5 edgar_igl
                bus->data = 0xffff;
183 a3ea5df5 edgar_igl
}
184 a3ea5df5 edgar_igl
185 a3ea5df5 edgar_igl
static void mdio_write_req(struct qemu_mdio *bus)
186 a3ea5df5 edgar_igl
{
187 a3ea5df5 edgar_igl
        struct qemu_phy *phy;
188 a3ea5df5 edgar_igl
189 a3ea5df5 edgar_igl
        phy = bus->devs[bus->addr];
190 a3ea5df5 edgar_igl
        if (phy && phy->write)
191 a3ea5df5 edgar_igl
                phy->write(phy, bus->req, bus->data);
192 a3ea5df5 edgar_igl
}
193 a3ea5df5 edgar_igl
194 a3ea5df5 edgar_igl
static void mdio_cycle(struct qemu_mdio *bus)
195 a3ea5df5 edgar_igl
{
196 a3ea5df5 edgar_igl
        bus->cnt++;
197 a3ea5df5 edgar_igl
198 a3ea5df5 edgar_igl
        D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n",
199 a3ea5df5 edgar_igl
                bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive));
200 a3ea5df5 edgar_igl
#if 0
201 a3ea5df5 edgar_igl
        if (bus->mdc)
202 a3ea5df5 edgar_igl
                printf("%d", bus->mdio);
203 a3ea5df5 edgar_igl
#endif
204 a3ea5df5 edgar_igl
        switch (bus->state)
205 a3ea5df5 edgar_igl
        {
206 a3ea5df5 edgar_igl
                case PREAMBLE:
207 a3ea5df5 edgar_igl
                        if (bus->mdc) {
208 a3ea5df5 edgar_igl
                                if (bus->cnt >= (32 * 2) && !bus->mdio) {
209 a3ea5df5 edgar_igl
                                        bus->cnt = 0;
210 a3ea5df5 edgar_igl
                                        bus->state = SOF;
211 a3ea5df5 edgar_igl
                                        bus->data = 0;
212 a3ea5df5 edgar_igl
                                }
213 a3ea5df5 edgar_igl
                        }
214 a3ea5df5 edgar_igl
                        break;
215 a3ea5df5 edgar_igl
                case SOF:
216 a3ea5df5 edgar_igl
                        if (bus->mdc) {
217 a3ea5df5 edgar_igl
                                if (bus->mdio != 1)
218 a3ea5df5 edgar_igl
                                        printf("WARNING: no SOF\n");
219 a3ea5df5 edgar_igl
                                if (bus->cnt == 1*2) {
220 a3ea5df5 edgar_igl
                                        bus->cnt = 0;
221 a3ea5df5 edgar_igl
                                        bus->opc = 0;
222 a3ea5df5 edgar_igl
                                        bus->state = OPC;
223 a3ea5df5 edgar_igl
                                }
224 a3ea5df5 edgar_igl
                        }
225 a3ea5df5 edgar_igl
                        break;
226 a3ea5df5 edgar_igl
                case OPC:
227 a3ea5df5 edgar_igl
                        if (bus->mdc) {
228 a3ea5df5 edgar_igl
                                bus->opc <<= 1;
229 a3ea5df5 edgar_igl
                                bus->opc |= bus->mdio & 1;
230 a3ea5df5 edgar_igl
                                if (bus->cnt == 2*2) {
231 a3ea5df5 edgar_igl
                                        bus->cnt = 0;
232 a3ea5df5 edgar_igl
                                        bus->addr = 0;
233 a3ea5df5 edgar_igl
                                        bus->state = ADDR;
234 a3ea5df5 edgar_igl
                                }
235 a3ea5df5 edgar_igl
                        }
236 a3ea5df5 edgar_igl
                        break;
237 a3ea5df5 edgar_igl
                case ADDR:
238 a3ea5df5 edgar_igl
                        if (bus->mdc) {
239 a3ea5df5 edgar_igl
                                bus->addr <<= 1;
240 a3ea5df5 edgar_igl
                                bus->addr |= bus->mdio & 1;
241 a3ea5df5 edgar_igl
242 a3ea5df5 edgar_igl
                                if (bus->cnt == 5*2) {
243 a3ea5df5 edgar_igl
                                        bus->cnt = 0;
244 a3ea5df5 edgar_igl
                                        bus->req = 0;
245 a3ea5df5 edgar_igl
                                        bus->state = REQ;
246 a3ea5df5 edgar_igl
                                }
247 a3ea5df5 edgar_igl
                        }
248 a3ea5df5 edgar_igl
                        break;
249 a3ea5df5 edgar_igl
                case REQ:
250 a3ea5df5 edgar_igl
                        if (bus->mdc) {
251 a3ea5df5 edgar_igl
                                bus->req <<= 1;
252 a3ea5df5 edgar_igl
                                bus->req |= bus->mdio & 1;
253 a3ea5df5 edgar_igl
                                if (bus->cnt == 5*2) {
254 a3ea5df5 edgar_igl
                                        bus->cnt = 0;
255 a3ea5df5 edgar_igl
                                        bus->state = TURNAROUND;
256 a3ea5df5 edgar_igl
                                }
257 a3ea5df5 edgar_igl
                        }
258 a3ea5df5 edgar_igl
                        break;
259 a3ea5df5 edgar_igl
                case TURNAROUND:
260 a3ea5df5 edgar_igl
                        if (bus->mdc && bus->cnt == 2*2) {
261 a3ea5df5 edgar_igl
                                bus->mdio = 0;
262 a3ea5df5 edgar_igl
                                bus->cnt = 0;
263 a3ea5df5 edgar_igl
264 a3ea5df5 edgar_igl
                                if (bus->opc == 2) {
265 a3ea5df5 edgar_igl
                                        bus->drive = 1;
266 a3ea5df5 edgar_igl
                                        mdio_read_req(bus);
267 a3ea5df5 edgar_igl
                                        bus->mdio = bus->data & 1;
268 a3ea5df5 edgar_igl
                                }
269 a3ea5df5 edgar_igl
                                bus->state = DATA;
270 a3ea5df5 edgar_igl
                        }
271 a3ea5df5 edgar_igl
                        break;
272 a3ea5df5 edgar_igl
                case DATA:                        
273 a3ea5df5 edgar_igl
                        if (!bus->mdc) {
274 a3ea5df5 edgar_igl
                                if (bus->drive) {
275 2e56350e edgar_igl
                                        bus->mdio = !!(bus->data & (1 << 15));
276 2e56350e edgar_igl
                                        bus->data <<= 1;
277 a3ea5df5 edgar_igl
                                }
278 a3ea5df5 edgar_igl
                        } else {
279 a3ea5df5 edgar_igl
                                if (!bus->drive) {
280 a3ea5df5 edgar_igl
                                        bus->data <<= 1;
281 a3ea5df5 edgar_igl
                                        bus->data |= bus->mdio;
282 a3ea5df5 edgar_igl
                                }
283 a3ea5df5 edgar_igl
                                if (bus->cnt == 16 * 2) {
284 a3ea5df5 edgar_igl
                                        bus->cnt = 0;
285 a3ea5df5 edgar_igl
                                        bus->state = PREAMBLE;
286 2e56350e edgar_igl
                                        if (!bus->drive)
287 2e56350e edgar_igl
                                                mdio_write_req(bus);
288 2e56350e edgar_igl
                                        bus->drive = 0;
289 a3ea5df5 edgar_igl
                                }
290 a3ea5df5 edgar_igl
                        }
291 a3ea5df5 edgar_igl
                        break;
292 a3ea5df5 edgar_igl
                default:
293 a3ea5df5 edgar_igl
                        break;
294 a3ea5df5 edgar_igl
        }
295 a3ea5df5 edgar_igl
}
296 a3ea5df5 edgar_igl
297 2e56350e edgar_igl
/* ETRAX-FS Ethernet MAC block starts here.  */
298 2e56350e edgar_igl
299 f6953f13 edgar_igl
#define RW_MA0_LO          0x00
300 f6953f13 edgar_igl
#define RW_MA0_HI          0x04
301 f6953f13 edgar_igl
#define RW_MA1_LO          0x08
302 f6953f13 edgar_igl
#define RW_MA1_HI          0x0c
303 f6953f13 edgar_igl
#define RW_GA_LO          0x10
304 f6953f13 edgar_igl
#define RW_GA_HI          0x14
305 f6953f13 edgar_igl
#define RW_GEN_CTRL          0x18
306 f6953f13 edgar_igl
#define RW_REC_CTRL          0x1c
307 f6953f13 edgar_igl
#define RW_TR_CTRL          0x20
308 f6953f13 edgar_igl
#define RW_CLR_ERR          0x24
309 f6953f13 edgar_igl
#define RW_MGM_CTRL          0x28
310 f6953f13 edgar_igl
#define R_STAT                  0x2c
311 f6953f13 edgar_igl
#define FS_ETH_MAX_REGS          0x5c
312 a3ea5df5 edgar_igl
313 a3ea5df5 edgar_igl
struct fs_eth
314 a3ea5df5 edgar_igl
{
315 f6953f13 edgar_igl
        CPUState *env;
316 a3ea5df5 edgar_igl
        qemu_irq *irq;
317 f6953f13 edgar_igl
        target_phys_addr_t base;
318 a3ea5df5 edgar_igl
        VLANClientState *vc;
319 a3ea5df5 edgar_igl
        int ethregs;
320 a3ea5df5 edgar_igl
321 f6953f13 edgar_igl
        /* Two addrs in the filter.  */
322 f6953f13 edgar_igl
        uint8_t macaddr[2][6];
323 a3ea5df5 edgar_igl
        uint32_t regs[FS_ETH_MAX_REGS];
324 a3ea5df5 edgar_igl
325 a3ea5df5 edgar_igl
        unsigned char rx_fifo[1536];
326 a3ea5df5 edgar_igl
        int rx_fifo_len;
327 a3ea5df5 edgar_igl
        int rx_fifo_pos;
328 a3ea5df5 edgar_igl
329 a3ea5df5 edgar_igl
        struct etraxfs_dma_client *dma_out;
330 a3ea5df5 edgar_igl
        struct etraxfs_dma_client *dma_in;
331 a3ea5df5 edgar_igl
332 a3ea5df5 edgar_igl
        /* MDIO bus.  */
333 a3ea5df5 edgar_igl
        struct qemu_mdio mdio_bus;
334 c6488268 edgar_igl
        unsigned int phyaddr;
335 c6488268 edgar_igl
        int duplex_mismatch;
336 c6488268 edgar_igl
337 f6953f13 edgar_igl
        /* PHY.         */
338 a3ea5df5 edgar_igl
        struct qemu_phy phy;
339 a3ea5df5 edgar_igl
};
340 a3ea5df5 edgar_igl
341 c6488268 edgar_igl
static void eth_validate_duplex(struct fs_eth *eth)
342 c6488268 edgar_igl
{
343 c6488268 edgar_igl
        struct qemu_phy *phy;
344 c6488268 edgar_igl
        unsigned int phy_duplex;
345 c6488268 edgar_igl
        unsigned int mac_duplex;
346 c6488268 edgar_igl
        int new_mm = 0;
347 c6488268 edgar_igl
348 c6488268 edgar_igl
        phy = eth->mdio_bus.devs[eth->phyaddr];
349 c6488268 edgar_igl
        phy_duplex = !!(phy->read(phy, 18) & (1 << 11));
350 c6488268 edgar_igl
        mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128);
351 c6488268 edgar_igl
352 c6488268 edgar_igl
        if (mac_duplex != phy_duplex)
353 c6488268 edgar_igl
                new_mm = 1;
354 c6488268 edgar_igl
355 c6488268 edgar_igl
        if (eth->regs[RW_GEN_CTRL] & 1) {
356 c6488268 edgar_igl
                if (new_mm != eth->duplex_mismatch) {
357 c6488268 edgar_igl
                        if (new_mm)
358 c6488268 edgar_igl
                                printf("HW: WARNING "
359 c6488268 edgar_igl
                                       "ETH duplex mismatch MAC=%d PHY=%d\n",
360 c6488268 edgar_igl
                                       mac_duplex, phy_duplex);
361 c6488268 edgar_igl
                        else
362 c6488268 edgar_igl
                                printf("HW: ETH duplex ok.\n");
363 c6488268 edgar_igl
                }
364 c6488268 edgar_igl
                eth->duplex_mismatch = new_mm;
365 c6488268 edgar_igl
        }
366 c6488268 edgar_igl
}
367 c6488268 edgar_igl
368 a3ea5df5 edgar_igl
static uint32_t eth_rinvalid (void *opaque, target_phys_addr_t addr)
369 a3ea5df5 edgar_igl
{
370 f6953f13 edgar_igl
        struct fs_eth *eth = opaque;
371 f6953f13 edgar_igl
        CPUState *env = eth->env;
372 d27b2e50 edgar_igl
        cpu_abort(env, "Unsupported short access. reg=" TARGET_FMT_plx "\n",
373 d27b2e50 edgar_igl
                  addr);
374 f6953f13 edgar_igl
        return 0;
375 a3ea5df5 edgar_igl
}
376 a3ea5df5 edgar_igl
377 a3ea5df5 edgar_igl
static uint32_t eth_readl (void *opaque, target_phys_addr_t addr)
378 a3ea5df5 edgar_igl
{
379 f6953f13 edgar_igl
        struct fs_eth *eth = opaque;
380 f6953f13 edgar_igl
        uint32_t r = 0;
381 a3ea5df5 edgar_igl
382 f6953f13 edgar_igl
        /* Make addr relative to this instances base.  */
383 f6953f13 edgar_igl
        addr -= eth->base;
384 f6953f13 edgar_igl
        switch (addr) {
385 a3ea5df5 edgar_igl
                case R_STAT:
386 a3ea5df5 edgar_igl
                        /* Attach an MDIO/PHY abstraction.  */
387 a3ea5df5 edgar_igl
                        r = eth->mdio_bus.mdio & 1;
388 a3ea5df5 edgar_igl
                        break;
389 f6953f13 edgar_igl
        default:
390 a3ea5df5 edgar_igl
                r = eth->regs[addr];
391 d27b2e50 edgar_igl
                D(printf ("%s %x\n", __func__, addr));
392 f6953f13 edgar_igl
                break;
393 f6953f13 edgar_igl
        }
394 f6953f13 edgar_igl
        return r;
395 a3ea5df5 edgar_igl
}
396 a3ea5df5 edgar_igl
397 a3ea5df5 edgar_igl
static void
398 a3ea5df5 edgar_igl
eth_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value)
399 a3ea5df5 edgar_igl
{
400 f6953f13 edgar_igl
        struct fs_eth *eth = opaque;
401 f6953f13 edgar_igl
        CPUState *env = eth->env;
402 d27b2e50 edgar_igl
        cpu_abort(env, "Unsupported short access. reg=" TARGET_FMT_plx "\n",
403 d27b2e50 edgar_igl
                  addr);
404 f6953f13 edgar_igl
}
405 f6953f13 edgar_igl
406 f6953f13 edgar_igl
static void eth_update_ma(struct fs_eth *eth, int ma)
407 f6953f13 edgar_igl
{
408 f6953f13 edgar_igl
        int reg;
409 f6953f13 edgar_igl
        int i = 0;
410 f6953f13 edgar_igl
411 f6953f13 edgar_igl
        ma &= 1;
412 f6953f13 edgar_igl
413 f6953f13 edgar_igl
        reg = RW_MA0_LO;
414 f6953f13 edgar_igl
        if (ma)
415 f6953f13 edgar_igl
                reg = RW_MA1_LO;
416 f6953f13 edgar_igl
417 f6953f13 edgar_igl
        eth->macaddr[ma][i++] = eth->regs[reg];
418 f6953f13 edgar_igl
        eth->macaddr[ma][i++] = eth->regs[reg] >> 8;
419 f6953f13 edgar_igl
        eth->macaddr[ma][i++] = eth->regs[reg] >> 16;
420 f6953f13 edgar_igl
        eth->macaddr[ma][i++] = eth->regs[reg] >> 24;
421 f6953f13 edgar_igl
        eth->macaddr[ma][i++] = eth->regs[reg + 4];
422 f6953f13 edgar_igl
        eth->macaddr[ma][i++] = eth->regs[reg + 4] >> 8;
423 f6953f13 edgar_igl
424 f6953f13 edgar_igl
        D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma,
425 f6953f13 edgar_igl
                 eth->macaddr[ma][0], eth->macaddr[ma][1],
426 f6953f13 edgar_igl
                 eth->macaddr[ma][2], eth->macaddr[ma][3],
427 f6953f13 edgar_igl
                 eth->macaddr[ma][4], eth->macaddr[ma][5]));
428 a3ea5df5 edgar_igl
}
429 a3ea5df5 edgar_igl
430 a3ea5df5 edgar_igl
static void
431 a3ea5df5 edgar_igl
eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
432 a3ea5df5 edgar_igl
{
433 f6953f13 edgar_igl
        struct fs_eth *eth = opaque;
434 f6953f13 edgar_igl
435 f6953f13 edgar_igl
        /* Make addr relative to this instances base.  */
436 f6953f13 edgar_igl
        addr -= eth->base;
437 f6953f13 edgar_igl
        switch (addr)
438 f6953f13 edgar_igl
        {
439 f6953f13 edgar_igl
                case RW_MA0_LO:
440 f6953f13 edgar_igl
                        eth->regs[addr] = value;
441 f6953f13 edgar_igl
                        eth_update_ma(eth, 0);
442 f6953f13 edgar_igl
                        break;
443 f6953f13 edgar_igl
                case RW_MA0_HI:
444 f6953f13 edgar_igl
                        eth->regs[addr] = value;
445 f6953f13 edgar_igl
                        eth_update_ma(eth, 0);
446 f6953f13 edgar_igl
                        break;
447 f6953f13 edgar_igl
                case RW_MA1_LO:
448 f6953f13 edgar_igl
                        eth->regs[addr] = value;
449 f6953f13 edgar_igl
                        eth_update_ma(eth, 1);
450 f6953f13 edgar_igl
                        break;
451 f6953f13 edgar_igl
                case RW_MA1_HI:
452 f6953f13 edgar_igl
                        eth->regs[addr] = value;
453 f6953f13 edgar_igl
                        eth_update_ma(eth, 1);
454 f6953f13 edgar_igl
                        break;
455 a3ea5df5 edgar_igl
456 a3ea5df5 edgar_igl
                case RW_MGM_CTRL:
457 a3ea5df5 edgar_igl
                        /* Attach an MDIO/PHY abstraction.  */
458 a3ea5df5 edgar_igl
                        if (value & 2)
459 a3ea5df5 edgar_igl
                                eth->mdio_bus.mdio = value & 1;
460 c6488268 edgar_igl
                        if (eth->mdio_bus.mdc != (value & 4)) {
461 a3ea5df5 edgar_igl
                                mdio_cycle(&eth->mdio_bus);
462 c6488268 edgar_igl
                                eth_validate_duplex(eth);
463 c6488268 edgar_igl
                        }
464 a3ea5df5 edgar_igl
                        eth->mdio_bus.mdc = !!(value & 4);
465 a3ea5df5 edgar_igl
                        break;
466 a3ea5df5 edgar_igl
467 c6488268 edgar_igl
                case RW_REC_CTRL:
468 c6488268 edgar_igl
                        eth->regs[addr] = value;
469 c6488268 edgar_igl
                        eth_validate_duplex(eth);
470 c6488268 edgar_igl
                        break;
471 c6488268 edgar_igl
472 f6953f13 edgar_igl
                default:
473 f6953f13 edgar_igl
                        eth->regs[addr] = value;
474 9bcd77d6 edgar_igl
                        D(printf ("%s %x %x\n",
475 9bcd77d6 edgar_igl
                                  __func__, addr, value));
476 f6953f13 edgar_igl
                        break;
477 f6953f13 edgar_igl
        }
478 f6953f13 edgar_igl
}
479 f6953f13 edgar_igl
480 f6953f13 edgar_igl
/* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom
481 f6953f13 edgar_igl
   filter dropping group addresses we have not joined.        The filter has 64
482 f6953f13 edgar_igl
   bits (m). The has function is a simple nible xor of the group addr.        */
483 f6953f13 edgar_igl
static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa)
484 f6953f13 edgar_igl
{
485 f6953f13 edgar_igl
        unsigned int hsh;
486 f6953f13 edgar_igl
        int m_individual = eth->regs[RW_REC_CTRL] & 4;
487 f6953f13 edgar_igl
        int match;
488 f6953f13 edgar_igl
489 f6953f13 edgar_igl
        /* First bit on the wire of a MAC address signals multicast or
490 f6953f13 edgar_igl
           physical address.  */
491 f6953f13 edgar_igl
        if (!m_individual && !sa[0] & 1)
492 f6953f13 edgar_igl
                return 0;
493 f6953f13 edgar_igl
494 f6953f13 edgar_igl
        /* Calculate the hash index for the GA registers. */
495 f6953f13 edgar_igl
        hsh = 0;
496 f6953f13 edgar_igl
        hsh ^= (*sa) & 0x3f;
497 f6953f13 edgar_igl
        hsh ^= ((*sa) >> 6) & 0x03;
498 f6953f13 edgar_igl
        ++sa;
499 f6953f13 edgar_igl
        hsh ^= ((*sa) << 2) & 0x03c;
500 f6953f13 edgar_igl
        hsh ^= ((*sa) >> 4) & 0xf;
501 f6953f13 edgar_igl
        ++sa;
502 f6953f13 edgar_igl
        hsh ^= ((*sa) << 4) & 0x30;
503 f6953f13 edgar_igl
        hsh ^= ((*sa) >> 2) & 0x3f;
504 f6953f13 edgar_igl
        ++sa;
505 f6953f13 edgar_igl
        hsh ^= (*sa) & 0x3f;
506 f6953f13 edgar_igl
        hsh ^= ((*sa) >> 6) & 0x03;
507 f6953f13 edgar_igl
        ++sa;
508 f6953f13 edgar_igl
        hsh ^= ((*sa) << 2) & 0x03c;
509 f6953f13 edgar_igl
        hsh ^= ((*sa) >> 4) & 0xf;
510 f6953f13 edgar_igl
        ++sa;
511 f6953f13 edgar_igl
        hsh ^= ((*sa) << 4) & 0x30;
512 f6953f13 edgar_igl
        hsh ^= ((*sa) >> 2) & 0x3f;
513 f6953f13 edgar_igl
514 f6953f13 edgar_igl
        hsh &= 63;
515 f6953f13 edgar_igl
        if (hsh > 31)
516 f6953f13 edgar_igl
                match = eth->regs[RW_GA_HI] & (1 << (hsh - 32));
517 f6953f13 edgar_igl
        else
518 f6953f13 edgar_igl
                match = eth->regs[RW_GA_LO] & (1 << hsh);
519 f6953f13 edgar_igl
        D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh,
520 f6953f13 edgar_igl
                 eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match));
521 f6953f13 edgar_igl
        return match;
522 a3ea5df5 edgar_igl
}
523 a3ea5df5 edgar_igl
524 a3ea5df5 edgar_igl
static int eth_can_receive(void *opaque)
525 a3ea5df5 edgar_igl
{
526 a3ea5df5 edgar_igl
        struct fs_eth *eth = opaque;
527 a3ea5df5 edgar_igl
        int r;
528 a3ea5df5 edgar_igl
529 a3ea5df5 edgar_igl
        r = eth->rx_fifo_len == 0;
530 a3ea5df5 edgar_igl
        if (!r) {
531 a3ea5df5 edgar_igl
                /* TODO: signal fifo overrun.  */
532 a3ea5df5 edgar_igl
                printf("PACKET LOSS!\n");
533 a3ea5df5 edgar_igl
        }
534 a3ea5df5 edgar_igl
        return r;
535 a3ea5df5 edgar_igl
}
536 a3ea5df5 edgar_igl
537 a3ea5df5 edgar_igl
static void eth_receive(void *opaque, const uint8_t *buf, int size)
538 a3ea5df5 edgar_igl
{
539 f6953f13 edgar_igl
        unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
540 a3ea5df5 edgar_igl
        struct fs_eth *eth = opaque;
541 f6953f13 edgar_igl
        int use_ma0 = eth->regs[RW_REC_CTRL] & 1;
542 f6953f13 edgar_igl
        int use_ma1 = eth->regs[RW_REC_CTRL] & 2;
543 f6953f13 edgar_igl
        int r_bcast = eth->regs[RW_REC_CTRL] & 8;
544 f6953f13 edgar_igl
545 f6953f13 edgar_igl
        if (size < 12)
546 f6953f13 edgar_igl
                return;
547 f6953f13 edgar_igl
548 f6953f13 edgar_igl
        D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n",
549 f6953f13 edgar_igl
                 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
550 f6953f13 edgar_igl
                 use_ma0, use_ma1, r_bcast));
551 f6953f13 edgar_igl
               
552 f6953f13 edgar_igl
        /* Does the frame get through the address filters?  */
553 f6953f13 edgar_igl
        if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6))
554 f6953f13 edgar_igl
            && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6))
555 f6953f13 edgar_igl
            && (!r_bcast || memcmp(buf, sa_bcast, 6))
556 f6953f13 edgar_igl
            && !eth_match_groupaddr(eth, buf))
557 f6953f13 edgar_igl
                return;
558 f6953f13 edgar_igl
559 a3ea5df5 edgar_igl
        if (size > sizeof(eth->rx_fifo)) {
560 f6953f13 edgar_igl
                /* TODO: signal error.        */
561 f6953f13 edgar_igl
        } else if (eth->rx_fifo_len) {
562 f6953f13 edgar_igl
                /* FIFO overrun.  */
563 a3ea5df5 edgar_igl
        } else {
564 a3ea5df5 edgar_igl
                memcpy(eth->rx_fifo, buf, size);
565 f6953f13 edgar_igl
                /* +4, HW passes the CRC to sw.         */
566 a3ea5df5 edgar_igl
                eth->rx_fifo_len = size + 4;
567 a3ea5df5 edgar_igl
                eth->rx_fifo_pos = 0;
568 a3ea5df5 edgar_igl
        }
569 a3ea5df5 edgar_igl
}
570 a3ea5df5 edgar_igl
571 a3ea5df5 edgar_igl
static void eth_rx_pull(void *opaque)
572 a3ea5df5 edgar_igl
{
573 a3ea5df5 edgar_igl
        struct fs_eth *eth = opaque;
574 a3ea5df5 edgar_igl
        int len;
575 a3ea5df5 edgar_igl
        if (eth->rx_fifo_len) {                
576 a3ea5df5 edgar_igl
                D(printf("%s %d\n", __func__, eth->rx_fifo_len));
577 a3ea5df5 edgar_igl
#if 0
578 a3ea5df5 edgar_igl
                {
579 a3ea5df5 edgar_igl
                        int i;
580 a3ea5df5 edgar_igl
                        for (i = 0; i < 32; i++)
581 a3ea5df5 edgar_igl
                                printf("%2.2x", eth->rx_fifo[i]);
582 a3ea5df5 edgar_igl
                        printf("\n");
583 a3ea5df5 edgar_igl
                }
584 a3ea5df5 edgar_igl
#endif
585 a3ea5df5 edgar_igl
                len = etraxfs_dmac_input(eth->dma_in,
586 a3ea5df5 edgar_igl
                                         eth->rx_fifo + eth->rx_fifo_pos, 
587 a3ea5df5 edgar_igl
                                         eth->rx_fifo_len, 1);
588 a3ea5df5 edgar_igl
                eth->rx_fifo_len -= len;
589 a3ea5df5 edgar_igl
                eth->rx_fifo_pos += len;
590 a3ea5df5 edgar_igl
        }
591 a3ea5df5 edgar_igl
}
592 a3ea5df5 edgar_igl
593 a3ea5df5 edgar_igl
static int eth_tx_push(void *opaque, unsigned char *buf, int len)
594 a3ea5df5 edgar_igl
{
595 a3ea5df5 edgar_igl
        struct fs_eth *eth = opaque;
596 a3ea5df5 edgar_igl
597 a3ea5df5 edgar_igl
        D(printf("%s buf=%p len=%d\n", __func__, buf, len));
598 a3ea5df5 edgar_igl
        qemu_send_packet(eth->vc, buf, len);
599 a3ea5df5 edgar_igl
        return len;
600 a3ea5df5 edgar_igl
}
601 a3ea5df5 edgar_igl
602 a3ea5df5 edgar_igl
static CPUReadMemoryFunc *eth_read[] = {
603 2e56350e edgar_igl
        &eth_rinvalid,
604 2e56350e edgar_igl
        &eth_rinvalid,
605 2e56350e edgar_igl
        &eth_readl,
606 a3ea5df5 edgar_igl
};
607 a3ea5df5 edgar_igl
608 a3ea5df5 edgar_igl
static CPUWriteMemoryFunc *eth_write[] = {
609 2e56350e edgar_igl
        &eth_winvalid,
610 2e56350e edgar_igl
        &eth_winvalid,
611 2e56350e edgar_igl
        &eth_writel,
612 a3ea5df5 edgar_igl
};
613 a3ea5df5 edgar_igl
614 a3ea5df5 edgar_igl
void *etraxfs_eth_init(NICInfo *nd, CPUState *env, 
615 a3ea5df5 edgar_igl
                       qemu_irq *irq, target_phys_addr_t base)
616 a3ea5df5 edgar_igl
{
617 a3ea5df5 edgar_igl
        struct etraxfs_dma_client *dma = NULL;        
618 a3ea5df5 edgar_igl
        struct fs_eth *eth = NULL;
619 a3ea5df5 edgar_igl
620 a3ea5df5 edgar_igl
        dma = qemu_mallocz(sizeof *dma * 2);
621 a3ea5df5 edgar_igl
        if (!dma)
622 a3ea5df5 edgar_igl
                return NULL;
623 a3ea5df5 edgar_igl
624 a3ea5df5 edgar_igl
        eth = qemu_mallocz(sizeof *eth);
625 a3ea5df5 edgar_igl
        if (!eth)
626 a3ea5df5 edgar_igl
                goto err;
627 a3ea5df5 edgar_igl
628 a3ea5df5 edgar_igl
        dma[0].client.push = eth_tx_push;
629 a3ea5df5 edgar_igl
        dma[0].client.opaque = eth;
630 a3ea5df5 edgar_igl
        dma[1].client.opaque = eth;
631 a3ea5df5 edgar_igl
        dma[1].client.pull = eth_rx_pull;
632 a3ea5df5 edgar_igl
633 a3ea5df5 edgar_igl
        eth->env = env;
634 a3ea5df5 edgar_igl
        eth->base = base;
635 a3ea5df5 edgar_igl
        eth->irq = irq;
636 a3ea5df5 edgar_igl
        eth->dma_out = dma;
637 a3ea5df5 edgar_igl
        eth->dma_in = dma + 1;
638 a3ea5df5 edgar_igl
639 a3ea5df5 edgar_igl
        /* Connect the phy.  */
640 c6488268 edgar_igl
        eth->phyaddr = 1;
641 a3ea5df5 edgar_igl
        tdk_init(&eth->phy);
642 c6488268 edgar_igl
        mdio_attach(&eth->mdio_bus, &eth->phy, eth->phyaddr);
643 a3ea5df5 edgar_igl
644 a3ea5df5 edgar_igl
        eth->ethregs = cpu_register_io_memory(0, eth_read, eth_write, eth);
645 a3ea5df5 edgar_igl
        cpu_register_physical_memory (base, 0x5c, eth->ethregs);
646 a3ea5df5 edgar_igl
647 a3ea5df5 edgar_igl
        eth->vc = qemu_new_vlan_client(nd->vlan, 
648 a3ea5df5 edgar_igl
                                       eth_receive, eth_can_receive, eth);
649 a3ea5df5 edgar_igl
650 a3ea5df5 edgar_igl
        return dma;
651 a3ea5df5 edgar_igl
  err:
652 a3ea5df5 edgar_igl
        qemu_free(eth);
653 a3ea5df5 edgar_igl
        qemu_free(dma);
654 a3ea5df5 edgar_igl
        return NULL;
655 a3ea5df5 edgar_igl
}