Statistics
| Branch: | Revision:

root / hw / etraxfs_eth.c @ c0b5b109

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