Statistics
| Branch: | Revision:

root / hw / etraxfs_eth.c @ a5f1b965

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 d297f464 edgar_igl
#ifdef USE_THIS_DEAD_CODE
158 a3ea5df5 edgar_igl
static void 
159 a3ea5df5 edgar_igl
mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
160 a3ea5df5 edgar_igl
{
161 a3ea5df5 edgar_igl
        bus->devs[addr & 0x1f] = NULL;        
162 a3ea5df5 edgar_igl
}
163 d297f464 edgar_igl
#endif
164 a3ea5df5 edgar_igl
165 a3ea5df5 edgar_igl
static void mdio_read_req(struct qemu_mdio *bus)
166 a3ea5df5 edgar_igl
{
167 a3ea5df5 edgar_igl
        struct qemu_phy *phy;
168 a3ea5df5 edgar_igl
169 a3ea5df5 edgar_igl
        phy = bus->devs[bus->addr];
170 a3ea5df5 edgar_igl
        if (phy && phy->read)
171 a3ea5df5 edgar_igl
                bus->data = phy->read(phy, bus->req);
172 a3ea5df5 edgar_igl
        else 
173 a3ea5df5 edgar_igl
                bus->data = 0xffff;
174 a3ea5df5 edgar_igl
}
175 a3ea5df5 edgar_igl
176 a3ea5df5 edgar_igl
static void mdio_write_req(struct qemu_mdio *bus)
177 a3ea5df5 edgar_igl
{
178 a3ea5df5 edgar_igl
        struct qemu_phy *phy;
179 a3ea5df5 edgar_igl
180 a3ea5df5 edgar_igl
        phy = bus->devs[bus->addr];
181 a3ea5df5 edgar_igl
        if (phy && phy->write)
182 a3ea5df5 edgar_igl
                phy->write(phy, bus->req, bus->data);
183 a3ea5df5 edgar_igl
}
184 a3ea5df5 edgar_igl
185 a3ea5df5 edgar_igl
static void mdio_cycle(struct qemu_mdio *bus)
186 a3ea5df5 edgar_igl
{
187 a3ea5df5 edgar_igl
        bus->cnt++;
188 a3ea5df5 edgar_igl
189 a3ea5df5 edgar_igl
        D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n",
190 a3ea5df5 edgar_igl
                bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive));
191 a3ea5df5 edgar_igl
#if 0
192 a3ea5df5 edgar_igl
        if (bus->mdc)
193 a3ea5df5 edgar_igl
                printf("%d", bus->mdio);
194 a3ea5df5 edgar_igl
#endif
195 a3ea5df5 edgar_igl
        switch (bus->state)
196 a3ea5df5 edgar_igl
        {
197 a3ea5df5 edgar_igl
                case PREAMBLE:
198 a3ea5df5 edgar_igl
                        if (bus->mdc) {
199 a3ea5df5 edgar_igl
                                if (bus->cnt >= (32 * 2) && !bus->mdio) {
200 a3ea5df5 edgar_igl
                                        bus->cnt = 0;
201 a3ea5df5 edgar_igl
                                        bus->state = SOF;
202 a3ea5df5 edgar_igl
                                        bus->data = 0;
203 a3ea5df5 edgar_igl
                                }
204 a3ea5df5 edgar_igl
                        }
205 a3ea5df5 edgar_igl
                        break;
206 a3ea5df5 edgar_igl
                case SOF:
207 a3ea5df5 edgar_igl
                        if (bus->mdc) {
208 a3ea5df5 edgar_igl
                                if (bus->mdio != 1)
209 a3ea5df5 edgar_igl
                                        printf("WARNING: no SOF\n");
210 a3ea5df5 edgar_igl
                                if (bus->cnt == 1*2) {
211 a3ea5df5 edgar_igl
                                        bus->cnt = 0;
212 a3ea5df5 edgar_igl
                                        bus->opc = 0;
213 a3ea5df5 edgar_igl
                                        bus->state = OPC;
214 a3ea5df5 edgar_igl
                                }
215 a3ea5df5 edgar_igl
                        }
216 a3ea5df5 edgar_igl
                        break;
217 a3ea5df5 edgar_igl
                case OPC:
218 a3ea5df5 edgar_igl
                        if (bus->mdc) {
219 a3ea5df5 edgar_igl
                                bus->opc <<= 1;
220 a3ea5df5 edgar_igl
                                bus->opc |= bus->mdio & 1;
221 a3ea5df5 edgar_igl
                                if (bus->cnt == 2*2) {
222 a3ea5df5 edgar_igl
                                        bus->cnt = 0;
223 a3ea5df5 edgar_igl
                                        bus->addr = 0;
224 a3ea5df5 edgar_igl
                                        bus->state = ADDR;
225 a3ea5df5 edgar_igl
                                }
226 a3ea5df5 edgar_igl
                        }
227 a3ea5df5 edgar_igl
                        break;
228 a3ea5df5 edgar_igl
                case ADDR:
229 a3ea5df5 edgar_igl
                        if (bus->mdc) {
230 a3ea5df5 edgar_igl
                                bus->addr <<= 1;
231 a3ea5df5 edgar_igl
                                bus->addr |= bus->mdio & 1;
232 a3ea5df5 edgar_igl
233 a3ea5df5 edgar_igl
                                if (bus->cnt == 5*2) {
234 a3ea5df5 edgar_igl
                                        bus->cnt = 0;
235 a3ea5df5 edgar_igl
                                        bus->req = 0;
236 a3ea5df5 edgar_igl
                                        bus->state = REQ;
237 a3ea5df5 edgar_igl
                                }
238 a3ea5df5 edgar_igl
                        }
239 a3ea5df5 edgar_igl
                        break;
240 a3ea5df5 edgar_igl
                case REQ:
241 a3ea5df5 edgar_igl
                        if (bus->mdc) {
242 a3ea5df5 edgar_igl
                                bus->req <<= 1;
243 a3ea5df5 edgar_igl
                                bus->req |= bus->mdio & 1;
244 a3ea5df5 edgar_igl
                                if (bus->cnt == 5*2) {
245 a3ea5df5 edgar_igl
                                        bus->cnt = 0;
246 a3ea5df5 edgar_igl
                                        bus->state = TURNAROUND;
247 a3ea5df5 edgar_igl
                                }
248 a3ea5df5 edgar_igl
                        }
249 a3ea5df5 edgar_igl
                        break;
250 a3ea5df5 edgar_igl
                case TURNAROUND:
251 a3ea5df5 edgar_igl
                        if (bus->mdc && bus->cnt == 2*2) {
252 a3ea5df5 edgar_igl
                                bus->mdio = 0;
253 a3ea5df5 edgar_igl
                                bus->cnt = 0;
254 a3ea5df5 edgar_igl
255 a3ea5df5 edgar_igl
                                if (bus->opc == 2) {
256 a3ea5df5 edgar_igl
                                        bus->drive = 1;
257 a3ea5df5 edgar_igl
                                        mdio_read_req(bus);
258 a3ea5df5 edgar_igl
                                        bus->mdio = bus->data & 1;
259 a3ea5df5 edgar_igl
                                }
260 a3ea5df5 edgar_igl
                                bus->state = DATA;
261 a3ea5df5 edgar_igl
                        }
262 a3ea5df5 edgar_igl
                        break;
263 a3ea5df5 edgar_igl
                case DATA:                        
264 a3ea5df5 edgar_igl
                        if (!bus->mdc) {
265 a3ea5df5 edgar_igl
                                if (bus->drive) {
266 2e56350e edgar_igl
                                        bus->mdio = !!(bus->data & (1 << 15));
267 2e56350e edgar_igl
                                        bus->data <<= 1;
268 a3ea5df5 edgar_igl
                                }
269 a3ea5df5 edgar_igl
                        } else {
270 a3ea5df5 edgar_igl
                                if (!bus->drive) {
271 a3ea5df5 edgar_igl
                                        bus->data <<= 1;
272 a3ea5df5 edgar_igl
                                        bus->data |= bus->mdio;
273 a3ea5df5 edgar_igl
                                }
274 a3ea5df5 edgar_igl
                                if (bus->cnt == 16 * 2) {
275 a3ea5df5 edgar_igl
                                        bus->cnt = 0;
276 a3ea5df5 edgar_igl
                                        bus->state = PREAMBLE;
277 2e56350e edgar_igl
                                        if (!bus->drive)
278 2e56350e edgar_igl
                                                mdio_write_req(bus);
279 2e56350e edgar_igl
                                        bus->drive = 0;
280 a3ea5df5 edgar_igl
                                }
281 a3ea5df5 edgar_igl
                        }
282 a3ea5df5 edgar_igl
                        break;
283 a3ea5df5 edgar_igl
                default:
284 a3ea5df5 edgar_igl
                        break;
285 a3ea5df5 edgar_igl
        }
286 a3ea5df5 edgar_igl
}
287 a3ea5df5 edgar_igl
288 2e56350e edgar_igl
/* ETRAX-FS Ethernet MAC block starts here.  */
289 2e56350e edgar_igl
290 f6953f13 edgar_igl
#define RW_MA0_LO          0x00
291 f6953f13 edgar_igl
#define RW_MA0_HI          0x04
292 f6953f13 edgar_igl
#define RW_MA1_LO          0x08
293 f6953f13 edgar_igl
#define RW_MA1_HI          0x0c
294 f6953f13 edgar_igl
#define RW_GA_LO          0x10
295 f6953f13 edgar_igl
#define RW_GA_HI          0x14
296 f6953f13 edgar_igl
#define RW_GEN_CTRL          0x18
297 f6953f13 edgar_igl
#define RW_REC_CTRL          0x1c
298 f6953f13 edgar_igl
#define RW_TR_CTRL          0x20
299 f6953f13 edgar_igl
#define RW_CLR_ERR          0x24
300 f6953f13 edgar_igl
#define RW_MGM_CTRL          0x28
301 f6953f13 edgar_igl
#define R_STAT                  0x2c
302 f6953f13 edgar_igl
#define FS_ETH_MAX_REGS          0x5c
303 a3ea5df5 edgar_igl
304 a3ea5df5 edgar_igl
struct fs_eth
305 a3ea5df5 edgar_igl
{
306 f6953f13 edgar_igl
        CPUState *env;
307 a3ea5df5 edgar_igl
        qemu_irq *irq;
308 f6953f13 edgar_igl
        target_phys_addr_t base;
309 a3ea5df5 edgar_igl
        VLANClientState *vc;
310 a3ea5df5 edgar_igl
        int ethregs;
311 a3ea5df5 edgar_igl
312 f6953f13 edgar_igl
        /* Two addrs in the filter.  */
313 f6953f13 edgar_igl
        uint8_t macaddr[2][6];
314 a3ea5df5 edgar_igl
        uint32_t regs[FS_ETH_MAX_REGS];
315 a3ea5df5 edgar_igl
316 a3ea5df5 edgar_igl
        unsigned char rx_fifo[1536];
317 a3ea5df5 edgar_igl
        int rx_fifo_len;
318 a3ea5df5 edgar_igl
        int rx_fifo_pos;
319 a3ea5df5 edgar_igl
320 a3ea5df5 edgar_igl
        struct etraxfs_dma_client *dma_out;
321 a3ea5df5 edgar_igl
        struct etraxfs_dma_client *dma_in;
322 a3ea5df5 edgar_igl
323 a3ea5df5 edgar_igl
        /* MDIO bus.  */
324 a3ea5df5 edgar_igl
        struct qemu_mdio mdio_bus;
325 f6953f13 edgar_igl
        /* PHY.         */
326 a3ea5df5 edgar_igl
        struct qemu_phy phy;
327 a3ea5df5 edgar_igl
};
328 a3ea5df5 edgar_igl
329 a3ea5df5 edgar_igl
static uint32_t eth_rinvalid (void *opaque, target_phys_addr_t addr)
330 a3ea5df5 edgar_igl
{
331 f6953f13 edgar_igl
        struct fs_eth *eth = opaque;
332 f6953f13 edgar_igl
        CPUState *env = eth->env;
333 d27b2e50 edgar_igl
        cpu_abort(env, "Unsupported short access. reg=" TARGET_FMT_plx "\n",
334 d27b2e50 edgar_igl
                  addr);
335 f6953f13 edgar_igl
        return 0;
336 a3ea5df5 edgar_igl
}
337 a3ea5df5 edgar_igl
338 a3ea5df5 edgar_igl
static uint32_t eth_readl (void *opaque, target_phys_addr_t addr)
339 a3ea5df5 edgar_igl
{
340 f6953f13 edgar_igl
        struct fs_eth *eth = opaque;
341 f6953f13 edgar_igl
        uint32_t r = 0;
342 a3ea5df5 edgar_igl
343 f6953f13 edgar_igl
        /* Make addr relative to this instances base.  */
344 f6953f13 edgar_igl
        addr -= eth->base;
345 f6953f13 edgar_igl
        switch (addr) {
346 a3ea5df5 edgar_igl
                case R_STAT:
347 a3ea5df5 edgar_igl
                        /* Attach an MDIO/PHY abstraction.  */
348 a3ea5df5 edgar_igl
                        r = eth->mdio_bus.mdio & 1;
349 a3ea5df5 edgar_igl
                        break;
350 f6953f13 edgar_igl
        default:
351 a3ea5df5 edgar_igl
                r = eth->regs[addr];
352 d27b2e50 edgar_igl
                D(printf ("%s %x\n", __func__, addr));
353 f6953f13 edgar_igl
                break;
354 f6953f13 edgar_igl
        }
355 f6953f13 edgar_igl
        return r;
356 a3ea5df5 edgar_igl
}
357 a3ea5df5 edgar_igl
358 a3ea5df5 edgar_igl
static void
359 a3ea5df5 edgar_igl
eth_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value)
360 a3ea5df5 edgar_igl
{
361 f6953f13 edgar_igl
        struct fs_eth *eth = opaque;
362 f6953f13 edgar_igl
        CPUState *env = eth->env;
363 d27b2e50 edgar_igl
        cpu_abort(env, "Unsupported short access. reg=" TARGET_FMT_plx "\n",
364 d27b2e50 edgar_igl
                  addr);
365 f6953f13 edgar_igl
}
366 f6953f13 edgar_igl
367 f6953f13 edgar_igl
static void eth_update_ma(struct fs_eth *eth, int ma)
368 f6953f13 edgar_igl
{
369 f6953f13 edgar_igl
        int reg;
370 f6953f13 edgar_igl
        int i = 0;
371 f6953f13 edgar_igl
372 f6953f13 edgar_igl
        ma &= 1;
373 f6953f13 edgar_igl
374 f6953f13 edgar_igl
        reg = RW_MA0_LO;
375 f6953f13 edgar_igl
        if (ma)
376 f6953f13 edgar_igl
                reg = RW_MA1_LO;
377 f6953f13 edgar_igl
378 f6953f13 edgar_igl
        eth->macaddr[ma][i++] = eth->regs[reg];
379 f6953f13 edgar_igl
        eth->macaddr[ma][i++] = eth->regs[reg] >> 8;
380 f6953f13 edgar_igl
        eth->macaddr[ma][i++] = eth->regs[reg] >> 16;
381 f6953f13 edgar_igl
        eth->macaddr[ma][i++] = eth->regs[reg] >> 24;
382 f6953f13 edgar_igl
        eth->macaddr[ma][i++] = eth->regs[reg + 4];
383 f6953f13 edgar_igl
        eth->macaddr[ma][i++] = eth->regs[reg + 4] >> 8;
384 f6953f13 edgar_igl
385 f6953f13 edgar_igl
        D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma,
386 f6953f13 edgar_igl
                 eth->macaddr[ma][0], eth->macaddr[ma][1],
387 f6953f13 edgar_igl
                 eth->macaddr[ma][2], eth->macaddr[ma][3],
388 f6953f13 edgar_igl
                 eth->macaddr[ma][4], eth->macaddr[ma][5]));
389 a3ea5df5 edgar_igl
}
390 a3ea5df5 edgar_igl
391 a3ea5df5 edgar_igl
static void
392 a3ea5df5 edgar_igl
eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
393 a3ea5df5 edgar_igl
{
394 f6953f13 edgar_igl
        struct fs_eth *eth = opaque;
395 f6953f13 edgar_igl
396 f6953f13 edgar_igl
        /* Make addr relative to this instances base.  */
397 f6953f13 edgar_igl
        addr -= eth->base;
398 f6953f13 edgar_igl
        switch (addr)
399 f6953f13 edgar_igl
        {
400 f6953f13 edgar_igl
                case RW_MA0_LO:
401 f6953f13 edgar_igl
                        eth->regs[addr] = value;
402 f6953f13 edgar_igl
                        eth_update_ma(eth, 0);
403 f6953f13 edgar_igl
                        break;
404 f6953f13 edgar_igl
                case RW_MA0_HI:
405 f6953f13 edgar_igl
                        eth->regs[addr] = value;
406 f6953f13 edgar_igl
                        eth_update_ma(eth, 0);
407 f6953f13 edgar_igl
                        break;
408 f6953f13 edgar_igl
                case RW_MA1_LO:
409 f6953f13 edgar_igl
                        eth->regs[addr] = value;
410 f6953f13 edgar_igl
                        eth_update_ma(eth, 1);
411 f6953f13 edgar_igl
                        break;
412 f6953f13 edgar_igl
                case RW_MA1_HI:
413 f6953f13 edgar_igl
                        eth->regs[addr] = value;
414 f6953f13 edgar_igl
                        eth_update_ma(eth, 1);
415 f6953f13 edgar_igl
                        break;
416 a3ea5df5 edgar_igl
417 a3ea5df5 edgar_igl
                case RW_MGM_CTRL:
418 a3ea5df5 edgar_igl
                        /* Attach an MDIO/PHY abstraction.  */
419 a3ea5df5 edgar_igl
                        if (value & 2)
420 a3ea5df5 edgar_igl
                                eth->mdio_bus.mdio = value & 1;
421 a3ea5df5 edgar_igl
                        if (eth->mdio_bus.mdc != (value & 4))
422 a3ea5df5 edgar_igl
                                mdio_cycle(&eth->mdio_bus);
423 a3ea5df5 edgar_igl
                        eth->mdio_bus.mdc = !!(value & 4);
424 a3ea5df5 edgar_igl
                        break;
425 a3ea5df5 edgar_igl
426 f6953f13 edgar_igl
                default:
427 f6953f13 edgar_igl
                        eth->regs[addr] = value;
428 9bcd77d6 edgar_igl
                        D(printf ("%s %x %x\n",
429 9bcd77d6 edgar_igl
                                  __func__, addr, value));
430 f6953f13 edgar_igl
                        break;
431 f6953f13 edgar_igl
        }
432 f6953f13 edgar_igl
}
433 f6953f13 edgar_igl
434 f6953f13 edgar_igl
/* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom
435 f6953f13 edgar_igl
   filter dropping group addresses we have not joined.        The filter has 64
436 f6953f13 edgar_igl
   bits (m). The has function is a simple nible xor of the group addr.        */
437 f6953f13 edgar_igl
static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa)
438 f6953f13 edgar_igl
{
439 f6953f13 edgar_igl
        unsigned int hsh;
440 f6953f13 edgar_igl
        int m_individual = eth->regs[RW_REC_CTRL] & 4;
441 f6953f13 edgar_igl
        int match;
442 f6953f13 edgar_igl
443 f6953f13 edgar_igl
        /* First bit on the wire of a MAC address signals multicast or
444 f6953f13 edgar_igl
           physical address.  */
445 f6953f13 edgar_igl
        if (!m_individual && !sa[0] & 1)
446 f6953f13 edgar_igl
                return 0;
447 f6953f13 edgar_igl
448 f6953f13 edgar_igl
        /* Calculate the hash index for the GA registers. */
449 f6953f13 edgar_igl
        hsh = 0;
450 f6953f13 edgar_igl
        hsh ^= (*sa) & 0x3f;
451 f6953f13 edgar_igl
        hsh ^= ((*sa) >> 6) & 0x03;
452 f6953f13 edgar_igl
        ++sa;
453 f6953f13 edgar_igl
        hsh ^= ((*sa) << 2) & 0x03c;
454 f6953f13 edgar_igl
        hsh ^= ((*sa) >> 4) & 0xf;
455 f6953f13 edgar_igl
        ++sa;
456 f6953f13 edgar_igl
        hsh ^= ((*sa) << 4) & 0x30;
457 f6953f13 edgar_igl
        hsh ^= ((*sa) >> 2) & 0x3f;
458 f6953f13 edgar_igl
        ++sa;
459 f6953f13 edgar_igl
        hsh ^= (*sa) & 0x3f;
460 f6953f13 edgar_igl
        hsh ^= ((*sa) >> 6) & 0x03;
461 f6953f13 edgar_igl
        ++sa;
462 f6953f13 edgar_igl
        hsh ^= ((*sa) << 2) & 0x03c;
463 f6953f13 edgar_igl
        hsh ^= ((*sa) >> 4) & 0xf;
464 f6953f13 edgar_igl
        ++sa;
465 f6953f13 edgar_igl
        hsh ^= ((*sa) << 4) & 0x30;
466 f6953f13 edgar_igl
        hsh ^= ((*sa) >> 2) & 0x3f;
467 f6953f13 edgar_igl
468 f6953f13 edgar_igl
        hsh &= 63;
469 f6953f13 edgar_igl
        if (hsh > 31)
470 f6953f13 edgar_igl
                match = eth->regs[RW_GA_HI] & (1 << (hsh - 32));
471 f6953f13 edgar_igl
        else
472 f6953f13 edgar_igl
                match = eth->regs[RW_GA_LO] & (1 << hsh);
473 f6953f13 edgar_igl
        D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh,
474 f6953f13 edgar_igl
                 eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match));
475 f6953f13 edgar_igl
        return match;
476 a3ea5df5 edgar_igl
}
477 a3ea5df5 edgar_igl
478 a3ea5df5 edgar_igl
static int eth_can_receive(void *opaque)
479 a3ea5df5 edgar_igl
{
480 a3ea5df5 edgar_igl
        struct fs_eth *eth = opaque;
481 a3ea5df5 edgar_igl
        int r;
482 a3ea5df5 edgar_igl
483 a3ea5df5 edgar_igl
        r = eth->rx_fifo_len == 0;
484 a3ea5df5 edgar_igl
        if (!r) {
485 a3ea5df5 edgar_igl
                /* TODO: signal fifo overrun.  */
486 a3ea5df5 edgar_igl
                printf("PACKET LOSS!\n");
487 a3ea5df5 edgar_igl
        }
488 a3ea5df5 edgar_igl
        return r;
489 a3ea5df5 edgar_igl
}
490 a3ea5df5 edgar_igl
491 a3ea5df5 edgar_igl
static void eth_receive(void *opaque, const uint8_t *buf, int size)
492 a3ea5df5 edgar_igl
{
493 f6953f13 edgar_igl
        unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
494 a3ea5df5 edgar_igl
        struct fs_eth *eth = opaque;
495 f6953f13 edgar_igl
        int use_ma0 = eth->regs[RW_REC_CTRL] & 1;
496 f6953f13 edgar_igl
        int use_ma1 = eth->regs[RW_REC_CTRL] & 2;
497 f6953f13 edgar_igl
        int r_bcast = eth->regs[RW_REC_CTRL] & 8;
498 f6953f13 edgar_igl
499 f6953f13 edgar_igl
        if (size < 12)
500 f6953f13 edgar_igl
                return;
501 f6953f13 edgar_igl
502 f6953f13 edgar_igl
        D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n",
503 f6953f13 edgar_igl
                 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
504 f6953f13 edgar_igl
                 use_ma0, use_ma1, r_bcast));
505 f6953f13 edgar_igl
               
506 f6953f13 edgar_igl
        /* Does the frame get through the address filters?  */
507 f6953f13 edgar_igl
        if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6))
508 f6953f13 edgar_igl
            && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6))
509 f6953f13 edgar_igl
            && (!r_bcast || memcmp(buf, sa_bcast, 6))
510 f6953f13 edgar_igl
            && !eth_match_groupaddr(eth, buf))
511 f6953f13 edgar_igl
                return;
512 f6953f13 edgar_igl
513 a3ea5df5 edgar_igl
        if (size > sizeof(eth->rx_fifo)) {
514 f6953f13 edgar_igl
                /* TODO: signal error.        */
515 f6953f13 edgar_igl
        } else if (eth->rx_fifo_len) {
516 f6953f13 edgar_igl
                /* FIFO overrun.  */
517 a3ea5df5 edgar_igl
        } else {
518 a3ea5df5 edgar_igl
                memcpy(eth->rx_fifo, buf, size);
519 f6953f13 edgar_igl
                /* +4, HW passes the CRC to sw.         */
520 a3ea5df5 edgar_igl
                eth->rx_fifo_len = size + 4;
521 a3ea5df5 edgar_igl
                eth->rx_fifo_pos = 0;
522 a3ea5df5 edgar_igl
        }
523 a3ea5df5 edgar_igl
}
524 a3ea5df5 edgar_igl
525 a3ea5df5 edgar_igl
static void eth_rx_pull(void *opaque)
526 a3ea5df5 edgar_igl
{
527 a3ea5df5 edgar_igl
        struct fs_eth *eth = opaque;
528 a3ea5df5 edgar_igl
        int len;
529 a3ea5df5 edgar_igl
        if (eth->rx_fifo_len) {                
530 a3ea5df5 edgar_igl
                D(printf("%s %d\n", __func__, eth->rx_fifo_len));
531 a3ea5df5 edgar_igl
#if 0
532 a3ea5df5 edgar_igl
                {
533 a3ea5df5 edgar_igl
                        int i;
534 a3ea5df5 edgar_igl
                        for (i = 0; i < 32; i++)
535 a3ea5df5 edgar_igl
                                printf("%2.2x", eth->rx_fifo[i]);
536 a3ea5df5 edgar_igl
                        printf("\n");
537 a3ea5df5 edgar_igl
                }
538 a3ea5df5 edgar_igl
#endif
539 a3ea5df5 edgar_igl
                len = etraxfs_dmac_input(eth->dma_in,
540 a3ea5df5 edgar_igl
                                         eth->rx_fifo + eth->rx_fifo_pos, 
541 a3ea5df5 edgar_igl
                                         eth->rx_fifo_len, 1);
542 a3ea5df5 edgar_igl
                eth->rx_fifo_len -= len;
543 a3ea5df5 edgar_igl
                eth->rx_fifo_pos += len;
544 a3ea5df5 edgar_igl
        }
545 a3ea5df5 edgar_igl
}
546 a3ea5df5 edgar_igl
547 a3ea5df5 edgar_igl
static int eth_tx_push(void *opaque, unsigned char *buf, int len)
548 a3ea5df5 edgar_igl
{
549 a3ea5df5 edgar_igl
        struct fs_eth *eth = opaque;
550 a3ea5df5 edgar_igl
551 a3ea5df5 edgar_igl
        D(printf("%s buf=%p len=%d\n", __func__, buf, len));
552 a3ea5df5 edgar_igl
        qemu_send_packet(eth->vc, buf, len);
553 a3ea5df5 edgar_igl
        return len;
554 a3ea5df5 edgar_igl
}
555 a3ea5df5 edgar_igl
556 a3ea5df5 edgar_igl
static CPUReadMemoryFunc *eth_read[] = {
557 2e56350e edgar_igl
        &eth_rinvalid,
558 2e56350e edgar_igl
        &eth_rinvalid,
559 2e56350e edgar_igl
        &eth_readl,
560 a3ea5df5 edgar_igl
};
561 a3ea5df5 edgar_igl
562 a3ea5df5 edgar_igl
static CPUWriteMemoryFunc *eth_write[] = {
563 2e56350e edgar_igl
        &eth_winvalid,
564 2e56350e edgar_igl
        &eth_winvalid,
565 2e56350e edgar_igl
        &eth_writel,
566 a3ea5df5 edgar_igl
};
567 a3ea5df5 edgar_igl
568 a3ea5df5 edgar_igl
void *etraxfs_eth_init(NICInfo *nd, CPUState *env, 
569 a3ea5df5 edgar_igl
                       qemu_irq *irq, target_phys_addr_t base)
570 a3ea5df5 edgar_igl
{
571 a3ea5df5 edgar_igl
        struct etraxfs_dma_client *dma = NULL;        
572 a3ea5df5 edgar_igl
        struct fs_eth *eth = NULL;
573 a3ea5df5 edgar_igl
574 a3ea5df5 edgar_igl
        dma = qemu_mallocz(sizeof *dma * 2);
575 a3ea5df5 edgar_igl
        if (!dma)
576 a3ea5df5 edgar_igl
                return NULL;
577 a3ea5df5 edgar_igl
578 a3ea5df5 edgar_igl
        eth = qemu_mallocz(sizeof *eth);
579 a3ea5df5 edgar_igl
        if (!eth)
580 a3ea5df5 edgar_igl
                goto err;
581 a3ea5df5 edgar_igl
582 a3ea5df5 edgar_igl
        dma[0].client.push = eth_tx_push;
583 a3ea5df5 edgar_igl
        dma[0].client.opaque = eth;
584 a3ea5df5 edgar_igl
        dma[1].client.opaque = eth;
585 a3ea5df5 edgar_igl
        dma[1].client.pull = eth_rx_pull;
586 a3ea5df5 edgar_igl
587 a3ea5df5 edgar_igl
        eth->env = env;
588 a3ea5df5 edgar_igl
        eth->base = base;
589 a3ea5df5 edgar_igl
        eth->irq = irq;
590 a3ea5df5 edgar_igl
        eth->dma_out = dma;
591 a3ea5df5 edgar_igl
        eth->dma_in = dma + 1;
592 a3ea5df5 edgar_igl
593 a3ea5df5 edgar_igl
        /* Connect the phy.  */
594 a3ea5df5 edgar_igl
        tdk_init(&eth->phy);
595 a3ea5df5 edgar_igl
        mdio_attach(&eth->mdio_bus, &eth->phy, 0x1);
596 a3ea5df5 edgar_igl
597 a3ea5df5 edgar_igl
        eth->ethregs = cpu_register_io_memory(0, eth_read, eth_write, eth);
598 a3ea5df5 edgar_igl
        cpu_register_physical_memory (base, 0x5c, eth->ethregs);
599 a3ea5df5 edgar_igl
600 a3ea5df5 edgar_igl
        eth->vc = qemu_new_vlan_client(nd->vlan, 
601 a3ea5df5 edgar_igl
                                       eth_receive, eth_can_receive, eth);
602 a3ea5df5 edgar_igl
603 a3ea5df5 edgar_igl
        return dma;
604 a3ea5df5 edgar_igl
  err:
605 a3ea5df5 edgar_igl
        qemu_free(eth);
606 a3ea5df5 edgar_igl
        qemu_free(dma);
607 a3ea5df5 edgar_igl
        return NULL;
608 a3ea5df5 edgar_igl
}