Revision a3ea5df5

b/hw/etraxfs_eth.c
1
/*
2
 * QEMU ETRAX Ethernet Controller.
3
 *
4
 * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24

  
25
#include <stdio.h>
26
#include "hw.h"
27
#include "net.h"
28

  
29
#include "etraxfs_dma.h"
30

  
31
#define D(x)
32

  
33
#define R_STAT            0x2c
34
#define RW_MGM_CTRL       0x28
35
#define FS_ETH_MAX_REGS   0x5c
36

  
37

  
38

  
39
struct qemu_phy
40
{
41
	uint32_t regs[32];
42

  
43
	unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
44
	void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data);
45
};
46

  
47
static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
48
{
49
	int regnum;
50
	unsigned r = 0;
51

  
52
	regnum = req & 0x1f;
53

  
54
	switch (regnum) {
55
		case 1:
56
			/* MR1.  */
57
			/* Speeds and modes.  */
58
			r |= (1 << 13) | (1 << 14);
59
			r |= (1 << 11) | (1 << 12);
60
			r |= (1 << 5); /* Autoneg complete.  */
61
			r |= (1 << 3); /* Autoneg able.  */
62
			r |= (1 << 2); /* Link.  */
63
			break;
64
		default:
65
			r = phy->regs[regnum];
66
			break;
67
	}
68
	D(printf("%s %x = reg[%d]\n", __func__, r, regnum));
69
	return r;
70
}
71

  
72
static void 
73
tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
74
{
75
	int regnum;
76

  
77
	regnum = req & 0x1f;
78
	D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
79
	switch (regnum) {
80
		default:
81
			phy->regs[regnum] = data;
82
			break;
83
	}
84
}
85

  
86
static void 
87
tdk_init(struct qemu_phy *phy)
88
{
89
	phy->read = tdk_read;
90
	phy->write = tdk_write;
91
}
92

  
93
struct qemu_mdio
94
{
95
	/* bus.  */
96
	int mdc;
97
	int mdio;
98

  
99
	/* decoder.  */
100
	enum {
101
		PREAMBLE,
102
		SOF,
103
		OPC,
104
		ADDR,
105
		REQ,
106
		TURNAROUND,
107
		DATA
108
	} state;
109
	unsigned int drive;
110

  
111
	unsigned int cnt;
112
	unsigned int addr;
113
	unsigned int opc;
114
	unsigned int req;
115
	unsigned int data;
116

  
117
	struct qemu_phy *devs[32];
118
};
119

  
120
static void 
121
mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
122
{
123
	bus->devs[addr & 0x1f] = phy;
124
}
125

  
126
static void 
127
mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
128
{
129
	bus->devs[addr & 0x1f] = NULL;	
130
}
131

  
132
static void mdio_read_req(struct qemu_mdio *bus)
133
{
134
	struct qemu_phy *phy;
135

  
136
	phy = bus->devs[bus->addr];
137
	if (phy && phy->read)
138
		bus->data = phy->read(phy, bus->req);
139
	else 
140
		bus->data = 0xffff;
141
}
142

  
143
static void mdio_write_req(struct qemu_mdio *bus)
144
{
145
	struct qemu_phy *phy;
146

  
147
	phy = bus->devs[bus->addr];
148
	if (phy && phy->write)
149
		phy->write(phy, bus->req, bus->data);
150
}
151

  
152
static void mdio_cycle(struct qemu_mdio *bus)
153
{
154
	bus->cnt++;
155

  
156
	D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n",
157
		bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive));
158
#if 0
159
	if (bus->mdc)
160
		printf("%d", bus->mdio);
161
#endif
162
	switch (bus->state)
163
	{
164
		case PREAMBLE:
165
			if (bus->mdc) {
166
				if (bus->cnt >= (32 * 2) && !bus->mdio) {
167
					bus->cnt = 0;
168
					bus->state = SOF;
169
					bus->data = 0;
170
				}
171
			}
172
			break;
173
		case SOF:
174
			if (bus->mdc) {
175
				if (bus->mdio != 1)
176
					printf("WARNING: no SOF\n");
177
				if (bus->cnt == 1*2) {
178
					bus->cnt = 0;
179
					bus->opc = 0;
180
					bus->state = OPC;
181
				}
182
			}
183
			break;
184
		case OPC:
185
			if (bus->mdc) {
186
				bus->opc <<= 1;
187
				bus->opc |= bus->mdio & 1;
188
				if (bus->cnt == 2*2) {
189
					bus->cnt = 0;
190
					bus->addr = 0;
191
					bus->state = ADDR;
192
				}
193
			}
194
			break;
195
		case ADDR:
196
			if (bus->mdc) {
197
				bus->addr <<= 1;
198
				bus->addr |= bus->mdio & 1;
199

  
200
				if (bus->cnt == 5*2) {
201
					bus->cnt = 0;
202
					bus->req = 0;
203
					bus->state = REQ;
204
				}
205
			}
206
			break;
207
		case REQ:
208
			if (bus->mdc) {
209
				bus->req <<= 1;
210
				bus->req |= bus->mdio & 1;
211
				if (bus->cnt == 5*2) {
212
					bus->cnt = 0;
213
					bus->state = TURNAROUND;
214
				}
215
			}
216
			break;
217
		case TURNAROUND:
218
			if (bus->mdc && bus->cnt == 2*2) {
219
				bus->mdio = 0;
220
				bus->cnt = 0;
221

  
222
				if (bus->opc == 2) {
223
					bus->drive = 1;
224
					mdio_read_req(bus);
225
					bus->mdio = bus->data & 1;
226
				}
227
				bus->state = DATA;
228
			}
229
			break;
230
		case DATA:			
231
			if (!bus->mdc) {
232
				if (bus->drive) {
233
					bus->mdio = bus->data & 1;
234
					bus->data >>= 1;
235
				}
236
			} else {
237
				if (!bus->drive) {
238
					bus->data <<= 1;
239
					bus->data |= bus->mdio;
240
				}
241
				if (bus->cnt == 16 * 2) {
242
					bus->cnt = 0;
243
					bus->state = PREAMBLE;
244
					mdio_write_req(bus);
245
				}
246
			}
247
			break;
248
		default:
249
			break;
250
	}
251
}
252

  
253

  
254
struct fs_eth
255
{
256
        CPUState *env;
257
	qemu_irq *irq;
258
        target_phys_addr_t base;
259
	VLANClientState *vc;
260
	uint8_t macaddr[6];
261
	int ethregs;
262

  
263
	uint32_t regs[FS_ETH_MAX_REGS];
264

  
265
	unsigned char rx_fifo[1536];
266
	int rx_fifo_len;
267
	int rx_fifo_pos;
268

  
269
	struct etraxfs_dma_client *dma_out;
270
	struct etraxfs_dma_client *dma_in;
271

  
272
	/* MDIO bus.  */
273
	struct qemu_mdio mdio_bus;
274
	/* PHY.  */
275
	struct qemu_phy phy;
276
};
277

  
278
static uint32_t eth_rinvalid (void *opaque, target_phys_addr_t addr)
279
{
280
        struct fs_eth *eth = opaque;
281
        CPUState *env = eth->env;
282
        cpu_abort(env, "Unsupported short access. reg=%x pc=%x.\n", 
283
                  addr, env->pc);
284
        return 0;
285
}
286

  
287
static uint32_t eth_readl (void *opaque, target_phys_addr_t addr)
288
{
289
        struct fs_eth *eth = opaque;
290
        D(CPUState *env = eth->env);
291
        uint32_t r = 0;
292

  
293
        /* Make addr relative to this instances base.  */
294
        addr -= eth->base;
295
        switch (addr) {
296
		case R_STAT:
297
			/* Attach an MDIO/PHY abstraction.  */
298
			r = eth->mdio_bus.mdio & 1;
299
			break;
300
        default:
301
		r = eth->regs[addr];
302
                D(printf ("%s %x p=%x\n", __func__, addr, env->pc));
303
                break;
304
        }
305
        return r;
306
}
307

  
308
static void
309
eth_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value)
310
{
311
        struct fs_eth *eth = opaque;
312
        CPUState *env = eth->env;
313
        cpu_abort(env, "Unsupported short access. reg=%x pc=%x.\n", 
314
                  addr, env->pc);
315
}
316

  
317
static void
318
eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
319
{
320
        struct fs_eth *eth = opaque;
321
        CPUState *env = eth->env;
322

  
323
        /* Make addr relative to this instances base.  */
324
        addr -= eth->base;
325
        switch (addr)
326
        {
327
		case RW_MGM_CTRL:
328
			/* Attach an MDIO/PHY abstraction.  */
329
			if (value & 2)
330
				eth->mdio_bus.mdio = value & 1;
331
			if (eth->mdio_bus.mdc != (value & 4))
332
				mdio_cycle(&eth->mdio_bus);
333
			eth->mdio_bus.mdc = !!(value & 4);
334
			break;
335

  
336
                default:
337
                        printf ("%s %x %x pc=%x\n",
338
                                __func__, addr, value, env->pc);
339
                        break;
340
        }
341
}
342

  
343
static int eth_can_receive(void *opaque)
344
{
345
	struct fs_eth *eth = opaque;
346
	int r;
347

  
348
	r = eth->rx_fifo_len == 0;
349
	if (!r) {
350
		/* TODO: signal fifo overrun.  */
351
		printf("PACKET LOSS!\n");
352
	}
353
	return r;
354
}
355

  
356
static void eth_receive(void *opaque, const uint8_t *buf, int size)
357
{
358
	struct fs_eth *eth = opaque;
359
	if (size > sizeof(eth->rx_fifo)) {
360
		/* TODO: signal error.  */
361
	} else {
362
		memcpy(eth->rx_fifo, buf, size);
363
		/* +4, HW passes the CRC to sw.  */
364
		eth->rx_fifo_len = size + 4;
365
		eth->rx_fifo_pos = 0;
366
	}
367
}
368

  
369
static void eth_rx_pull(void *opaque)
370
{
371
	struct fs_eth *eth = opaque;
372
	int len;
373
	if (eth->rx_fifo_len) {		
374
		D(printf("%s %d\n", __func__, eth->rx_fifo_len));
375
#if 0
376
		{
377
			int i;
378
			for (i = 0; i < 32; i++)
379
				printf("%2.2x", eth->rx_fifo[i]);
380
			printf("\n");
381
		}
382
#endif
383
		len = etraxfs_dmac_input(eth->dma_in,
384
					 eth->rx_fifo + eth->rx_fifo_pos, 
385
					 eth->rx_fifo_len, 1);
386
		eth->rx_fifo_len -= len;
387
		eth->rx_fifo_pos += len;
388
	}
389
}
390

  
391
static int eth_tx_push(void *opaque, unsigned char *buf, int len)
392
{
393
	struct fs_eth *eth = opaque;
394

  
395
	D(printf("%s buf=%p len=%d\n", __func__, buf, len));
396
	qemu_send_packet(eth->vc, buf, len);
397
	return len;
398
}
399

  
400
static CPUReadMemoryFunc *eth_read[] = {
401
    &eth_rinvalid,
402
    &eth_rinvalid,
403
    &eth_readl,
404
};
405

  
406
static CPUWriteMemoryFunc *eth_write[] = {
407
    &eth_winvalid,
408
    &eth_winvalid,
409
    &eth_writel,
410
};
411

  
412
void *etraxfs_eth_init(NICInfo *nd, CPUState *env, 
413
		       qemu_irq *irq, target_phys_addr_t base)
414
{
415
	struct etraxfs_dma_client *dma = NULL;	
416
	struct fs_eth *eth = NULL;
417

  
418
	dma = qemu_mallocz(sizeof *dma * 2);
419
	if (!dma)
420
		return NULL;
421

  
422
	eth = qemu_mallocz(sizeof *eth);
423
	if (!eth)
424
		goto err;
425

  
426
	dma[0].client.push = eth_tx_push;
427
	dma[0].client.opaque = eth;
428
	dma[1].client.opaque = eth;
429
	dma[1].client.pull = eth_rx_pull;
430

  
431
	eth->env = env;
432
	eth->base = base;
433
	eth->irq = irq;
434
	eth->dma_out = dma;
435
	eth->dma_in = dma + 1;
436
	memcpy(eth->macaddr, nd->macaddr, 6);
437

  
438
	/* Connect the phy.  */
439
	tdk_init(&eth->phy);
440
	mdio_attach(&eth->mdio_bus, &eth->phy, 0x1);
441

  
442
	eth->ethregs = cpu_register_io_memory(0, eth_read, eth_write, eth);
443
	cpu_register_physical_memory (base, 0x5c, eth->ethregs);
444

  
445
	eth->vc = qemu_new_vlan_client(nd->vlan, 
446
				       eth_receive, eth_can_receive, eth);
447

  
448
	return dma;
449
  err:
450
	qemu_free(eth);
451
	qemu_free(dma);
452
	return NULL;
453
}

Also available in: Unified diff