Statistics
| Branch: | Revision:

root / hw / etraxfs_eth.c @ 8da3ff18

History | View | Annotate | Download (13.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 a3ea5df5 edgar_igl
        VLANClientState *vc;
318 a3ea5df5 edgar_igl
        int ethregs;
319 a3ea5df5 edgar_igl
320 f6953f13 edgar_igl
        /* Two addrs in the filter.  */
321 f6953f13 edgar_igl
        uint8_t macaddr[2][6];
322 a3ea5df5 edgar_igl
        uint32_t regs[FS_ETH_MAX_REGS];
323 a3ea5df5 edgar_igl
324 a3ea5df5 edgar_igl
        struct etraxfs_dma_client *dma_out;
325 a3ea5df5 edgar_igl
        struct etraxfs_dma_client *dma_in;
326 a3ea5df5 edgar_igl
327 a3ea5df5 edgar_igl
        /* MDIO bus.  */
328 a3ea5df5 edgar_igl
        struct qemu_mdio mdio_bus;
329 c6488268 edgar_igl
        unsigned int phyaddr;
330 c6488268 edgar_igl
        int duplex_mismatch;
331 c6488268 edgar_igl
332 f6953f13 edgar_igl
        /* PHY.         */
333 a3ea5df5 edgar_igl
        struct qemu_phy phy;
334 a3ea5df5 edgar_igl
};
335 a3ea5df5 edgar_igl
336 c6488268 edgar_igl
static void eth_validate_duplex(struct fs_eth *eth)
337 c6488268 edgar_igl
{
338 c6488268 edgar_igl
        struct qemu_phy *phy;
339 c6488268 edgar_igl
        unsigned int phy_duplex;
340 c6488268 edgar_igl
        unsigned int mac_duplex;
341 c6488268 edgar_igl
        int new_mm = 0;
342 c6488268 edgar_igl
343 c6488268 edgar_igl
        phy = eth->mdio_bus.devs[eth->phyaddr];
344 c6488268 edgar_igl
        phy_duplex = !!(phy->read(phy, 18) & (1 << 11));
345 c6488268 edgar_igl
        mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128);
346 c6488268 edgar_igl
347 c6488268 edgar_igl
        if (mac_duplex != phy_duplex)
348 c6488268 edgar_igl
                new_mm = 1;
349 c6488268 edgar_igl
350 c6488268 edgar_igl
        if (eth->regs[RW_GEN_CTRL] & 1) {
351 c6488268 edgar_igl
                if (new_mm != eth->duplex_mismatch) {
352 c6488268 edgar_igl
                        if (new_mm)
353 c6488268 edgar_igl
                                printf("HW: WARNING "
354 c6488268 edgar_igl
                                       "ETH duplex mismatch MAC=%d PHY=%d\n",
355 c6488268 edgar_igl
                                       mac_duplex, phy_duplex);
356 c6488268 edgar_igl
                        else
357 c6488268 edgar_igl
                                printf("HW: ETH duplex ok.\n");
358 c6488268 edgar_igl
                }
359 c6488268 edgar_igl
                eth->duplex_mismatch = new_mm;
360 c6488268 edgar_igl
        }
361 c6488268 edgar_igl
}
362 c6488268 edgar_igl
363 a3ea5df5 edgar_igl
static uint32_t eth_rinvalid (void *opaque, target_phys_addr_t addr)
364 a3ea5df5 edgar_igl
{
365 f6953f13 edgar_igl
        struct fs_eth *eth = opaque;
366 f6953f13 edgar_igl
        CPUState *env = eth->env;
367 d27b2e50 edgar_igl
        cpu_abort(env, "Unsupported short access. reg=" TARGET_FMT_plx "\n",
368 d27b2e50 edgar_igl
                  addr);
369 f6953f13 edgar_igl
        return 0;
370 a3ea5df5 edgar_igl
}
371 a3ea5df5 edgar_igl
372 a3ea5df5 edgar_igl
static uint32_t eth_readl (void *opaque, target_phys_addr_t addr)
373 a3ea5df5 edgar_igl
{
374 f6953f13 edgar_igl
        struct fs_eth *eth = opaque;
375 f6953f13 edgar_igl
        uint32_t r = 0;
376 a3ea5df5 edgar_igl
377 f6953f13 edgar_igl
        switch (addr) {
378 a3ea5df5 edgar_igl
                case R_STAT:
379 a3ea5df5 edgar_igl
                        /* Attach an MDIO/PHY abstraction.  */
380 a3ea5df5 edgar_igl
                        r = eth->mdio_bus.mdio & 1;
381 a3ea5df5 edgar_igl
                        break;
382 f6953f13 edgar_igl
        default:
383 a3ea5df5 edgar_igl
                r = eth->regs[addr];
384 d27b2e50 edgar_igl
                D(printf ("%s %x\n", __func__, addr));
385 f6953f13 edgar_igl
                break;
386 f6953f13 edgar_igl
        }
387 f6953f13 edgar_igl
        return r;
388 a3ea5df5 edgar_igl
}
389 a3ea5df5 edgar_igl
390 a3ea5df5 edgar_igl
static void
391 a3ea5df5 edgar_igl
eth_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value)
392 a3ea5df5 edgar_igl
{
393 f6953f13 edgar_igl
        struct fs_eth *eth = opaque;
394 f6953f13 edgar_igl
        CPUState *env = eth->env;
395 d27b2e50 edgar_igl
        cpu_abort(env, "Unsupported short access. reg=" TARGET_FMT_plx "\n",
396 d27b2e50 edgar_igl
                  addr);
397 f6953f13 edgar_igl
}
398 f6953f13 edgar_igl
399 f6953f13 edgar_igl
static void eth_update_ma(struct fs_eth *eth, int ma)
400 f6953f13 edgar_igl
{
401 f6953f13 edgar_igl
        int reg;
402 f6953f13 edgar_igl
        int i = 0;
403 f6953f13 edgar_igl
404 f6953f13 edgar_igl
        ma &= 1;
405 f6953f13 edgar_igl
406 f6953f13 edgar_igl
        reg = RW_MA0_LO;
407 f6953f13 edgar_igl
        if (ma)
408 f6953f13 edgar_igl
                reg = RW_MA1_LO;
409 f6953f13 edgar_igl
410 f6953f13 edgar_igl
        eth->macaddr[ma][i++] = eth->regs[reg];
411 f6953f13 edgar_igl
        eth->macaddr[ma][i++] = eth->regs[reg] >> 8;
412 f6953f13 edgar_igl
        eth->macaddr[ma][i++] = eth->regs[reg] >> 16;
413 f6953f13 edgar_igl
        eth->macaddr[ma][i++] = eth->regs[reg] >> 24;
414 f6953f13 edgar_igl
        eth->macaddr[ma][i++] = eth->regs[reg + 4];
415 f6953f13 edgar_igl
        eth->macaddr[ma][i++] = eth->regs[reg + 4] >> 8;
416 f6953f13 edgar_igl
417 f6953f13 edgar_igl
        D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma,
418 f6953f13 edgar_igl
                 eth->macaddr[ma][0], eth->macaddr[ma][1],
419 f6953f13 edgar_igl
                 eth->macaddr[ma][2], eth->macaddr[ma][3],
420 f6953f13 edgar_igl
                 eth->macaddr[ma][4], eth->macaddr[ma][5]));
421 a3ea5df5 edgar_igl
}
422 a3ea5df5 edgar_igl
423 a3ea5df5 edgar_igl
static void
424 a3ea5df5 edgar_igl
eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
425 a3ea5df5 edgar_igl
{
426 f6953f13 edgar_igl
        struct fs_eth *eth = opaque;
427 f6953f13 edgar_igl
428 f6953f13 edgar_igl
        switch (addr)
429 f6953f13 edgar_igl
        {
430 f6953f13 edgar_igl
                case RW_MA0_LO:
431 f6953f13 edgar_igl
                        eth->regs[addr] = value;
432 f6953f13 edgar_igl
                        eth_update_ma(eth, 0);
433 f6953f13 edgar_igl
                        break;
434 f6953f13 edgar_igl
                case RW_MA0_HI:
435 f6953f13 edgar_igl
                        eth->regs[addr] = value;
436 f6953f13 edgar_igl
                        eth_update_ma(eth, 0);
437 f6953f13 edgar_igl
                        break;
438 f6953f13 edgar_igl
                case RW_MA1_LO:
439 f6953f13 edgar_igl
                        eth->regs[addr] = value;
440 f6953f13 edgar_igl
                        eth_update_ma(eth, 1);
441 f6953f13 edgar_igl
                        break;
442 f6953f13 edgar_igl
                case RW_MA1_HI:
443 f6953f13 edgar_igl
                        eth->regs[addr] = value;
444 f6953f13 edgar_igl
                        eth_update_ma(eth, 1);
445 f6953f13 edgar_igl
                        break;
446 a3ea5df5 edgar_igl
447 a3ea5df5 edgar_igl
                case RW_MGM_CTRL:
448 a3ea5df5 edgar_igl
                        /* Attach an MDIO/PHY abstraction.  */
449 a3ea5df5 edgar_igl
                        if (value & 2)
450 a3ea5df5 edgar_igl
                                eth->mdio_bus.mdio = value & 1;
451 c6488268 edgar_igl
                        if (eth->mdio_bus.mdc != (value & 4)) {
452 a3ea5df5 edgar_igl
                                mdio_cycle(&eth->mdio_bus);
453 c6488268 edgar_igl
                                eth_validate_duplex(eth);
454 c6488268 edgar_igl
                        }
455 a3ea5df5 edgar_igl
                        eth->mdio_bus.mdc = !!(value & 4);
456 a3ea5df5 edgar_igl
                        break;
457 a3ea5df5 edgar_igl
458 c6488268 edgar_igl
                case RW_REC_CTRL:
459 c6488268 edgar_igl
                        eth->regs[addr] = value;
460 c6488268 edgar_igl
                        eth_validate_duplex(eth);
461 c6488268 edgar_igl
                        break;
462 c6488268 edgar_igl
463 f6953f13 edgar_igl
                default:
464 f6953f13 edgar_igl
                        eth->regs[addr] = value;
465 9bcd77d6 edgar_igl
                        D(printf ("%s %x %x\n",
466 9bcd77d6 edgar_igl
                                  __func__, addr, value));
467 f6953f13 edgar_igl
                        break;
468 f6953f13 edgar_igl
        }
469 f6953f13 edgar_igl
}
470 f6953f13 edgar_igl
471 f6953f13 edgar_igl
/* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom
472 f6953f13 edgar_igl
   filter dropping group addresses we have not joined.        The filter has 64
473 f6953f13 edgar_igl
   bits (m). The has function is a simple nible xor of the group addr.        */
474 f6953f13 edgar_igl
static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa)
475 f6953f13 edgar_igl
{
476 f6953f13 edgar_igl
        unsigned int hsh;
477 f6953f13 edgar_igl
        int m_individual = eth->regs[RW_REC_CTRL] & 4;
478 f6953f13 edgar_igl
        int match;
479 f6953f13 edgar_igl
480 f6953f13 edgar_igl
        /* First bit on the wire of a MAC address signals multicast or
481 f6953f13 edgar_igl
           physical address.  */
482 f6953f13 edgar_igl
        if (!m_individual && !sa[0] & 1)
483 f6953f13 edgar_igl
                return 0;
484 f6953f13 edgar_igl
485 f6953f13 edgar_igl
        /* Calculate the hash index for the GA registers. */
486 f6953f13 edgar_igl
        hsh = 0;
487 f6953f13 edgar_igl
        hsh ^= (*sa) & 0x3f;
488 f6953f13 edgar_igl
        hsh ^= ((*sa) >> 6) & 0x03;
489 f6953f13 edgar_igl
        ++sa;
490 f6953f13 edgar_igl
        hsh ^= ((*sa) << 2) & 0x03c;
491 f6953f13 edgar_igl
        hsh ^= ((*sa) >> 4) & 0xf;
492 f6953f13 edgar_igl
        ++sa;
493 f6953f13 edgar_igl
        hsh ^= ((*sa) << 4) & 0x30;
494 f6953f13 edgar_igl
        hsh ^= ((*sa) >> 2) & 0x3f;
495 f6953f13 edgar_igl
        ++sa;
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
505 f6953f13 edgar_igl
        hsh &= 63;
506 f6953f13 edgar_igl
        if (hsh > 31)
507 f6953f13 edgar_igl
                match = eth->regs[RW_GA_HI] & (1 << (hsh - 32));
508 f6953f13 edgar_igl
        else
509 f6953f13 edgar_igl
                match = eth->regs[RW_GA_LO] & (1 << hsh);
510 f6953f13 edgar_igl
        D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh,
511 f6953f13 edgar_igl
                 eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match));
512 f6953f13 edgar_igl
        return match;
513 a3ea5df5 edgar_igl
}
514 a3ea5df5 edgar_igl
515 a3ea5df5 edgar_igl
static int eth_can_receive(void *opaque)
516 a3ea5df5 edgar_igl
{
517 aa25cf46 edgar_igl
        return 1;
518 a3ea5df5 edgar_igl
}
519 a3ea5df5 edgar_igl
520 a3ea5df5 edgar_igl
static void eth_receive(void *opaque, const uint8_t *buf, int size)
521 a3ea5df5 edgar_igl
{
522 f6953f13 edgar_igl
        unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
523 a3ea5df5 edgar_igl
        struct fs_eth *eth = opaque;
524 f6953f13 edgar_igl
        int use_ma0 = eth->regs[RW_REC_CTRL] & 1;
525 f6953f13 edgar_igl
        int use_ma1 = eth->regs[RW_REC_CTRL] & 2;
526 f6953f13 edgar_igl
        int r_bcast = eth->regs[RW_REC_CTRL] & 8;
527 f6953f13 edgar_igl
528 f6953f13 edgar_igl
        if (size < 12)
529 f6953f13 edgar_igl
                return;
530 f6953f13 edgar_igl
531 f6953f13 edgar_igl
        D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n",
532 f6953f13 edgar_igl
                 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
533 f6953f13 edgar_igl
                 use_ma0, use_ma1, r_bcast));
534 f6953f13 edgar_igl
               
535 f6953f13 edgar_igl
        /* Does the frame get through the address filters?  */
536 f6953f13 edgar_igl
        if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6))
537 f6953f13 edgar_igl
            && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6))
538 f6953f13 edgar_igl
            && (!r_bcast || memcmp(buf, sa_bcast, 6))
539 f6953f13 edgar_igl
            && !eth_match_groupaddr(eth, buf))
540 f6953f13 edgar_igl
                return;
541 f6953f13 edgar_igl
542 aa25cf46 edgar_igl
        /* FIXME: Find another way to pass on the fake csum.  */
543 aa25cf46 edgar_igl
        etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1);
544 a3ea5df5 edgar_igl
}
545 a3ea5df5 edgar_igl
546 a3ea5df5 edgar_igl
static int eth_tx_push(void *opaque, unsigned char *buf, int len)
547 a3ea5df5 edgar_igl
{
548 a3ea5df5 edgar_igl
        struct fs_eth *eth = opaque;
549 a3ea5df5 edgar_igl
550 a3ea5df5 edgar_igl
        D(printf("%s buf=%p len=%d\n", __func__, buf, len));
551 a3ea5df5 edgar_igl
        qemu_send_packet(eth->vc, buf, len);
552 a3ea5df5 edgar_igl
        return len;
553 a3ea5df5 edgar_igl
}
554 a3ea5df5 edgar_igl
555 a3ea5df5 edgar_igl
static CPUReadMemoryFunc *eth_read[] = {
556 2e56350e edgar_igl
        &eth_rinvalid,
557 2e56350e edgar_igl
        &eth_rinvalid,
558 2e56350e edgar_igl
        &eth_readl,
559 a3ea5df5 edgar_igl
};
560 a3ea5df5 edgar_igl
561 a3ea5df5 edgar_igl
static CPUWriteMemoryFunc *eth_write[] = {
562 2e56350e edgar_igl
        &eth_winvalid,
563 2e56350e edgar_igl
        &eth_winvalid,
564 2e56350e edgar_igl
        &eth_writel,
565 a3ea5df5 edgar_igl
};
566 a3ea5df5 edgar_igl
567 a3ea5df5 edgar_igl
void *etraxfs_eth_init(NICInfo *nd, CPUState *env, 
568 a3ea5df5 edgar_igl
                       qemu_irq *irq, target_phys_addr_t base)
569 a3ea5df5 edgar_igl
{
570 a3ea5df5 edgar_igl
        struct etraxfs_dma_client *dma = NULL;        
571 a3ea5df5 edgar_igl
        struct fs_eth *eth = NULL;
572 a3ea5df5 edgar_igl
573 a3ea5df5 edgar_igl
        dma = qemu_mallocz(sizeof *dma * 2);
574 a3ea5df5 edgar_igl
        if (!dma)
575 a3ea5df5 edgar_igl
                return NULL;
576 a3ea5df5 edgar_igl
577 a3ea5df5 edgar_igl
        eth = qemu_mallocz(sizeof *eth);
578 a3ea5df5 edgar_igl
        if (!eth)
579 a3ea5df5 edgar_igl
                goto err;
580 a3ea5df5 edgar_igl
581 a3ea5df5 edgar_igl
        dma[0].client.push = eth_tx_push;
582 a3ea5df5 edgar_igl
        dma[0].client.opaque = eth;
583 a3ea5df5 edgar_igl
        dma[1].client.opaque = eth;
584 aa25cf46 edgar_igl
        dma[1].client.pull = NULL;
585 a3ea5df5 edgar_igl
586 a3ea5df5 edgar_igl
        eth->env = env;
587 a3ea5df5 edgar_igl
        eth->irq = irq;
588 a3ea5df5 edgar_igl
        eth->dma_out = dma;
589 a3ea5df5 edgar_igl
        eth->dma_in = dma + 1;
590 a3ea5df5 edgar_igl
591 a3ea5df5 edgar_igl
        /* Connect the phy.  */
592 c6488268 edgar_igl
        eth->phyaddr = 1;
593 a3ea5df5 edgar_igl
        tdk_init(&eth->phy);
594 c6488268 edgar_igl
        mdio_attach(&eth->mdio_bus, &eth->phy, eth->phyaddr);
595 a3ea5df5 edgar_igl
596 a3ea5df5 edgar_igl
        eth->ethregs = cpu_register_io_memory(0, eth_read, eth_write, eth);
597 a3ea5df5 edgar_igl
        cpu_register_physical_memory (base, 0x5c, eth->ethregs);
598 a3ea5df5 edgar_igl
599 a3ea5df5 edgar_igl
        eth->vc = qemu_new_vlan_client(nd->vlan, 
600 a3ea5df5 edgar_igl
                                       eth_receive, eth_can_receive, eth);
601 a3ea5df5 edgar_igl
602 a3ea5df5 edgar_igl
        return dma;
603 a3ea5df5 edgar_igl
  err:
604 a3ea5df5 edgar_igl
        qemu_free(eth);
605 a3ea5df5 edgar_igl
        qemu_free(dma);
606 a3ea5df5 edgar_igl
        return NULL;
607 a3ea5df5 edgar_igl
}