fec.c 53.3 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
/*
 * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx.
 * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
 *
5
 * Right now, I am very wasteful with the buffers.  I allocate memory
Linus Torvalds's avatar
Linus Torvalds committed
6
7
8
9
10
11
12
13
14
 * pages and then divide them into 2K frame buffers.  This way I know I
 * have buffers large enough to hold one frame within one buffer descriptor.
 * Once I get this working, I will use 64 or 128 byte CPM buffers, which
 * will be much more memory efficient and will easily handle lots of
 * small packets.
 *
 * Much better multiple PHY support by Magnus Damm.
 * Copyright (c) 2000 Ericsson Radio Systems AB.
 *
15
16
 * Support for FEC controller of ColdFire processors.
 * Copyright (c) 2001-2005 Greg Ungerer (gerg@snapgear.com)
17
18
 *
 * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be)
19
 * Copyright (c) 2004-2006 Macq Electronique SA.
Linus Torvalds's avatar
Linus Torvalds committed
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/bitops.h>
39
40
#include <linux/io.h>
#include <linux/irq.h>
41
#include <linux/clk.h>
42
#include <linux/platform_device.h>
Linus Torvalds's avatar
Linus Torvalds committed
43

44
#include <asm/cacheflush.h>
45
46

#ifndef CONFIG_ARCH_MXC
Linus Torvalds's avatar
Linus Torvalds committed
47
48
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
49
#endif
50

Linus Torvalds's avatar
Linus Torvalds committed
51
52
#include "fec.h"

53
54
55
56
57
58
59
#ifdef CONFIG_ARCH_MXC
#include <mach/hardware.h>
#define FEC_ALIGNMENT	0xf
#else
#define FEC_ALIGNMENT	0x3
#endif

60
61
62
/*
 * Define the fixed address of the FEC hardware.
 */
63
#if defined(CONFIG_M5272)
64
#define HAVE_mii_link_interrupt
Linus Torvalds's avatar
Linus Torvalds committed
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

static unsigned char	fec_mac_default[] = {
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

/*
 * Some hardware gets it MAC address out of local flash memory.
 * if this is non-zero then assume it is the address to get MAC from.
 */
#if defined(CONFIG_NETtel)
#define	FEC_FLASHMAC	0xf0006006
#elif defined(CONFIG_GILBARCONAP) || defined(CONFIG_SCALES)
#define	FEC_FLASHMAC	0xf0006000
#elif defined(CONFIG_CANCam)
#define	FEC_FLASHMAC	0xf0020000
80
81
82
83
#elif defined (CONFIG_M5272C3)
#define	FEC_FLASHMAC	(0xffe04000 + 4)
#elif defined(CONFIG_MOD5272)
#define FEC_FLASHMAC 	0xffc0406b
Linus Torvalds's avatar
Linus Torvalds committed
84
85
86
#else
#define	FEC_FLASHMAC	0
#endif
87
#endif /* CONFIG_M5272 */
88

Sascha Hauer's avatar
Sascha Hauer committed
89
/* Forward declarations of some structures to support different PHYs */
Linus Torvalds's avatar
Linus Torvalds committed
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120

typedef struct {
	uint mii_data;
	void (*funct)(uint mii_reg, struct net_device *dev);
} phy_cmd_t;

typedef struct {
	uint id;
	char *name;

	const phy_cmd_t *config;
	const phy_cmd_t *startup;
	const phy_cmd_t *ack_int;
	const phy_cmd_t *shutdown;
} phy_info_t;

/* The number of Tx and Rx buffers.  These are allocated from the page
 * pool.  The code may assume these are power of two, so it it best
 * to keep them that size.
 * We don't need to allocate pages for the transmitter.  We just use
 * the skbuffer directly.
 */
#define FEC_ENET_RX_PAGES	8
#define FEC_ENET_RX_FRSIZE	2048
#define FEC_ENET_RX_FRPPG	(PAGE_SIZE / FEC_ENET_RX_FRSIZE)
#define RX_RING_SIZE		(FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES)
#define FEC_ENET_TX_FRSIZE	2048
#define FEC_ENET_TX_FRPPG	(PAGE_SIZE / FEC_ENET_TX_FRSIZE)
#define TX_RING_SIZE		16	/* Must be power of two */
#define TX_RING_MOD_MASK	15	/*   for this to work */

121
#if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE)
122
#error "FEC: descriptor ring size constants too large"
123
124
#endif

Sascha Hauer's avatar
Sascha Hauer committed
125
/* Interrupt events/masks. */
Linus Torvalds's avatar
Linus Torvalds committed
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#define FEC_ENET_HBERR	((uint)0x80000000)	/* Heartbeat error */
#define FEC_ENET_BABR	((uint)0x40000000)	/* Babbling receiver */
#define FEC_ENET_BABT	((uint)0x20000000)	/* Babbling transmitter */
#define FEC_ENET_GRA	((uint)0x10000000)	/* Graceful stop complete */
#define FEC_ENET_TXF	((uint)0x08000000)	/* Full frame transmitted */
#define FEC_ENET_TXB	((uint)0x04000000)	/* A buffer was transmitted */
#define FEC_ENET_RXF	((uint)0x02000000)	/* Full frame received */
#define FEC_ENET_RXB	((uint)0x01000000)	/* A buffer was received */
#define FEC_ENET_MII	((uint)0x00800000)	/* MII interrupt */
#define FEC_ENET_EBERR	((uint)0x00400000)	/* SDMA bus error */

/* The FEC stores dest/src/type, data, and checksum for receive packets.
 */
#define PKT_MAXBUF_SIZE		1518
#define PKT_MINBUF_SIZE		64
#define PKT_MAXBLR_SIZE		1520


/*
145
 * The 5270/5271/5280/5282/532x RX control register also contains maximum frame
Linus Torvalds's avatar
Linus Torvalds committed
146
147
148
 * size bits. Other FEC hardware does not, so we need to take that into
 * account when setting it.
 */
149
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
150
    defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARCH_MXC)
Linus Torvalds's avatar
Linus Torvalds committed
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#define	OPT_FRAME_SIZE	(PKT_MAXBUF_SIZE << 16)
#else
#define	OPT_FRAME_SIZE	0
#endif

/* The FEC buffer descriptors track the ring buffers.  The rx_bd_base and
 * tx_bd_base always point to the base of the buffer descriptors.  The
 * cur_rx and cur_tx point to the currently available buffer.
 * The dirty_tx tracks the current buffer that is being sent by the
 * controller.  The cur_tx and dirty_tx are equal under both completely
 * empty and completely full conditions.  The empty/ready indicator in
 * the buffer descriptor determines the actual condition.
 */
struct fec_enet_private {
	/* Hardware registers of the FEC device */
Sascha Hauer's avatar
Sascha Hauer committed
166
	void __iomem *hwp;
Linus Torvalds's avatar
Linus Torvalds committed
167

Greg Ungerer's avatar
Greg Ungerer committed
168
169
	struct net_device *netdev;

170
171
	struct clk *clk;

Linus Torvalds's avatar
Linus Torvalds committed
172
173
174
	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
	unsigned char *tx_bounce[TX_RING_SIZE];
	struct	sk_buff* tx_skbuff[TX_RING_SIZE];
Sascha Hauer's avatar
Sascha Hauer committed
175
	struct	sk_buff* rx_skbuff[RX_RING_SIZE];
Linus Torvalds's avatar
Linus Torvalds committed
176
177
178
	ushort	skb_cur;
	ushort	skb_dirty;

Sascha Hauer's avatar
Sascha Hauer committed
179
	/* CPM dual port RAM relative addresses */
180
	dma_addr_t	bd_dma;
Sascha Hauer's avatar
Sascha Hauer committed
181
	/* Address of Rx and Tx buffers */
182
183
184
185
	struct bufdesc	*rx_bd_base;
	struct bufdesc	*tx_bd_base;
	/* The next free ring entry */
	struct bufdesc	*cur_rx, *cur_tx; 
Sascha Hauer's avatar
Sascha Hauer committed
186
	/* The ring entries to be free()ed */
187
188
	struct bufdesc	*dirty_tx;

Linus Torvalds's avatar
Linus Torvalds committed
189
	uint	tx_full;
190
191
192
193
	/* hold while accessing the HW like ringbuffer for tx/rx but not MAC */
	spinlock_t hw_lock;
	/* hold while accessing the mii_list_t() elements */
	spinlock_t mii_lock;
Linus Torvalds's avatar
Linus Torvalds committed
194
195
196
197
198

	uint	phy_id;
	uint	phy_id_done;
	uint	phy_status;
	uint	phy_speed;
199
	phy_info_t const	*phy;
Linus Torvalds's avatar
Linus Torvalds committed
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
	struct work_struct phy_task;

	uint	sequence_done;
	uint	mii_phy_task_queued;

	uint	phy_addr;

	int	index;
	int	opened;
	int	link;
	int	old_link;
	int	full_duplex;
};

static void fec_enet_mii(struct net_device *dev);
215
static irqreturn_t fec_enet_interrupt(int irq, void * dev_id);
Linus Torvalds's avatar
Linus Torvalds committed
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
static void fec_enet_tx(struct net_device *dev);
static void fec_enet_rx(struct net_device *dev);
static int fec_enet_close(struct net_device *dev);
static void fec_restart(struct net_device *dev, int duplex);
static void fec_stop(struct net_device *dev);


/* MII processing.  We keep this as simple as possible.  Requests are
 * placed on the list (if there is room).  When the request is finished
 * by the MII, an optional function may be called.
 */
typedef struct mii_list {
	uint	mii_regval;
	void	(*mii_func)(uint val, struct net_device *dev);
	struct	mii_list *mii_next;
} mii_list_t;

#define		NMII	20
234
235
236
237
static mii_list_t	mii_cmds[NMII];
static mii_list_t	*mii_free;
static mii_list_t	*mii_head;
static mii_list_t	*mii_tail;
Linus Torvalds's avatar
Linus Torvalds committed
238

239
static int	mii_queue(struct net_device *dev, int request,
Linus Torvalds's avatar
Linus Torvalds committed
240
241
				void (*func)(uint, struct net_device *));

Sascha Hauer's avatar
Sascha Hauer committed
242
/* Make MII read/write commands for the FEC */
Linus Torvalds's avatar
Linus Torvalds committed
243
244
245
246
247
#define mk_mii_read(REG)	(0x60020000 | ((REG & 0x1f) << 18))
#define mk_mii_write(REG, VAL)	(0x50020000 | ((REG & 0x1f) << 18) | \
						(VAL & 0xffff))
#define mk_mii_end	0

Sascha Hauer's avatar
Sascha Hauer committed
248
249
/* Transmitter timeout */
#define TX_TIMEOUT (2 * HZ)
Linus Torvalds's avatar
Linus Torvalds committed
250

Sascha Hauer's avatar
Sascha Hauer committed
251
/* Register definitions for the PHY */
Linus Torvalds's avatar
Linus Torvalds committed
252
253
254
255
256

#define MII_REG_CR          0  /* Control Register                         */
#define MII_REG_SR          1  /* Status Register                          */
#define MII_REG_PHYIR1      2  /* PHY Identification Register 1            */
#define MII_REG_PHYIR2      3  /* PHY Identification Register 2            */
257
#define MII_REG_ANAR        4  /* A-N Advertisement Register               */
Linus Torvalds's avatar
Linus Torvalds committed
258
259
260
261
262
263
264
265
266
267
268
#define MII_REG_ANLPAR      5  /* A-N Link Partner Ability Register        */
#define MII_REG_ANER        6  /* A-N Expansion Register                   */
#define MII_REG_ANNPTR      7  /* A-N Next Page Transmit Register          */
#define MII_REG_ANLPRNPR    8  /* A-N Link Partner Received Next Page Reg. */

/* values for phy_status */

#define PHY_CONF_ANE	0x0001  /* 1 auto-negotiation enabled */
#define PHY_CONF_LOOP	0x0002  /* 1 loopback mode enabled */
#define PHY_CONF_SPMASK	0x00f0  /* mask for speed */
#define PHY_CONF_10HDX	0x0010  /* 10 Mbit half duplex supported */
269
#define PHY_CONF_10FDX	0x0020  /* 10 Mbit full duplex supported */
Linus Torvalds's avatar
Linus Torvalds committed
270
#define PHY_CONF_100HDX	0x0040  /* 100 Mbit half duplex supported */
271
#define PHY_CONF_100FDX	0x0080  /* 100 Mbit full duplex supported */
Linus Torvalds's avatar
Linus Torvalds committed
272
273
274
275
276
277

#define PHY_STAT_LINK	0x0100  /* 1 up - 0 down */
#define PHY_STAT_FAULT	0x0200  /* 1 remote fault */
#define PHY_STAT_ANC	0x0400  /* 1 auto-negotiation complete	*/
#define PHY_STAT_SPMASK	0xf000  /* mask for speed */
#define PHY_STAT_10HDX	0x1000  /* 10 Mbit half duplex selected	*/
278
#define PHY_STAT_10FDX	0x2000  /* 10 Mbit full duplex selected	*/
Linus Torvalds's avatar
Linus Torvalds committed
279
#define PHY_STAT_100HDX	0x4000  /* 100 Mbit half duplex selected */
280
#define PHY_STAT_100FDX	0x8000  /* 100 Mbit full duplex selected */
Linus Torvalds's avatar
Linus Torvalds committed
281
282
283
284
285


static int
fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
Sascha Hauer's avatar
Sascha Hauer committed
286
	struct fec_enet_private *fep = netdev_priv(dev);
287
	struct bufdesc *bdp;
288
	unsigned short	status;
289
	unsigned long flags;
Linus Torvalds's avatar
Linus Torvalds committed
290
291
292
293
294
295

	if (!fep->link) {
		/* Link is down or autonegotiation is in progress. */
		return 1;
	}

296
	spin_lock_irqsave(&fep->hw_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
297
298
299
	/* Fill in a Tx ring entry */
	bdp = fep->cur_tx;

300
	status = bdp->cbd_sc;
Sascha Hauer's avatar
Sascha Hauer committed
301

302
	if (status & BD_ENET_TX_READY) {
Linus Torvalds's avatar
Linus Torvalds committed
303
304
305
306
		/* Ooops.  All transmit buffers are full.  Bail out.
		 * This should not happen, since dev->tbusy should be set.
		 */
		printk("%s: tx queue full!.\n", dev->name);
307
		spin_unlock_irqrestore(&fep->hw_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
308
309
310
		return 1;
	}

Sascha Hauer's avatar
Sascha Hauer committed
311
	/* Clear all of the status flags */
312
	status &= ~BD_ENET_TX_STATS;
Linus Torvalds's avatar
Linus Torvalds committed
313

Sascha Hauer's avatar
Sascha Hauer committed
314
	/* Set buffer length and buffer pointer */
Linus Torvalds's avatar
Linus Torvalds committed
315
316
317
318
	bdp->cbd_bufaddr = __pa(skb->data);
	bdp->cbd_datlen = skb->len;

	/*
Sascha Hauer's avatar
Sascha Hauer committed
319
320
321
	 * On some FEC implementations data must be aligned on
	 * 4-byte boundaries. Use bounce buffers to copy data
	 * and get it aligned. Ugh.
Linus Torvalds's avatar
Linus Torvalds committed
322
	 */
323
	if (bdp->cbd_bufaddr & FEC_ALIGNMENT) {
Linus Torvalds's avatar
Linus Torvalds committed
324
325
		unsigned int index;
		index = bdp - fep->tx_bd_base;
326
		memcpy(fep->tx_bounce[index], (void *)skb->data, skb->len);
Linus Torvalds's avatar
Linus Torvalds committed
327
328
329
		bdp->cbd_bufaddr = __pa(fep->tx_bounce[index]);
	}

Sascha Hauer's avatar
Sascha Hauer committed
330
	/* Save skb pointer */
Linus Torvalds's avatar
Linus Torvalds committed
331
332
	fep->tx_skbuff[fep->skb_cur] = skb;

333
	dev->stats.tx_bytes += skb->len;
Linus Torvalds's avatar
Linus Torvalds committed
334
	fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK;
335

Linus Torvalds's avatar
Linus Torvalds committed
336
337
338
	/* Push the data cache so the CPM does not get stale memory
	 * data.
	 */
Sascha Hauer's avatar
Sascha Hauer committed
339
340
	bdp->cbd_bufaddr = dma_map_single(&dev->dev, skb->data,
			FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE);
Linus Torvalds's avatar
Linus Torvalds committed
341

342
343
	/* Send it on its way.  Tell FEC it's ready, interrupt when done,
	 * it's the last BD of the frame, and to put the CRC on the end.
Linus Torvalds's avatar
Linus Torvalds committed
344
	 */
345
	status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
Linus Torvalds's avatar
Linus Torvalds committed
346
			| BD_ENET_TX_LAST | BD_ENET_TX_TC);
347
	bdp->cbd_sc = status;
Linus Torvalds's avatar
Linus Torvalds committed
348
349
350
351

	dev->trans_start = jiffies;

	/* Trigger transmission start */
Sascha Hauer's avatar
Sascha Hauer committed
352
	writel(0, fep->hwp + FEC_X_DES_ACTIVE);
Linus Torvalds's avatar
Linus Torvalds committed
353

Sascha Hauer's avatar
Sascha Hauer committed
354
355
	/* If this was the last BD in the ring, start at the beginning again. */
	if (status & BD_ENET_TX_WRAP)
Linus Torvalds's avatar
Linus Torvalds committed
356
		bdp = fep->tx_bd_base;
Sascha Hauer's avatar
Sascha Hauer committed
357
	else
Linus Torvalds's avatar
Linus Torvalds committed
358
359
360
361
362
363
364
		bdp++;

	if (bdp == fep->dirty_tx) {
		fep->tx_full = 1;
		netif_stop_queue(dev);
	}

365
	fep->cur_tx = bdp;
Linus Torvalds's avatar
Linus Torvalds committed
366

367
	spin_unlock_irqrestore(&fep->hw_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
368
369
370
371
372
373
374
375
376

	return 0;
}

static void
fec_timeout(struct net_device *dev)
{
	struct fec_enet_private *fep = netdev_priv(dev);

377
	dev->stats.tx_errors++;
Linus Torvalds's avatar
Linus Torvalds committed
378

379
	fec_restart(dev, fep->full_duplex);
Linus Torvalds's avatar
Linus Torvalds committed
380
381
382
383
	netif_wake_queue(dev);
}

static irqreturn_t
384
fec_enet_interrupt(int irq, void * dev_id)
Linus Torvalds's avatar
Linus Torvalds committed
385
386
{
	struct	net_device *dev = dev_id;
Sascha Hauer's avatar
Sascha Hauer committed
387
	struct fec_enet_private *fep = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
388
	uint	int_events;
389
	irqreturn_t ret = IRQ_NONE;
Linus Torvalds's avatar
Linus Torvalds committed
390

391
	do {
Sascha Hauer's avatar
Sascha Hauer committed
392
393
		int_events = readl(fep->hwp + FEC_IEVENT);
		writel(int_events, fep->hwp + FEC_IEVENT);
Linus Torvalds's avatar
Linus Torvalds committed
394
395

		if (int_events & FEC_ENET_RXF) {
396
			ret = IRQ_HANDLED;
Linus Torvalds's avatar
Linus Torvalds committed
397
398
399
400
			fec_enet_rx(dev);
		}

		/* Transmit OK, or non-fatal error. Update the buffer
Sascha Hauer's avatar
Sascha Hauer committed
401
402
403
		 * descriptors. FEC handles all errors, we just discover
		 * them as part of the transmit process.
		 */
Linus Torvalds's avatar
Linus Torvalds committed
404
		if (int_events & FEC_ENET_TXF) {
405
			ret = IRQ_HANDLED;
Linus Torvalds's avatar
Linus Torvalds committed
406
407
408
409
			fec_enet_tx(dev);
		}

		if (int_events & FEC_ENET_MII) {
410
			ret = IRQ_HANDLED;
Linus Torvalds's avatar
Linus Torvalds committed
411
412
			fec_enet_mii(dev);
		}
413

414
415
416
	} while (int_events);

	return ret;
Linus Torvalds's avatar
Linus Torvalds committed
417
418
419
420
421
422
423
}


static void
fec_enet_tx(struct net_device *dev)
{
	struct	fec_enet_private *fep;
424
	struct bufdesc *bdp;
425
	unsigned short status;
Linus Torvalds's avatar
Linus Torvalds committed
426
427
428
	struct	sk_buff	*skb;

	fep = netdev_priv(dev);
429
	spin_lock_irq(&fep->hw_lock);
Linus Torvalds's avatar
Linus Torvalds committed
430
431
	bdp = fep->dirty_tx;

432
	while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
Sascha Hauer's avatar
Sascha Hauer committed
433
434
435
436
437
		if (bdp == fep->cur_tx && fep->tx_full == 0)
			break;

		dma_unmap_single(&dev->dev, bdp->cbd_bufaddr, FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE);
		bdp->cbd_bufaddr = 0;
Linus Torvalds's avatar
Linus Torvalds committed
438
439
440

		skb = fep->tx_skbuff[fep->skb_dirty];
		/* Check for errors. */
441
		if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
Linus Torvalds's avatar
Linus Torvalds committed
442
443
				   BD_ENET_TX_RL | BD_ENET_TX_UN |
				   BD_ENET_TX_CSL)) {
444
			dev->stats.tx_errors++;
445
			if (status & BD_ENET_TX_HB)  /* No heartbeat */
446
				dev->stats.tx_heartbeat_errors++;
447
			if (status & BD_ENET_TX_LC)  /* Late collision */
448
				dev->stats.tx_window_errors++;
449
			if (status & BD_ENET_TX_RL)  /* Retrans limit */
450
				dev->stats.tx_aborted_errors++;
451
			if (status & BD_ENET_TX_UN)  /* Underrun */
452
				dev->stats.tx_fifo_errors++;
453
			if (status & BD_ENET_TX_CSL) /* Carrier lost */
454
				dev->stats.tx_carrier_errors++;
Linus Torvalds's avatar
Linus Torvalds committed
455
		} else {
456
			dev->stats.tx_packets++;
Linus Torvalds's avatar
Linus Torvalds committed
457
458
		}

459
		if (status & BD_ENET_TX_READY)
Linus Torvalds's avatar
Linus Torvalds committed
460
			printk("HEY! Enet xmit interrupt and TX_READY.\n");
Sascha Hauer's avatar
Sascha Hauer committed
461

Linus Torvalds's avatar
Linus Torvalds committed
462
463
464
		/* Deferred means some collisions occurred during transmit,
		 * but we eventually sent the packet OK.
		 */
465
		if (status & BD_ENET_TX_DEF)
466
			dev->stats.collisions++;
467

Sascha Hauer's avatar
Sascha Hauer committed
468
		/* Free the sk buffer associated with this last transmit */
Linus Torvalds's avatar
Linus Torvalds committed
469
470
471
		dev_kfree_skb_any(skb);
		fep->tx_skbuff[fep->skb_dirty] = NULL;
		fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK;
472

Sascha Hauer's avatar
Sascha Hauer committed
473
		/* Update pointer to next buffer descriptor to be transmitted */
474
		if (status & BD_ENET_TX_WRAP)
Linus Torvalds's avatar
Linus Torvalds committed
475
476
477
			bdp = fep->tx_bd_base;
		else
			bdp++;
478

Sascha Hauer's avatar
Sascha Hauer committed
479
		/* Since we have freed up a buffer, the ring is no longer full
Linus Torvalds's avatar
Linus Torvalds committed
480
481
482
483
484
485
486
		 */
		if (fep->tx_full) {
			fep->tx_full = 0;
			if (netif_queue_stopped(dev))
				netif_wake_queue(dev);
		}
	}
487
	fep->dirty_tx = bdp;
488
	spin_unlock_irq(&fep->hw_lock);
Linus Torvalds's avatar
Linus Torvalds committed
489
490
491
492
493
494
495
496
497
498
499
}


/* During a receive, the cur_rx points to the current incoming buffer.
 * When we update through the ring, if the next incoming buffer has
 * not been given to the system, we just set the empty indicator,
 * effectively tossing the packet.
 */
static void
fec_enet_rx(struct net_device *dev)
{
Sascha Hauer's avatar
Sascha Hauer committed
500
	struct	fec_enet_private *fep = netdev_priv(dev);
501
	struct bufdesc *bdp;
502
	unsigned short status;
Linus Torvalds's avatar
Linus Torvalds committed
503
504
505
	struct	sk_buff	*skb;
	ushort	pkt_len;
	__u8 *data;
506

507
508
#ifdef CONFIG_M532x
	flush_cache_all();
509
#endif
Linus Torvalds's avatar
Linus Torvalds committed
510

511
512
	spin_lock_irq(&fep->hw_lock);

Linus Torvalds's avatar
Linus Torvalds committed
513
514
515
516
517
	/* First, grab all of the stats for the incoming packet.
	 * These get messed up if we get called due to a busy condition.
	 */
	bdp = fep->cur_rx;

Sascha Hauer's avatar
Sascha Hauer committed
518
	while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
Linus Torvalds's avatar
Linus Torvalds committed
519

Sascha Hauer's avatar
Sascha Hauer committed
520
521
522
523
524
		/* Since we have allocated space to hold a complete frame,
		 * the last indicator should be set.
		 */
		if ((status & BD_ENET_RX_LAST) == 0)
			printk("FEC ENET: rcv is not +last\n");
Linus Torvalds's avatar
Linus Torvalds committed
525

Sascha Hauer's avatar
Sascha Hauer committed
526
527
		if (!fep->opened)
			goto rx_processing_done;
Linus Torvalds's avatar
Linus Torvalds committed
528

Sascha Hauer's avatar
Sascha Hauer committed
529
530
		/* Check for errors. */
		if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
Linus Torvalds's avatar
Linus Torvalds committed
531
			   BD_ENET_RX_CR | BD_ENET_RX_OV)) {
Sascha Hauer's avatar
Sascha Hauer committed
532
533
534
535
536
537
538
539
540
541
542
			dev->stats.rx_errors++;
			if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
				/* Frame too long or too short. */
				dev->stats.rx_length_errors++;
			}
			if (status & BD_ENET_RX_NO)	/* Frame alignment */
				dev->stats.rx_frame_errors++;
			if (status & BD_ENET_RX_CR)	/* CRC Error */
				dev->stats.rx_crc_errors++;
			if (status & BD_ENET_RX_OV)	/* FIFO overrun */
				dev->stats.rx_fifo_errors++;
Linus Torvalds's avatar
Linus Torvalds committed
543
544
		}

Sascha Hauer's avatar
Sascha Hauer committed
545
546
547
548
549
550
551
552
553
		/* Report late collisions as a frame error.
		 * On this error, the BD is closed, but we don't know what we
		 * have in the buffer.  So, just drop this frame on the floor.
		 */
		if (status & BD_ENET_RX_CL) {
			dev->stats.rx_errors++;
			dev->stats.rx_frame_errors++;
			goto rx_processing_done;
		}
Linus Torvalds's avatar
Linus Torvalds committed
554

Sascha Hauer's avatar
Sascha Hauer committed
555
556
557
558
559
		/* Process the incoming frame. */
		dev->stats.rx_packets++;
		pkt_len = bdp->cbd_datlen;
		dev->stats.rx_bytes += pkt_len;
		data = (__u8*)__va(bdp->cbd_bufaddr);
Linus Torvalds's avatar
Linus Torvalds committed
560

Sascha Hauer's avatar
Sascha Hauer committed
561
562
	        dma_unmap_single(NULL, bdp->cbd_bufaddr, bdp->cbd_datlen,
        			DMA_FROM_DEVICE);
563

Sascha Hauer's avatar
Sascha Hauer committed
564
565
566
567
568
		/* This does 16 byte alignment, exactly what we need.
		 * The packet length includes FCS, but we don't want to
		 * include that when passing upstream as it messes up
		 * bridging applications.
		 */
Sascha Hauer's avatar
Sascha Hauer committed
569
		skb = dev_alloc_skb(pkt_len - 4 + NET_IP_ALIGN);
Linus Torvalds's avatar
Linus Torvalds committed
570

Sascha Hauer's avatar
Sascha Hauer committed
571
		if (unlikely(!skb)) {
Sascha Hauer's avatar
Sascha Hauer committed
572
573
574
575
			printk("%s: Memory squeeze, dropping packet.\n",
					dev->name);
			dev->stats.rx_dropped++;
		} else {
Sascha Hauer's avatar
Sascha Hauer committed
576
			skb_reserve(skb, NET_IP_ALIGN);
Sascha Hauer's avatar
Sascha Hauer committed
577
578
579
580
581
			skb_put(skb, pkt_len - 4);	/* Make room */
			skb_copy_to_linear_data(skb, data, pkt_len - 4);
			skb->protocol = eth_type_trans(skb, dev);
			netif_rx(skb);
		}
Sascha Hauer's avatar
Sascha Hauer committed
582
583
584

        	bdp->cbd_bufaddr = dma_map_single(NULL, data, bdp->cbd_datlen,
			DMA_FROM_DEVICE);
Sascha Hauer's avatar
Sascha Hauer committed
585
586
587
rx_processing_done:
		/* Clear the status flags for this buffer */
		status &= ~BD_ENET_RX_STATS;
Linus Torvalds's avatar
Linus Torvalds committed
588

Sascha Hauer's avatar
Sascha Hauer committed
589
590
591
		/* Mark the buffer empty */
		status |= BD_ENET_RX_EMPTY;
		bdp->cbd_sc = status;
592

Sascha Hauer's avatar
Sascha Hauer committed
593
594
595
596
597
598
599
600
601
602
603
		/* Update BD pointer to next entry */
		if (status & BD_ENET_RX_WRAP)
			bdp = fep->rx_bd_base;
		else
			bdp++;
		/* Doing this here will keep the FEC running while we process
		 * incoming frames.  On a heavily loaded network, we should be
		 * able to keep up at the expense of system resources.
		 */
		writel(0, fep->hwp + FEC_R_DES_ACTIVE);
	}
604
	fep->cur_rx = bdp;
Linus Torvalds's avatar
Linus Torvalds committed
605

606
	spin_unlock_irq(&fep->hw_lock);
Linus Torvalds's avatar
Linus Torvalds committed
607
608
}

609
/* called from interrupt context */
Linus Torvalds's avatar
Linus Torvalds committed
610
611
612
613
614
615
616
static void
fec_enet_mii(struct net_device *dev)
{
	struct	fec_enet_private *fep;
	mii_list_t	*mip;

	fep = netdev_priv(dev);
617
618
	spin_lock_irq(&fep->mii_lock);

Linus Torvalds's avatar
Linus Torvalds committed
619
620
	if ((mip = mii_head) == NULL) {
		printk("MII and no head!\n");
621
		goto unlock;
Linus Torvalds's avatar
Linus Torvalds committed
622
623
624
	}

	if (mip->mii_func != NULL)
Sascha Hauer's avatar
Sascha Hauer committed
625
		(*(mip->mii_func))(readl(fep->hwp + FEC_MII_DATA), dev);
Linus Torvalds's avatar
Linus Torvalds committed
626
627
628
629
630
631

	mii_head = mip->mii_next;
	mip->mii_next = mii_free;
	mii_free = mip;

	if ((mip = mii_head) != NULL)
Sascha Hauer's avatar
Sascha Hauer committed
632
		writel(mip->mii_regval, fep->hwp + FEC_MII_DATA);
633
634

unlock:
635
	spin_unlock_irq(&fep->mii_lock);
Linus Torvalds's avatar
Linus Torvalds committed
636
637
638
639
640
641
642
643
644
645
}

static int
mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_device *))
{
	struct fec_enet_private *fep;
	unsigned long	flags;
	mii_list_t	*mip;
	int		retval;

Sascha Hauer's avatar
Sascha Hauer committed
646
	/* Add PHY address to register command */
Linus Torvalds's avatar
Linus Torvalds committed
647
	fep = netdev_priv(dev);
648
	spin_lock_irqsave(&fep->mii_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
649

650
	regval |= fep->phy_addr << 23;
Linus Torvalds's avatar
Linus Torvalds committed
651
652
653
654
655
656
657
658
659
660
	retval = 0;

	if ((mip = mii_free) != NULL) {
		mii_free = mip->mii_next;
		mip->mii_regval = regval;
		mip->mii_func = func;
		mip->mii_next = NULL;
		if (mii_head) {
			mii_tail->mii_next = mip;
			mii_tail = mip;
661
		} else {
Linus Torvalds's avatar
Linus Torvalds committed
662
			mii_head = mii_tail = mip;
Sascha Hauer's avatar
Sascha Hauer committed
663
			writel(regval, fep->hwp + FEC_MII_DATA);
Linus Torvalds's avatar
Linus Torvalds committed
664
		}
665
	} else {
Linus Torvalds's avatar
Linus Torvalds committed
666
667
668
		retval = 1;
	}

669
670
	spin_unlock_irqrestore(&fep->mii_lock, flags);
	return retval;
Linus Torvalds's avatar
Linus Torvalds committed
671
672
673
674
675
676
677
}

static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c)
{
	if(!c)
		return;

678
679
	for (; c->mii_data != mk_mii_end; c++)
		mii_queue(dev, c->mii_data, c->funct);
Linus Torvalds's avatar
Linus Torvalds committed
680
681
682
683
684
685
}

static void mii_parse_sr(uint mii_reg, struct net_device *dev)
{
	struct fec_enet_private *fep = netdev_priv(dev);
	volatile uint *s = &(fep->phy_status);
686
	uint status;
Linus Torvalds's avatar
Linus Torvalds committed
687

688
	status = *s & ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC);
Linus Torvalds's avatar
Linus Torvalds committed
689
690

	if (mii_reg & 0x0004)
691
		status |= PHY_STAT_LINK;
Linus Torvalds's avatar
Linus Torvalds committed
692
	if (mii_reg & 0x0010)
693
		status |= PHY_STAT_FAULT;
Linus Torvalds's avatar
Linus Torvalds committed
694
	if (mii_reg & 0x0020)
695
696
		status |= PHY_STAT_ANC;
	*s = status;
Linus Torvalds's avatar
Linus Torvalds committed
697
698
699
700
701
702
}

static void mii_parse_cr(uint mii_reg, struct net_device *dev)
{
	struct fec_enet_private *fep = netdev_priv(dev);
	volatile uint *s = &(fep->phy_status);
703
	uint status;
Linus Torvalds's avatar
Linus Torvalds committed
704

705
	status = *s & ~(PHY_CONF_ANE | PHY_CONF_LOOP);
Linus Torvalds's avatar
Linus Torvalds committed
706
707

	if (mii_reg & 0x1000)
708
		status |= PHY_CONF_ANE;
Linus Torvalds's avatar
Linus Torvalds committed
709
	if (mii_reg & 0x4000)
710
711
		status |= PHY_CONF_LOOP;
	*s = status;
Linus Torvalds's avatar
Linus Torvalds committed
712
713
714
715
716
717
}

static void mii_parse_anar(uint mii_reg, struct net_device *dev)
{
	struct fec_enet_private *fep = netdev_priv(dev);
	volatile uint *s = &(fep->phy_status);
718
	uint status;
Linus Torvalds's avatar
Linus Torvalds committed
719

720
	status = *s & ~(PHY_CONF_SPMASK);
Linus Torvalds's avatar
Linus Torvalds committed
721
722

	if (mii_reg & 0x0020)
723
		status |= PHY_CONF_10HDX;
Linus Torvalds's avatar
Linus Torvalds committed
724
	if (mii_reg & 0x0040)
725
		status |= PHY_CONF_10FDX;
Linus Torvalds's avatar
Linus Torvalds committed
726
	if (mii_reg & 0x0080)
727
		status |= PHY_CONF_100HDX;
Linus Torvalds's avatar
Linus Torvalds committed
728
	if (mii_reg & 0x00100)
729
730
		status |= PHY_CONF_100FDX;
	*s = status;
Linus Torvalds's avatar
Linus Torvalds committed
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
}

/* ------------------------------------------------------------------------- */
/* The Level one LXT970 is used by many boards				     */

#define MII_LXT970_MIRROR    16  /* Mirror register           */
#define MII_LXT970_IER       17  /* Interrupt Enable Register */
#define MII_LXT970_ISR       18  /* Interrupt Status Register */
#define MII_LXT970_CONFIG    19  /* Configuration Register    */
#define MII_LXT970_CSR       20  /* Chip Status Register      */

static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev)
{
	struct fec_enet_private *fep = netdev_priv(dev);
	volatile uint *s = &(fep->phy_status);
746
	uint status;
Linus Torvalds's avatar
Linus Torvalds committed
747

748
	status = *s & ~(PHY_STAT_SPMASK);
Linus Torvalds's avatar
Linus Torvalds committed
749
750
	if (mii_reg & 0x0800) {
		if (mii_reg & 0x1000)
751
			status |= PHY_STAT_100FDX;
Linus Torvalds's avatar
Linus Torvalds committed
752
		else
753
			status |= PHY_STAT_100HDX;
Linus Torvalds's avatar
Linus Torvalds committed
754
755
	} else {
		if (mii_reg & 0x1000)
756
			status |= PHY_STAT_10FDX;
Linus Torvalds's avatar
Linus Torvalds committed
757
		else
758
			status |= PHY_STAT_10HDX;
Linus Torvalds's avatar
Linus Torvalds committed
759
	}
760
	*s = status;
Linus Torvalds's avatar
Linus Torvalds committed
761
762
}

763
static phy_cmd_t const phy_cmd_lxt970_config[] = {
Linus Torvalds's avatar
Linus Torvalds committed
764
765
766
		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
		{ mk_mii_end, }
767
768
	};
static phy_cmd_t const phy_cmd_lxt970_startup[] = { /* enable interrupts */
Linus Torvalds's avatar
Linus Torvalds committed
769
770
771
		{ mk_mii_write(MII_LXT970_IER, 0x0002), NULL },
		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
		{ mk_mii_end, }
772
773
	};
static phy_cmd_t const phy_cmd_lxt970_ack_int[] = {
Linus Torvalds's avatar
Linus Torvalds committed
774
775
776
777
778
779
780
		/* read SR and ISR to acknowledge */
		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
		{ mk_mii_read(MII_LXT970_ISR), NULL },

		/* find out the current status */
		{ mk_mii_read(MII_LXT970_CSR), mii_parse_lxt970_csr },
		{ mk_mii_end, }
781
782
	};
static phy_cmd_t const phy_cmd_lxt970_shutdown[] = { /* disable interrupts */
Linus Torvalds's avatar
Linus Torvalds committed
783
784
		{ mk_mii_write(MII_LXT970_IER, 0x0000), NULL },
		{ mk_mii_end, }
785
786
	};
static phy_info_t const phy_info_lxt970 = {
787
	.id = 0x07810000,
788
789
790
791
792
	.name = "LXT970",
	.config = phy_cmd_lxt970_config,
	.startup = phy_cmd_lxt970_startup,
	.ack_int = phy_cmd_lxt970_ack_int,
	.shutdown = phy_cmd_lxt970_shutdown
Linus Torvalds's avatar
Linus Torvalds committed
793
};
794

Linus Torvalds's avatar
Linus Torvalds committed
795
796
797
798
799
800
801
802
803
804
805
806
/* ------------------------------------------------------------------------- */
/* The Level one LXT971 is used on some of my custom boards                  */

/* register definitions for the 971 */

#define MII_LXT971_PCR       16  /* Port Control Register     */
#define MII_LXT971_SR2       17  /* Status Register 2         */
#define MII_LXT971_IER       18  /* Interrupt Enable Register */
#define MII_LXT971_ISR       19  /* Interrupt Status Register */
#define MII_LXT971_LCR       20  /* LED Control Register      */
#define MII_LXT971_TCR       30  /* Transmit Control Register */

807
/*
Linus Torvalds's avatar
Linus Torvalds committed
808
809
810
811
812
813
814
815
816
 * I had some nice ideas of running the MDIO faster...
 * The 971 should support 8MHz and I tried it, but things acted really
 * weird, so 2.5 MHz ought to be enough for anyone...
 */

static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev)
{
	struct fec_enet_private *fep = netdev_priv(dev);
	volatile uint *s = &(fep->phy_status);
817
	uint status;
Linus Torvalds's avatar
Linus Torvalds committed
818

819
	status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC);
Linus Torvalds's avatar
Linus Torvalds committed
820
821
822

	if (mii_reg & 0x0400) {
		fep->link = 1;
823
		status |= PHY_STAT_LINK;
Linus Torvalds's avatar
Linus Torvalds committed
824
825
826
827
	} else {
		fep->link = 0;
	}
	if (mii_reg & 0x0080)
828
		status |= PHY_STAT_ANC;
Linus Torvalds's avatar
Linus Torvalds committed
829
830
	if (mii_reg & 0x4000) {
		if (mii_reg & 0x0200)
831
			status |= PHY_STAT_100FDX;
Linus Torvalds's avatar
Linus Torvalds committed
832
		else
833
			status |= PHY_STAT_100HDX;
Linus Torvalds's avatar
Linus Torvalds committed
834
835
	} else {
		if (mii_reg & 0x0200)
836
			status |= PHY_STAT_10FDX;
Linus Torvalds's avatar
Linus Torvalds committed
837
		else
838
			status |= PHY_STAT_10HDX;
Linus Torvalds's avatar
Linus Torvalds committed
839
840
	}
	if (mii_reg & 0x0008)
841
		status |= PHY_STAT_FAULT;
Linus Torvalds's avatar
Linus Torvalds committed
842

843
844
	*s = status;
}
845

846
static phy_cmd_t const phy_cmd_lxt971_config[] = {
847
		/* limit to 10MBit because my prototype board
Linus Torvalds's avatar
Linus Torvalds committed
848
849
850
851
852
		 * doesn't work with 100. */
		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
		{ mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 },
		{ mk_mii_end, }
853
854
	};
static phy_cmd_t const phy_cmd_lxt971_startup[] = {  /* enable interrupts */
Linus Torvalds's avatar
Linus Torvalds committed
855
856
857
858
859
860
		{ mk_mii_write(MII_LXT971_IER, 0x00f2), NULL },
		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
		{ mk_mii_write(MII_LXT971_LCR, 0xd422), NULL }, /* LED config */
		/* Somehow does the 971 tell me that the link is down
		 * the first read after power-up.
		 * read here to get a valid value in ack_int */
861
		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
Linus Torvalds's avatar
Linus Torvalds committed
862
		{ mk_mii_end, }
863
864
865
866
	};
static phy_cmd_t const phy_cmd_lxt971_ack_int[] = {
		/* acknowledge the int before reading status ! */
		{ mk_mii_read(MII_LXT971_ISR), NULL },
Linus Torvalds's avatar
Linus Torvalds committed
867
868
869
870
		/* find out the current status */
		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
		{ mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 },
		{ mk_mii_end, }
871
872
	};
static phy_cmd_t const phy_cmd_lxt971_shutdown[] = { /* disable interrupts */
Linus Torvalds's avatar
Linus Torvalds committed
873
874
		{ mk_mii_write(MII_LXT971_IER, 0x0000), NULL },
		{ mk_mii_end, }
875
876
	};
static phy_info_t const phy_info_lxt971 = {
877
	.id = 0x0001378e,
878
879
880
881
882
	.name = "LXT971",
	.config = phy_cmd_lxt971_config,
	.startup = phy_cmd_lxt971_startup,
	.ack_int = phy_cmd_lxt971_ack_int,
	.shutdown = phy_cmd_lxt971_shutdown
Linus Torvalds's avatar
Linus Torvalds committed
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
};

/* ------------------------------------------------------------------------- */
/* The Quality Semiconductor QS6612 is used on the RPX CLLF                  */

/* register definitions */

#define MII_QS6612_MCR       17  /* Mode Control Register      */
#define MII_QS6612_FTR       27  /* Factory Test Register      */
#define MII_QS6612_MCO       28  /* Misc. Control Register     */
#define MII_QS6612_ISR       29  /* Interrupt Source Register  */
#define MII_QS6612_IMR       30  /* Interrupt Mask Register    */
#define MII_QS6612_PCR       31  /* 100BaseTx PHY Control Reg. */

static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev)
{
	struct fec_enet_private *fep = netdev_priv(dev);
	volatile uint *s = &(fep->phy_status);
901
	uint status;
Linus Torvalds's avatar
Linus Torvalds committed
902

903
	status = *s & ~(PHY_STAT_SPMASK);
Linus Torvalds's avatar
Linus Torvalds committed
904
905

	switch((mii_reg >> 2) & 7) {
906
907
908
909
	case 1: status |= PHY_STAT_10HDX; break;
	case 2: status |= PHY_STAT_100HDX; break;
	case 5: status |= PHY_STAT_10FDX; break;
	case 6: status |= PHY_STAT_100FDX; break;
Linus Torvalds's avatar
Linus Torvalds committed
910
911
}

912
913
914
915
	*s = status;
}

static phy_cmd_t const phy_cmd_qs6612_config[] = {
916
		/* The PHY powers up isolated on the RPX,
Linus Torvalds's avatar
Linus Torvalds committed
917
918
919
920
921
922
923
924
		 * so send a command to allow operation.
		 */
		{ mk_mii_write(MII_QS6612_PCR, 0x0dc0), NULL },

		/* parse cr and anar to get some info */
		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
		{ mk_mii_end, }
925
926
	};
static phy_cmd_t const phy_cmd_qs6612_startup[] = {  /* enable interrupts */
Linus Torvalds's avatar
Linus Torvalds committed
927
928
929
		{ mk_mii_write(MII_QS6612_IMR, 0x003a), NULL },
		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
		{ mk_mii_end, }
930
931
	};
static phy_cmd_t const phy_cmd_qs6612_ack_int[] = {
Linus Torvalds's avatar
Linus Torvalds committed
932
933
934
935
936
937
938
939
		/* we need to read ISR, SR and ANER to acknowledge */
		{ mk_mii_read(MII_QS6612_ISR), NULL },
		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
		{ mk_mii_read(MII_REG_ANER), NULL },

		/* read pcr to get info */
		{ mk_mii_read(MII_QS6612_PCR), mii_parse_qs6612_pcr },
		{ mk_mii_end, }
940
941
	};
static phy_cmd_t const phy_cmd_qs6612_shutdown[] = { /* disable interrupts */
Linus Torvalds's avatar
Linus Torvalds committed
942
943
		{ mk_mii_write(MII_QS6612_IMR, 0x0000), NULL },
		{ mk_mii_end, }
944
945
	};
static phy_info_t const phy_info_qs6612 = {
946
	.id = 0x00181440,
947
948
949
950
951
	.name = "QS6612",
	.config = phy_cmd_qs6612_config,
	.startup = phy_cmd_qs6612_startup,
	.ack_int = phy_cmd_qs6612_ack_int,
	.shutdown = phy_cmd_qs6612_shutdown
Linus Torvalds's avatar
Linus Torvalds committed
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
};

/* ------------------------------------------------------------------------- */
/* AMD AM79C874 phy                                                          */

/* register definitions for the 874 */

#define MII_AM79C874_MFR       16  /* Miscellaneous Feature Register */
#define MII_AM79C874_ICSR      17  /* Interrupt/Status Register      */
#define MII_AM79C874_DR        18  /* Diagnostic Register            */
#define MII_AM79C874_PMLR      19  /* Power and Loopback Register    */
#define MII_AM79C874_MCR       21  /* ModeControl Register           */
#define MII_AM79C874_DC        23  /* Disconnect Counter             */
#define MII_AM79C874_REC       24  /* Recieve Error Counter          */

static void mii_parse_am79c874_dr(uint mii_reg, struct net_device *dev)
{
	struct fec_enet_private *fep = netdev_priv(dev);
	volatile uint *s = &(fep->phy_status);
971
	uint status;
Linus Torvalds's avatar
Linus Torvalds committed
972

973
	status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_ANC);
Linus Torvalds's avatar
Linus Torvalds committed
974
975

	if (mii_reg & 0x0080)
976
		status |= PHY_STAT_ANC;
Linus Torvalds's avatar
Linus Torvalds committed
977
	if (mii_reg & 0x0400)
978
		status |= ((mii_reg & 0x0800) ? PHY_STAT_100FDX : PHY_STAT_100HDX);
Linus Torvalds's avatar
Linus Torvalds committed
979
	else
980
981
982
		status |= ((mii_reg & 0x0800) ? PHY_STAT_10FDX : PHY_STAT_10HDX);

	*s = status;
Linus Torvalds's avatar
Linus Torvalds committed
983
984
}

985
static phy_cmd_t const phy_cmd_am79c874_config[] = {
Linus Torvalds's avatar
Linus Torvalds committed
986
987
988
989
		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
		{ mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr },
		{ mk_mii_end, }
990
991
	};
static phy_cmd_t const phy_cmd_am79c874_startup[] = {  /* enable interrupts */
Linus Torvalds's avatar
Linus Torvalds committed
992
993
		{ mk_mii_write(MII_AM79C874_ICSR, 0xff00), NULL },
		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
994
		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
Linus Torvalds's avatar
Linus Torvalds committed
995
		{ mk_mii_end, }
996
997
	};
static phy_cmd_t const phy_cmd_am79c874_ack_int[] = {
Linus Torvalds's avatar
Linus Torvalds committed
998
999
1000
1001
1002
1003
		/* find out the current status */
		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
		{ mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr },
		/* we only need to read ISR to acknowledge */
		{ mk_mii_read(MII_AM79C874_ICSR), NULL },
		{ mk_mii_end, }
1004
1005
	};
static phy_cmd_t const phy_cmd_am79c874_shutdown[] = { /* disable interrupts */
Linus Torvalds's avatar
Linus Torvalds committed
1006
1007
		{ mk_mii_write(MII_AM79C874_ICSR, 0x0000), NULL },
		{ mk_mii_end, }
1008
1009
1010
1011
1012
1013
1014
1015
	};
static phy_info_t const phy_info_am79c874 = {
	.id = 0x00022561,
	.name = "AM79C874",
	.config = phy_cmd_am79c874_config,
	.startup = phy_cmd_am79c874_startup,
	.ack_int = phy_cmd_am79c874_ack_int,
	.shutdown = phy_cmd_am79c874_shutdown
Linus Torvalds's avatar
Linus Torvalds committed
1016
1017
};

1018

Linus Torvalds's avatar
Linus Torvalds committed
1019
1020
1021
1022
1023
1024
/* ------------------------------------------------------------------------- */
/* Kendin KS8721BL phy                                                       */

/* register definitions for the 8721 */

#define MII_KS8721BL_RXERCR	21
1025
#define MII_KS8721BL_ICSR	27
Linus Torvalds's avatar
Linus Torvalds committed
1026
1027
#define	MII_KS8721BL_PHYCR	31

1028
static phy_cmd_t const phy_cmd_ks8721bl_config[] = {
Linus Torvalds's avatar
Linus Torvalds committed
1029
1030
1031
		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
		{ mk_mii_end, }
1032
1033
	};
static phy_cmd_t const phy_cmd_ks8721bl_startup[] = {  /* enable interrupts */
Linus Torvalds's avatar
Linus Torvalds committed
1034
1035
		{ mk_mii_write(MII_KS8721BL_ICSR, 0xff00), NULL },
		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
1036
		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
Linus Torvalds's avatar
Linus Torvalds committed
1037
		{ mk_mii_end, }
1038
1039
	};
static phy_cmd_t const phy_cmd_ks8721bl_ack_int[] = {
Linus Torvalds's avatar
Linus Torvalds committed
1040
1041
1042
1043
1044
		/* find out the current status */
		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
		/* we only need to read ISR to acknowledge */
		{ mk_mii_read(MII_KS8721BL_ICSR), NULL },
		{ mk_mii_end, }
1045
1046
	};
static phy_cmd_t const phy_cmd_ks8721bl_shutdown[] = { /* disable interrupts */
Linus Torvalds's avatar
Linus Torvalds committed
1047
1048
		{ mk_mii_write(MII_KS8721BL_ICSR, 0x0000), NULL },
		{ mk_mii_end, }
1049
1050
	};
static phy_info_t const phy_info_ks8721bl = {
1051
	.id = 0x00022161,
1052
1053
1054
1055
1056
	.name = "KS8721BL",
	.config = phy_cmd_ks8721bl_config,
	.startup = phy_cmd_ks8721bl_startup,
	.ack_int = phy_cmd_ks8721bl_ack_int,
	.shutdown = phy_cmd_ks8721bl_shutdown
Linus Torvalds's avatar
Linus Torvalds committed
1057
1058
};

1059
1060
1061
1062
1063
1064
1065
/* ------------------------------------------------------------------------- */
/* register definitions for the DP83848 */

#define MII_DP8384X_PHYSTST    16  /* PHY Status Register */

static void mii_parse_dp8384x_sr2(uint mii_reg, struct net_device *dev)
{
1066
	struct fec_enet_private *fep = netdev_priv(dev);
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
	volatile uint *s = &(fep->phy_status);

	*s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC);

	/* Link up */
	if (mii_reg & 0x0001) {
		fep->link = 1;
		*s |= PHY_STAT_LINK;
	} else
		fep->link = 0;
	/* Status of link */
	if (mii_reg & 0x0010)   /* Autonegotioation complete */
		*s |= PHY_STAT_ANC;
	if (mii_reg & 0x0002) {   /* 10MBps? */
		if (mii_reg & 0x0004)   /* Full Duplex? */
			*s |= PHY_STAT_10FDX;
		else
			*s |= PHY_STAT_10HDX;
	} else {                  /* 100 Mbps? */
		if (mii_reg & 0x0004)   /* Full Duplex? */
			*s |= PHY_STAT_100FDX;
		else
			*s |= PHY_STAT_100HDX;
	}
	if (mii_reg & 0x0008)
		*s |= PHY_STAT_FAULT;
}

static phy_info_t phy_info_dp83848= {
	0x020005c9,
	"DP83848",

	(const phy_cmd_t []) {  /* config */
		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
		{ mk_mii_read(MII_DP8384X_PHYSTST), mii_parse_dp8384x_sr2 },
		{ mk_mii_end, }
	},
	(const phy_cmd_t []) {  /* startup - enable interrupts */
		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
		{ mk_mii_end, }
	},
	(const phy_cmd_t []) { /* ack_int - never happens, no interrupt */
		{ mk_mii_end, }
	},
	(const phy_cmd_t []) {  /* shutdown */
		{ mk_mii_end, }
	},
};

Linus Torvalds's avatar
Linus Torvalds committed
1118
1119
/* ------------------------------------------------------------------------- */

1120
static phy_info_t const * const phy_info[] = {
Linus Torvalds's avatar
Linus Torvalds committed
1121
1122
1123
1124
1125
	&phy_info_lxt970,
	&phy_info_lxt971,
	&phy_info_qs6612,
	&phy_info_am79c874,
	&phy_info_ks8721bl,
1126
	&phy_info_dp83848,
Linus Torvalds's avatar
Linus Torvalds committed
1127
1128
1129
1130
	NULL
};

/* ------------------------------------------------------------------------- */
1131
#ifdef HAVE_mii_link_interrupt
Linus Torvalds's avatar
Linus Torvalds committed
1132
static irqreturn_t
1133
mii_link_interrupt(int irq, void * dev_id);
Linus Torvalds's avatar
Linus Torvalds committed
1134
1135

/*
1136
 *	This is specific to the MII interrupt setup of the M5272EVB.
Linus Torvalds's avatar
Linus Torvalds committed
1137
 */
1138
static void __inline__ fec_request_mii_intr(struct net_device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
1139
{
1140
1141
	if (request_irq(66, mii_link_interrupt, IRQF_DISABLED, "fec(MII)", dev) != 0)
		printk("FEC: Could not allocate fec(MII) IRQ(66)!\n");
Linus Torvalds's avatar
Linus Torvalds committed
1142
1143
1144
1145
1146
1147
}

static void __inline__ fec_disable_phy_intr(void)
{
	volatile unsigned long *icrp;
	icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
1148
	*icrp = 0x08000000;
Linus Torvalds's avatar
Linus Torvalds committed
1149
1150
1151
1152
1153
1154
1155
}

static void __inline__ fec_phy_ack_intr(void)
{
	volatile unsigned long *icrp;
	/* Acknowledge the interrupt */
	icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
1156
	*icrp = 0x0d000000;
Linus Torvalds's avatar
Linus Torvalds committed
1157
1158
}

1159
#ifdef CONFIG_M5272
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
static void __inline__ fec_get_mac(struct net_device *dev)
{
	struct fec_enet_private *fep = netdev_priv(dev);
	unsigned char *iap, tmpaddr[ETH_ALEN];

	if (FEC_FLASHMAC) {
		/*
		 * Get MAC address from FLASH.
		 * If it is all 1's or 0's, use the default.
		 */
1170
		iap = (unsigned char *)FEC_FLASHMAC