au1000_eth.c 36.6 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
/*
 *
 * Alchemy Au1x00 ethernet driver
 *
5
 * Copyright 2001-2003, 2006 MontaVista Software Inc.
Linus Torvalds's avatar
Linus Torvalds committed
6
7
8
 * Copyright 2002 TimeSys Corp.
 * Added ethtool/mii-tool support,
 * Copyright 2004 Matt Porter <mporter@kernel.crashing.org>
9
10
 * Update: 2004 Bjoern Riemer, riemer@fokus.fraunhofer.de
 * or riemer@riemer-nt.de: fixed the link beat detection with
Linus Torvalds's avatar
Linus Torvalds committed
11
 * ioctls (SIOCGMIIPHY)
12
13
14
 * Copyright 2006 Herbert Valerio Riedel <hvr@gnu.org>
 *  converted to use linux-2.6.x's PHY framework
 *
Linus Torvalds's avatar
Linus Torvalds committed
15
 * Author: MontaVista Software, Inc.
Florian Fainelli's avatar
Florian Fainelli committed
16
 *		ppopov@mvista.com or source@mvista.com
Linus Torvalds's avatar
Linus Torvalds committed
17
18
19
20
21
22
23
24
25
26
27
28
29
 *
 * ########################################################################
 *
 *  This program is free software; you can distribute it and/or modify it
 *  under the terms of the GNU General Public License (Version 2) as
 *  published by the Free Software Foundation.
 *
 *  This program is distributed in the hope it will be useful, but WITHOUT
 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 *  for more details.
 *
 *  You should have received a copy of the GNU General Public License along
30
 *  with this program; if not, see <http://www.gnu.org/licenses/>.
Linus Torvalds's avatar
Linus Torvalds committed
31
32
33
 *
 * ########################################################################
 *
34
 *
Linus Torvalds's avatar
Linus Torvalds committed
35
 */
36
37
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

38
#include <linux/capability.h>
Ralf Baechle's avatar
Ralf Baechle committed
39
#include <linux/dma-mapping.h>
Linus Torvalds's avatar
Linus Torvalds committed
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/in.h>
#include <linux/ioport.h>
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
56
#include <linux/crc32.h>
57
#include <linux/phy.h>
58
#include <linux/platform_device.h>
59
60
#include <linux/cpu.h>
#include <linux/io.h>
Yoichi Yuasa's avatar
Yoichi Yuasa committed
61

Linus Torvalds's avatar
Linus Torvalds committed
62
63
64
65
#include <asm/mipsregs.h>
#include <asm/irq.h>
#include <asm/processor.h>

Yoichi Yuasa's avatar
Yoichi Yuasa committed
66
#include <au1000.h>
67
#include <au1xxx_eth.h>
Yoichi Yuasa's avatar
Yoichi Yuasa committed
68
69
#include <prom.h>

Linus Torvalds's avatar
Linus Torvalds committed
70
71
72
73
74
75
76
77
#include "au1000_eth.h"

#ifdef AU1000_ETH_DEBUG
static int au1000_debug = 5;
#else
static int au1000_debug = 3;
#endif

78
79
80
81
#define AU1000_DEF_MSG_ENABLE	(NETIF_MSG_DRV	| \
				NETIF_MSG_PROBE	| \
				NETIF_MSG_LINK)

82
#define DRV_NAME	"au1000_eth"
Florian Fainelli's avatar
Florian Fainelli committed
83
#define DRV_VERSION	"1.7"
Linus Torvalds's avatar
Linus Torvalds committed
84
85
86
87
88
89
#define DRV_AUTHOR	"Pete Popov <ppopov@embeddedalley.com>"
#define DRV_DESC	"Au1xxx on-chip Ethernet driver"

MODULE_AUTHOR(DRV_AUTHOR);
MODULE_DESCRIPTION(DRV_DESC);
MODULE_LICENSE("GPL");
90
MODULE_VERSION(DRV_VERSION);
Linus Torvalds's avatar
Linus Torvalds committed
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
/* AU1000 MAC registers and bits */
#define MAC_CONTROL		0x0
#  define MAC_RX_ENABLE		(1 << 2)
#  define MAC_TX_ENABLE		(1 << 3)
#  define MAC_DEF_CHECK		(1 << 5)
#  define MAC_SET_BL(X)		(((X) & 0x3) << 6)
#  define MAC_AUTO_PAD		(1 << 8)
#  define MAC_DISABLE_RETRY	(1 << 10)
#  define MAC_DISABLE_BCAST	(1 << 11)
#  define MAC_LATE_COL		(1 << 12)
#  define MAC_HASH_MODE		(1 << 13)
#  define MAC_HASH_ONLY		(1 << 15)
#  define MAC_PASS_ALL		(1 << 16)
#  define MAC_INVERSE_FILTER	(1 << 17)
#  define MAC_PROMISCUOUS	(1 << 18)
#  define MAC_PASS_ALL_MULTI	(1 << 19)
#  define MAC_FULL_DUPLEX	(1 << 20)
#  define MAC_NORMAL_MODE	0
#  define MAC_INT_LOOPBACK	(1 << 21)
#  define MAC_EXT_LOOPBACK	(1 << 22)
#  define MAC_DISABLE_RX_OWN	(1 << 23)
#  define MAC_BIG_ENDIAN	(1 << 30)
#  define MAC_RX_ALL		(1 << 31)
#define MAC_ADDRESS_HIGH	0x4
#define MAC_ADDRESS_LOW		0x8
#define MAC_MCAST_HIGH		0xC
#define MAC_MCAST_LOW		0x10
#define MAC_MII_CNTRL		0x14
#  define MAC_MII_BUSY		(1 << 0)
#  define MAC_MII_READ		0
#  define MAC_MII_WRITE		(1 << 1)
#  define MAC_SET_MII_SELECT_REG(X) (((X) & 0x1f) << 6)
#  define MAC_SET_MII_SELECT_PHY(X) (((X) & 0x1f) << 11)
#define MAC_MII_DATA		0x18
#define MAC_FLOW_CNTRL		0x1C
#  define MAC_FLOW_CNTRL_BUSY	(1 << 0)
#  define MAC_FLOW_CNTRL_ENABLE (1 << 1)
#  define MAC_PASS_CONTROL	(1 << 2)
#  define MAC_SET_PAUSE(X)	(((X) & 0xffff) << 16)
#define MAC_VLAN1_TAG		0x20
#define MAC_VLAN2_TAG		0x24

/* Ethernet Controller Enable */
#  define MAC_EN_CLOCK_ENABLE	(1 << 0)
#  define MAC_EN_RESET0		(1 << 1)
#  define MAC_EN_TOSS		(0 << 2)
#  define MAC_EN_CACHEABLE	(1 << 3)
#  define MAC_EN_RESET1		(1 << 4)
#  define MAC_EN_RESET2		(1 << 5)
#  define MAC_DMA_RESET		(1 << 6)

/* Ethernet Controller DMA Channels */
/* offsets from MAC_TX_RING_ADDR address */
#define MAC_TX_BUFF0_STATUS	0x0
#  define TX_FRAME_ABORTED	(1 << 0)
#  define TX_JAB_TIMEOUT	(1 << 1)
#  define TX_NO_CARRIER		(1 << 2)
#  define TX_LOSS_CARRIER	(1 << 3)
#  define TX_EXC_DEF		(1 << 4)
#  define TX_LATE_COLL_ABORT	(1 << 5)
#  define TX_EXC_COLL		(1 << 6)
#  define TX_UNDERRUN		(1 << 7)
#  define TX_DEFERRED		(1 << 8)
#  define TX_LATE_COLL		(1 << 9)
#  define TX_COLL_CNT_MASK	(0xF << 10)
#  define TX_PKT_RETRY		(1 << 31)
#define MAC_TX_BUFF0_ADDR	0x4
#  define TX_DMA_ENABLE		(1 << 0)
#  define TX_T_DONE		(1 << 1)
#  define TX_GET_DMA_BUFFER(X)	(((X) >> 2) & 0x3)
#define MAC_TX_BUFF0_LEN	0x8
#define MAC_TX_BUFF1_STATUS	0x10
#define MAC_TX_BUFF1_ADDR	0x14
#define MAC_TX_BUFF1_LEN	0x18
#define MAC_TX_BUFF2_STATUS	0x20
#define MAC_TX_BUFF2_ADDR	0x24
#define MAC_TX_BUFF2_LEN	0x28
#define MAC_TX_BUFF3_STATUS	0x30
#define MAC_TX_BUFF3_ADDR	0x34
#define MAC_TX_BUFF3_LEN	0x38

/* offsets from MAC_RX_RING_ADDR */
#define MAC_RX_BUFF0_STATUS	0x0
#  define RX_FRAME_LEN_MASK	0x3fff
#  define RX_WDOG_TIMER		(1 << 14)
#  define RX_RUNT		(1 << 15)
#  define RX_OVERLEN		(1 << 16)
#  define RX_COLL		(1 << 17)
#  define RX_ETHER		(1 << 18)
#  define RX_MII_ERROR		(1 << 19)
#  define RX_DRIBBLING		(1 << 20)
#  define RX_CRC_ERROR		(1 << 21)
#  define RX_VLAN1		(1 << 22)
#  define RX_VLAN2		(1 << 23)
#  define RX_LEN_ERROR		(1 << 24)
#  define RX_CNTRL_FRAME	(1 << 25)
#  define RX_U_CNTRL_FRAME	(1 << 26)
#  define RX_MCAST_FRAME	(1 << 27)
#  define RX_BCAST_FRAME	(1 << 28)
#  define RX_FILTER_FAIL	(1 << 29)
#  define RX_PACKET_FILTER	(1 << 30)
#  define RX_MISSED_FRAME	(1 << 31)

#  define RX_ERROR (RX_WDOG_TIMER | RX_RUNT | RX_OVERLEN |  \
		    RX_COLL | RX_MII_ERROR | RX_CRC_ERROR | \
		    RX_LEN_ERROR | RX_U_CNTRL_FRAME | RX_MISSED_FRAME)
#define MAC_RX_BUFF0_ADDR	0x4
#  define RX_DMA_ENABLE		(1 << 0)
#  define RX_T_DONE		(1 << 1)
#  define RX_GET_DMA_BUFFER(X)	(((X) >> 2) & 0x3)
#  define RX_SET_BUFF_ADDR(X)	((X) & 0xffffffc0)
#define MAC_RX_BUFF1_STATUS	0x10
#define MAC_RX_BUFF1_ADDR	0x14
#define MAC_RX_BUFF2_STATUS	0x20
#define MAC_RX_BUFF2_ADDR	0x24
#define MAC_RX_BUFF3_STATUS	0x30
#define MAC_RX_BUFF3_ADDR	0x34

Linus Torvalds's avatar
Linus Torvalds committed
210
211
212
/*
 * Theory of operation
 *
213
214
215
 * The Au1000 MACs use a simple rx and tx descriptor ring scheme.
 * There are four receive and four transmit descriptors.  These
 * descriptors are not in memory; rather, they are just a set of
Linus Torvalds's avatar
Linus Torvalds committed
216
217
218
 * hardware registers.
 *
 * Since the Au1000 has a coherent data cache, the receive and
219
 * transmit buffers are allocated from the KSEG0 segment. The
Linus Torvalds's avatar
Linus Torvalds committed
220
221
222
223
224
 * hardware registers, however, are still mapped at KSEG1 to
 * make sure there's no out-of-order writes, and that all writes
 * complete immediately.
 */

225
226
227
228
229
/*
 * board-specific configurations
 *
 * PHY detection algorithm
 *
230
 * If phy_static_config is undefined, the PHY setup is
231
232
233
 * autodetected:
 *
 * mii_probe() first searches the current MAC's MII bus for a PHY,
234
 * selecting the first (or last, if phy_search_highest_addr is
235
236
237
 * defined) PHY address not already claimed by another netdev.
 *
 * If nothing was found that way when searching for the 2nd ethernet
238
 * controller's PHY and phy1_search_mac0 is defined, then
239
240
241
242
243
244
 * the first MII bus is searched as well for an unclaimed PHY; this is
 * needed in case of a dual-PHY accessible only through the MAC0's MII
 * bus.
 *
 * Finally, if no PHY is found, then the corresponding ethernet
 * controller is not registered to the network subsystem.
Linus Torvalds's avatar
Linus Torvalds committed
245
246
 */

247
/* autodetection defaults: phy1_search_mac0 */
Linus Torvalds's avatar
Linus Torvalds committed
248

249
250
251
252
253
254
255
256
257
258
259
260
261
262
/* static PHY setup
 *
 * most boards PHY setup should be detectable properly with the
 * autodetection algorithm in mii_probe(), but in some cases (e.g. if
 * you have a switch attached, or want to use the PHY's interrupt
 * notification capabilities) you can provide a static PHY
 * configuration here
 *
 * IRQs may only be set, if a PHY address was configured
 * If a PHY address is given, also a bus id is required to be set
 *
 * ps: make sure the used irqs are configured properly in the board
 * specific irq-map
 */
Linus Torvalds's avatar
Linus Torvalds committed
263

264
static void au1000_enable_mac(struct net_device *dev, int force_reset)
Florian Fainelli's avatar
Florian Fainelli committed
265
266
267
268
269
270
{
	unsigned long flags;
	struct au1000_private *aup = netdev_priv(dev);

	spin_lock_irqsave(&aup->lock, flags);

Florian Fainelli's avatar
Florian Fainelli committed
271
	if (force_reset || (!aup->mac_enabled)) {
272
		writel(MAC_EN_CLOCK_ENABLE, aup->enable);
273
274
		wmb(); /* drain writebuffer */
		mdelay(2);
275
		writel((MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2
276
				| MAC_EN_CLOCK_ENABLE), aup->enable);
277
278
		wmb(); /* drain writebuffer */
		mdelay(2);
Florian Fainelli's avatar
Florian Fainelli committed
279
280
281
282
283
284
285

		aup->mac_enabled = 1;
	}

	spin_unlock_irqrestore(&aup->lock, flags);
}

286
287
288
/*
 * MII operations
 */
289
static int au1000_mdio_read(struct net_device *dev, int phy_addr, int reg)
Linus Torvalds's avatar
Linus Torvalds committed
290
{
291
	struct au1000_private *aup = netdev_priv(dev);
292
293
	u32 *const mii_control_reg = &aup->mac->mii_control;
	u32 *const mii_data_reg = &aup->mac->mii_data;
Linus Torvalds's avatar
Linus Torvalds committed
294
295
296
	u32 timedout = 20;
	u32 mii_control;

297
	while (readl(mii_control_reg) & MAC_MII_BUSY) {
Linus Torvalds's avatar
Linus Torvalds committed
298
299
		mdelay(1);
		if (--timedout == 0) {
300
			netdev_err(dev, "read_MII busy timeout!!\n");
Linus Torvalds's avatar
Linus Torvalds committed
301
302
303
304
			return -1;
		}
	}

305
	mii_control = MAC_SET_MII_SELECT_REG(reg) |
306
		MAC_SET_MII_SELECT_PHY(phy_addr) | MAC_MII_READ;
Linus Torvalds's avatar
Linus Torvalds committed
307

308
	writel(mii_control, mii_control_reg);
Linus Torvalds's avatar
Linus Torvalds committed
309
310

	timedout = 20;
311
	while (readl(mii_control_reg) & MAC_MII_BUSY) {
Linus Torvalds's avatar
Linus Torvalds committed
312
313
		mdelay(1);
		if (--timedout == 0) {
314
			netdev_err(dev, "mdio_read busy timeout!!\n");
Linus Torvalds's avatar
Linus Torvalds committed
315
316
317
			return -1;
		}
	}
318
	return readl(mii_data_reg);
Linus Torvalds's avatar
Linus Torvalds committed
319
320
}

321
322
static void au1000_mdio_write(struct net_device *dev, int phy_addr,
			      int reg, u16 value)
Linus Torvalds's avatar
Linus Torvalds committed
323
{
324
	struct au1000_private *aup = netdev_priv(dev);
325
326
	u32 *const mii_control_reg = &aup->mac->mii_control;
	u32 *const mii_data_reg = &aup->mac->mii_data;
Linus Torvalds's avatar
Linus Torvalds committed
327
328
329
	u32 timedout = 20;
	u32 mii_control;

330
	while (readl(mii_control_reg) & MAC_MII_BUSY) {
Linus Torvalds's avatar
Linus Torvalds committed
331
332
		mdelay(1);
		if (--timedout == 0) {
333
			netdev_err(dev, "mdio_write busy timeout!!\n");
Linus Torvalds's avatar
Linus Torvalds committed
334
335
336
337
			return;
		}
	}

338
	mii_control = MAC_SET_MII_SELECT_REG(reg) |
339
		MAC_SET_MII_SELECT_PHY(phy_addr) | MAC_MII_WRITE;
Linus Torvalds's avatar
Linus Torvalds committed
340

341
342
	writel(value, mii_data_reg);
	writel(mii_control, mii_control_reg);
Linus Torvalds's avatar
Linus Torvalds committed
343
344
}

345
static int au1000_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
346
347
348
{
	struct net_device *const dev = bus->priv;

349
350
351
352
353
	/* make sure the MAC associated with this
	 * mii_bus is enabled
	 */
	au1000_enable_mac(dev, 0);

354
	return au1000_mdio_read(dev, phy_addr, regnum);
355
}
Linus Torvalds's avatar
Linus Torvalds committed
356

357
358
static int au1000_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
				u16 value)
Linus Torvalds's avatar
Linus Torvalds committed
359
{
360
	struct net_device *const dev = bus->priv;
Linus Torvalds's avatar
Linus Torvalds committed
361

362
363
364
365
366
	/* make sure the MAC associated with this
	 * mii_bus is enabled
	 */
	au1000_enable_mac(dev, 0);

367
	au1000_mdio_write(dev, phy_addr, regnum, value);
368
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
369
370
}

371
static int au1000_mdiobus_reset(struct mii_bus *bus)
Linus Torvalds's avatar
Linus Torvalds committed
372
{
373
	struct net_device *const dev = bus->priv;
Linus Torvalds's avatar
Linus Torvalds committed
374

375
376
377
378
379
	/* make sure the MAC associated with this
	 * mii_bus is enabled
	 */
	au1000_enable_mac(dev, 0);

380
381
	return 0;
}
Linus Torvalds's avatar
Linus Torvalds committed
382

383
static void au1000_hard_stop(struct net_device *dev)
Florian Fainelli's avatar
Florian Fainelli committed
384
385
{
	struct au1000_private *aup = netdev_priv(dev);
386
	u32 reg;
Florian Fainelli's avatar
Florian Fainelli committed
387

388
	netif_dbg(aup, drv, dev, "hard stop\n");
Florian Fainelli's avatar
Florian Fainelli committed
389

390
391
392
	reg = readl(&aup->mac->control);
	reg &= ~(MAC_RX_ENABLE | MAC_TX_ENABLE);
	writel(reg, &aup->mac->control);
393
394
	wmb(); /* drain writebuffer */
	mdelay(10);
Florian Fainelli's avatar
Florian Fainelli committed
395
396
}

397
static void au1000_enable_rx_tx(struct net_device *dev)
Florian Fainelli's avatar
Florian Fainelli committed
398
399
{
	struct au1000_private *aup = netdev_priv(dev);
400
	u32 reg;
Florian Fainelli's avatar
Florian Fainelli committed
401

402
	netif_dbg(aup, hw, dev, "enable_rx_tx\n");
Florian Fainelli's avatar
Florian Fainelli committed
403

404
405
406
	reg = readl(&aup->mac->control);
	reg |= (MAC_RX_ENABLE | MAC_TX_ENABLE);
	writel(reg, &aup->mac->control);
407
408
	wmb(); /* drain writebuffer */
	mdelay(10);
Florian Fainelli's avatar
Florian Fainelli committed
409
410
411
412
413
414
415
416
}

static void
au1000_adjust_link(struct net_device *dev)
{
	struct au1000_private *aup = netdev_priv(dev);
	struct phy_device *phydev = aup->phy_dev;
	unsigned long flags;
417
	u32 reg;
Florian Fainelli's avatar
Florian Fainelli committed
418
419
420
421
422
423
424
425

	int status_change = 0;

	BUG_ON(!aup->phy_dev);

	spin_lock_irqsave(&aup->lock, flags);

	if (phydev->link && (aup->old_speed != phydev->speed)) {
426
		/* speed changed */
Florian Fainelli's avatar
Florian Fainelli committed
427

428
		switch (phydev->speed) {
Florian Fainelli's avatar
Florian Fainelli committed
429
430
431
432
		case SPEED_10:
		case SPEED_100:
			break;
		default:
433
434
			netdev_warn(dev, "Speed (%d) is not 10/100 ???\n",
							phydev->speed);
Florian Fainelli's avatar
Florian Fainelli committed
435
436
437
438
439
440
441
442
443
			break;
		}

		aup->old_speed = phydev->speed;

		status_change = 1;
	}

	if (phydev->link && (aup->old_duplex != phydev->duplex)) {
444
		/* duplex mode changed */
Florian Fainelli's avatar
Florian Fainelli committed
445
446

		/* switching duplex mode requires to disable rx and tx! */
447
		au1000_hard_stop(dev);
Florian Fainelli's avatar
Florian Fainelli committed
448

449
450
451
452
453
454
455
456
457
		reg = readl(&aup->mac->control);
		if (DUPLEX_FULL == phydev->duplex) {
			reg |= MAC_FULL_DUPLEX;
			reg &= ~MAC_DISABLE_RX_OWN;
		} else {
			reg &= ~MAC_FULL_DUPLEX;
			reg |= MAC_DISABLE_RX_OWN;
		}
		writel(reg, &aup->mac->control);
458
459
		wmb(); /* drain writebuffer */
		mdelay(1);
Florian Fainelli's avatar
Florian Fainelli committed
460

461
		au1000_enable_rx_tx(dev);
Florian Fainelli's avatar
Florian Fainelli committed
462
463
464
465
466
		aup->old_duplex = phydev->duplex;

		status_change = 1;
	}

467
468
	if (phydev->link != aup->old_link) {
		/* link state changed */
Florian Fainelli's avatar
Florian Fainelli committed
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483

		if (!phydev->link) {
			/* link went down */
			aup->old_speed = 0;
			aup->old_duplex = -1;
		}

		aup->old_link = phydev->link;
		status_change = 1;
	}

	spin_unlock_irqrestore(&aup->lock, flags);

	if (status_change) {
		if (phydev->link)
484
485
			netdev_info(dev, "link up (%d/%s)\n",
			       phydev->speed,
Florian Fainelli's avatar
Florian Fainelli committed
486
487
			       DUPLEX_FULL == phydev->duplex ? "Full" : "Half");
		else
488
			netdev_info(dev, "link down\n");
Florian Fainelli's avatar
Florian Fainelli committed
489
490
491
	}
}

Florian Fainelli's avatar
Florian Fainelli committed
492
static int au1000_mii_probe(struct net_device *dev)
493
{
494
	struct au1000_private *const aup = netdev_priv(dev);
495
	struct phy_device *phydev = NULL;
496
	int phy_addr;
497

498
499
	if (aup->phy_static_config) {
		BUG_ON(aup->mac_id < 0 || aup->mac_id > 1);
500

501
		if (aup->phy_addr)
502
			phydev = mdiobus_get_phy(aup->mii_bus, aup->phy_addr);
503
		else
504
			netdev_info(dev, "using PHY-less setup\n");
505
		return 0;
506
	}
507

508
	/* find the first (lowest address) PHY
509
510
	 * on the current MAC's MII bus
	 */
511
	for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++)
512
513
		if (mdiobus_get_phy(aup->mii_bus, aup->phy_addr)) {
			phydev = mdiobus_get_phy(aup->mii_bus, aup->phy_addr);
514
515
516
517
			if (!aup->phy_search_highest_addr)
				/* break out with first one found */
				break;
		}
518

519
520
521
522
523
524
525
526
527
528
529
530
	if (aup->phy1_search_mac0) {
		/* try harder to find a PHY */
		if (!phydev && (aup->mac_id == 1)) {
			/* no PHY found, maybe we have a dual PHY? */
			dev_info(&dev->dev, ": no PHY found on MAC1, "
				"let's see if it's attached to MAC0...\n");

			/* find the first (lowest address) non-attached
			 * PHY on the MAC0 MII bus
			 */
			for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
				struct phy_device *const tmp_phydev =
531
532
					mdiobus_get_phy(aup->mii_bus,
							phy_addr);
533
534
535
536
537
538
539
540
541
542
543
544
545
546

				if (aup->mac_id == 1)
					break;

				/* no PHY here... */
				if (!tmp_phydev)
					continue;

				/* already claimed by MAC0 */
				if (tmp_phydev->attached_dev)
					continue;

				phydev = tmp_phydev;
				break; /* found it */
547
			}
Linus Torvalds's avatar
Linus Torvalds committed
548
549
550
		}
	}

551
	if (!phydev) {
552
		netdev_err(dev, "no PHY found\n");
Linus Torvalds's avatar
Linus Torvalds committed
553
554
555
		return -1;
	}

556
557
558
	/* now we are supposed to have a proper phydev, to attach to... */
	BUG_ON(phydev->attached_dev);

Andrew Lunn's avatar
Andrew Lunn committed
559
	phydev = phy_connect(dev, phydev_name(phydev),
560
			     &au1000_adjust_link, PHY_INTERFACE_MODE_MII);
561
562

	if (IS_ERR(phydev)) {
563
		netdev_err(dev, "Could not attach to PHY\n");
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
		return PTR_ERR(phydev);
	}

	/* mask with MAC supported features */
	phydev->supported &= (SUPPORTED_10baseT_Half
			      | SUPPORTED_10baseT_Full
			      | SUPPORTED_100baseT_Half
			      | SUPPORTED_100baseT_Full
			      | SUPPORTED_Autoneg
			      /* | SUPPORTED_Pause | SUPPORTED_Asym_Pause */
			      | SUPPORTED_MII
			      | SUPPORTED_TP);

	phydev->advertising = phydev->supported;

	aup->old_link = 0;
	aup->old_speed = 0;
	aup->old_duplex = -1;
	aup->phy_dev = phydev;

584
	phy_attached_info(phydev);
Linus Torvalds's avatar
Linus Torvalds committed
585
586
587
588
589
590
591

	return 0;
}


/*
 * Buffer allocation/deallocation routines. The buffer descriptor returned
592
 * has the virtual and dma address of a buffer suitable for
Linus Torvalds's avatar
Linus Torvalds committed
593
594
 * both, receive and transmit operations.
 */
595
static struct db_dest *au1000_GetFreeDB(struct au1000_private *aup)
Linus Torvalds's avatar
Linus Torvalds committed
596
{
597
	struct db_dest *pDB;
Linus Torvalds's avatar
Linus Torvalds committed
598
599
	pDB = aup->pDBfree;

Florian Fainelli's avatar
Florian Fainelli committed
600
	if (pDB)
Linus Torvalds's avatar
Linus Torvalds committed
601
		aup->pDBfree = pDB->pnext;
Florian Fainelli's avatar
Florian Fainelli committed
602

Linus Torvalds's avatar
Linus Torvalds committed
603
604
605
	return pDB;
}

606
void au1000_ReleaseDB(struct au1000_private *aup, struct db_dest *pDB)
Linus Torvalds's avatar
Linus Torvalds committed
607
{
608
	struct db_dest *pDBfree = aup->pDBfree;
Linus Torvalds's avatar
Linus Torvalds committed
609
610
611
612
613
	if (pDBfree)
		pDBfree->pnext = pDB;
	aup->pDBfree = pDB;
}

614
static void au1000_reset_mac_unlocked(struct net_device *dev)
615
{
616
	struct au1000_private *const aup = netdev_priv(dev);
617
618
	int i;

619
	au1000_hard_stop(dev);
620

621
	writel(MAC_EN_CLOCK_ENABLE, aup->enable);
622
623
	wmb(); /* drain writebuffer */
	mdelay(2);
624
	writel(0, aup->enable);
625
626
	wmb(); /* drain writebuffer */
	mdelay(2);
627

Linus Torvalds's avatar
Linus Torvalds committed
628
629
630
631
632
633
634
635
636
	aup->tx_full = 0;
	for (i = 0; i < NUM_RX_DMA; i++) {
		/* reset control bits */
		aup->rx_dma_ring[i]->buff_stat &= ~0xf;
	}
	for (i = 0; i < NUM_TX_DMA; i++) {
		/* reset control bits */
		aup->tx_dma_ring[i]->buff_stat &= ~0xf;
	}
637
638
639

	aup->mac_enabled = 0;

Linus Torvalds's avatar
Linus Torvalds committed
640
641
}

642
static void au1000_reset_mac(struct net_device *dev)
643
{
644
	struct au1000_private *const aup = netdev_priv(dev);
645
646
	unsigned long flags;

647
648
	netif_dbg(aup, hw, dev, "reset mac, aup %x\n",
					(unsigned)aup);
649
650
651

	spin_lock_irqsave(&aup->lock, flags);

Florian Fainelli's avatar
Florian Fainelli committed
652
	au1000_reset_mac_unlocked(dev);
653
654
655

	spin_unlock_irqrestore(&aup->lock, flags);
}
Linus Torvalds's avatar
Linus Torvalds committed
656

657
/*
Linus Torvalds's avatar
Linus Torvalds committed
658
659
660
661
 * Setup the receive and transmit "rings".  These pointers are the addresses
 * of the rx and tx MAC DMA registers so they are fixed by the hardware --
 * these are not descriptors sitting in memory.
 */
662
static void
663
au1000_setup_hw_rings(struct au1000_private *aup, void __iomem *tx_base)
Linus Torvalds's avatar
Linus Torvalds committed
664
665
666
667
{
	int i;

	for (i = 0; i < NUM_RX_DMA; i++) {
668
669
		aup->rx_dma_ring[i] = (struct rx_dma *)
			(tx_base + 0x100 + sizeof(struct rx_dma) * i);
Linus Torvalds's avatar
Linus Torvalds committed
670
671
	}
	for (i = 0; i < NUM_TX_DMA; i++) {
672
673
		aup->tx_dma_ring[i] = (struct tx_dma *)
			(tx_base + sizeof(struct tx_dma) * i);
Linus Torvalds's avatar
Linus Torvalds committed
674
675
676
	}
}

677
678
679
/*
 * ethtool operations
 */
Linus Torvalds's avatar
Linus Torvalds committed
680

681
static int au1000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
Linus Torvalds's avatar
Linus Torvalds committed
682
{
683
	struct au1000_private *aup = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
684

685
686
	if (aup->phy_dev)
		return phy_ethtool_gset(aup->phy_dev, cmd);
Linus Torvalds's avatar
Linus Torvalds committed
687

688
	return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
689
690
}

691
static int au1000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
Linus Torvalds's avatar
Linus Torvalds committed
692
{
693
	struct au1000_private *aup = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
694

695
696
	if (!capable(CAP_NET_ADMIN))
		return -EPERM;
Linus Torvalds's avatar
Linus Torvalds committed
697

698
699
	if (aup->phy_dev)
		return phy_ethtool_sset(aup->phy_dev, cmd);
Linus Torvalds's avatar
Linus Torvalds committed
700

701
	return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
702
703
704
705
706
}

static void
au1000_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
707
	struct au1000_private *aup = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
708

709
710
711
712
	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
	snprintf(info->bus_info, sizeof(info->bus_info), "%s %d", DRV_NAME,
		 aup->mac_id);
Linus Torvalds's avatar
Linus Torvalds committed
713
714
}

715
716
717
718
719
720
721
722
723
724
725
726
static void au1000_set_msglevel(struct net_device *dev, u32 value)
{
	struct au1000_private *aup = netdev_priv(dev);
	aup->msg_enable = value;
}

static u32 au1000_get_msglevel(struct net_device *dev)
{
	struct au1000_private *aup = netdev_priv(dev);
	return aup->msg_enable;
}

727
static const struct ethtool_ops au1000_ethtool_ops = {
Linus Torvalds's avatar
Linus Torvalds committed
728
729
730
	.get_settings = au1000_get_settings,
	.set_settings = au1000_set_settings,
	.get_drvinfo = au1000_get_drvinfo,
731
	.get_link = ethtool_op_get_link,
732
733
	.get_msglevel = au1000_get_msglevel,
	.set_msglevel = au1000_set_msglevel,
Linus Torvalds's avatar
Linus Torvalds committed
734
735
};

Florian Fainelli's avatar
Florian Fainelli committed
736
737
738
739
740
741
742
743
744
745
746

/*
 * Initialize the interface.
 *
 * When the device powers up, the clocks are disabled and the
 * mac is in reset state.  When the interface is closed, we
 * do the same -- reset the device and disable the clocks to
 * conserve power. Thus, whenever au1000_init() is called,
 * the device should already be in reset state.
 */
static int au1000_init(struct net_device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
747
{
Florian Fainelli's avatar
Florian Fainelli committed
748
749
750
751
	struct au1000_private *aup = netdev_priv(dev);
	unsigned long flags;
	int i;
	u32 control;
752

753
	netif_dbg(aup, hw, dev, "au1000_init\n");
Linus Torvalds's avatar
Linus Torvalds committed
754

Florian Fainelli's avatar
Florian Fainelli committed
755
	/* bring the device out of reset */
756
	au1000_enable_mac(dev, 1);
757

Florian Fainelli's avatar
Florian Fainelli committed
758
	spin_lock_irqsave(&aup->lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
759

760
	writel(0, &aup->mac->control);
Florian Fainelli's avatar
Florian Fainelli committed
761
762
763
	aup->tx_head = (aup->tx_dma_ring[0]->buff_stat & 0xC) >> 2;
	aup->tx_tail = aup->tx_head;
	aup->rx_head = (aup->rx_dma_ring[0]->buff_stat & 0xC) >> 2;
Linus Torvalds's avatar
Linus Torvalds committed
764

765
766
767
768
769
	writel(dev->dev_addr[5]<<8 | dev->dev_addr[4],
					&aup->mac->mac_addr_high);
	writel(dev->dev_addr[3]<<24 | dev->dev_addr[2]<<16 |
		dev->dev_addr[1]<<8 | dev->dev_addr[0],
					&aup->mac->mac_addr_low);
Florian Fainelli's avatar
Florian Fainelli committed
770

771

Florian Fainelli's avatar
Florian Fainelli committed
772
	for (i = 0; i < NUM_RX_DMA; i++)
Florian Fainelli's avatar
Florian Fainelli committed
773
		aup->rx_dma_ring[i]->buff_stat |= RX_DMA_ENABLE;
Florian Fainelli's avatar
Florian Fainelli committed
774

775
	wmb(); /* drain writebuffer */
Linus Torvalds's avatar
Linus Torvalds committed
776

Florian Fainelli's avatar
Florian Fainelli committed
777
778
779
780
781
782
783
784
785
786
787
	control = MAC_RX_ENABLE | MAC_TX_ENABLE;
#ifndef CONFIG_CPU_LITTLE_ENDIAN
	control |= MAC_BIG_ENDIAN;
#endif
	if (aup->phy_dev) {
		if (aup->phy_dev->link && (DUPLEX_FULL == aup->phy_dev->duplex))
			control |= MAC_FULL_DUPLEX;
		else
			control |= MAC_DISABLE_RX_OWN;
	} else { /* PHY-less op, assume full-duplex */
		control |= MAC_FULL_DUPLEX;
Linus Torvalds's avatar
Linus Torvalds committed
788
789
	}

790
791
	writel(control, &aup->mac->control);
	writel(0x8100, &aup->mac->vlan1_tag); /* activate vlan support */
792
	wmb(); /* drain writebuffer */
Linus Torvalds's avatar
Linus Torvalds committed
793

Florian Fainelli's avatar
Florian Fainelli committed
794
795
796
	spin_unlock_irqrestore(&aup->lock, flags);
	return 0;
}
Linus Torvalds's avatar
Linus Torvalds committed
797

798
static inline void au1000_update_rx_stats(struct net_device *dev, u32 status)
Florian Fainelli's avatar
Florian Fainelli committed
799
800
{
	struct net_device_stats *ps = &dev->stats;
Linus Torvalds's avatar
Linus Torvalds committed
801

Florian Fainelli's avatar
Florian Fainelli committed
802
803
804
	ps->rx_packets++;
	if (status & RX_MCAST_FRAME)
		ps->multicast++;
Linus Torvalds's avatar
Linus Torvalds committed
805

Florian Fainelli's avatar
Florian Fainelli committed
806
807
808
809
	if (status & RX_ERROR) {
		ps->rx_errors++;
		if (status & RX_MISSED_FRAME)
			ps->rx_missed_errors++;
810
		if (status & (RX_OVERLEN | RX_RUNT | RX_LEN_ERROR))
Florian Fainelli's avatar
Florian Fainelli committed
811
812
813
814
815
			ps->rx_length_errors++;
		if (status & RX_CRC_ERROR)
			ps->rx_crc_errors++;
		if (status & RX_COLL)
			ps->collisions++;
816
	} else
Florian Fainelli's avatar
Florian Fainelli committed
817
		ps->rx_bytes += status & RX_FRAME_LEN_MASK;
818

Linus Torvalds's avatar
Linus Torvalds committed
819
820
}

821
/*
Florian Fainelli's avatar
Florian Fainelli committed
822
 * Au1000 receive routine.
Linus Torvalds's avatar
Linus Torvalds committed
823
 */
Florian Fainelli's avatar
Florian Fainelli committed
824
static int au1000_rx(struct net_device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
825
{
826
	struct au1000_private *aup = netdev_priv(dev);
Florian Fainelli's avatar
Florian Fainelli committed
827
	struct sk_buff *skb;
828
	struct rx_dma *prxd;
Florian Fainelli's avatar
Florian Fainelli committed
829
	u32 buff_stat, status;
830
	struct db_dest *pDB;
Florian Fainelli's avatar
Florian Fainelli committed
831
	u32	frmlen;
Linus Torvalds's avatar
Linus Torvalds committed
832

833
	netif_dbg(aup, rx_status, dev, "au1000_rx head %d\n", aup->rx_head);
Linus Torvalds's avatar
Linus Torvalds committed
834

Florian Fainelli's avatar
Florian Fainelli committed
835
836
837
838
839
	prxd = aup->rx_dma_ring[aup->rx_head];
	buff_stat = prxd->buff_stat;
	while (buff_stat & RX_T_DONE)  {
		status = prxd->status;
		pDB = aup->rx_db_inuse[aup->rx_head];
840
		au1000_update_rx_stats(dev, status);
Florian Fainelli's avatar
Florian Fainelli committed
841
		if (!(status & RX_ERROR))  {
Linus Torvalds's avatar
Linus Torvalds committed
842

Florian Fainelli's avatar
Florian Fainelli committed
843
844
845
			/* good frame */
			frmlen = (status & RX_FRAME_LEN_MASK);
			frmlen -= 4; /* Remove FCS */
846
			skb = netdev_alloc_skb(dev, frmlen + 2);
Florian Fainelli's avatar
Florian Fainelli committed
847
848
849
850
851
852
853
854
855
856
			if (skb == NULL) {
				dev->stats.rx_dropped++;
				continue;
			}
			skb_reserve(skb, 2);	/* 16 byte IP header align */
			skb_copy_to_linear_data(skb,
				(unsigned char *)pDB->vaddr, frmlen);
			skb_put(skb, frmlen);
			skb->protocol = eth_type_trans(skb, dev);
			netif_rx(skb);	/* pass the packet to upper layers */
857
		} else {
Florian Fainelli's avatar
Florian Fainelli committed
858
			if (au1000_debug > 4) {
859
				pr_err("rx_error(s):");
Florian Fainelli's avatar
Florian Fainelli committed
860
				if (status & RX_MISSED_FRAME)
861
					pr_cont(" miss");
Florian Fainelli's avatar
Florian Fainelli committed
862
				if (status & RX_WDOG_TIMER)
863
					pr_cont(" wdog");
Florian Fainelli's avatar
Florian Fainelli committed
864
				if (status & RX_RUNT)
865
					pr_cont(" runt");
Florian Fainelli's avatar
Florian Fainelli committed
866
				if (status & RX_OVERLEN)
867
					pr_cont(" overlen");
Florian Fainelli's avatar
Florian Fainelli committed
868
				if (status & RX_COLL)
869
					pr_cont(" coll");
Florian Fainelli's avatar
Florian Fainelli committed
870
				if (status & RX_MII_ERROR)
871
					pr_cont(" mii error");
Florian Fainelli's avatar
Florian Fainelli committed
872
				if (status & RX_CRC_ERROR)
873
					pr_cont(" crc error");
Florian Fainelli's avatar
Florian Fainelli committed
874
				if (status & RX_LEN_ERROR)
875
					pr_cont(" len error");
Florian Fainelli's avatar
Florian Fainelli committed
876
				if (status & RX_U_CNTRL_FRAME)
877
878
					pr_cont(" u control frame");
				pr_cont("\n");
Florian Fainelli's avatar
Florian Fainelli committed
879
880
881
882
			}
		}
		prxd->buff_stat = (u32)(pDB->dma_addr | RX_DMA_ENABLE);
		aup->rx_head = (aup->rx_head + 1) & (NUM_RX_DMA - 1);
883
		wmb(); /* drain writebuffer */
Linus Torvalds's avatar
Linus Torvalds committed
884

Florian Fainelli's avatar
Florian Fainelli committed
885
886
887
		/* next descriptor */
		prxd = aup->rx_dma_ring[aup->rx_head];
		buff_stat = prxd->buff_stat;
Linus Torvalds's avatar
Linus Torvalds committed
888
889
890
891
	}
	return 0;
}

892
static void au1000_update_tx_stats(struct net_device *dev, u32 status)
Linus Torvalds's avatar
Linus Torvalds committed
893
{
894
	struct au1000_private *aup = netdev_priv(dev);
Florian Fainelli's avatar
Florian Fainelli committed
895
	struct net_device_stats *ps = &dev->stats;
896

Florian Fainelli's avatar
Florian Fainelli committed
897
898
899
900
	if (status & TX_FRAME_ABORTED) {
		if (!aup->phy_dev || (DUPLEX_FULL == aup->phy_dev->duplex)) {
			if (status & (TX_JAB_TIMEOUT | TX_UNDERRUN)) {
				/* any other tx errors are only valid
901
902
				 * in half duplex mode
				 */
Florian Fainelli's avatar
Florian Fainelli committed
903
904
905
				ps->tx_errors++;
				ps->tx_aborted_errors++;
			}
906
		} else {
Florian Fainelli's avatar
Florian Fainelli committed
907
908
909
910
911
912
913
			ps->tx_errors++;
			ps->tx_aborted_errors++;
			if (status & (TX_NO_CARRIER | TX_LOSS_CARRIER))
				ps->tx_carrier_errors++;
		}
	}
}
914

Florian Fainelli's avatar
Florian Fainelli committed
915
916
917
918
919
920
921
922
/*
 * Called from the interrupt service routine to acknowledge
 * the TX DONE bits.  This is a must if the irq is setup as
 * edge triggered.
 */
static void au1000_tx_ack(struct net_device *dev)
{
	struct au1000_private *aup = netdev_priv(dev);
923
	struct tx_dma *ptxd;
924

Florian Fainelli's avatar
Florian Fainelli committed
925
	ptxd = aup->tx_dma_ring[aup->tx_tail];
926

Florian Fainelli's avatar
Florian Fainelli committed
927
	while (ptxd->buff_stat & TX_T_DONE) {
928
		au1000_update_tx_stats(dev, ptxd->status);
Florian Fainelli's avatar
Florian Fainelli committed
929
930
		ptxd->buff_stat &= ~TX_T_DONE;
		ptxd->len = 0;
931
		wmb(); /* drain writebuffer */
932

Florian Fainelli's avatar
Florian Fainelli committed
933
934
		aup->tx_tail = (aup->tx_tail + 1) & (NUM_TX_DMA - 1);
		ptxd = aup->tx_dma_ring[aup->tx_tail];
935

Florian Fainelli's avatar
Florian Fainelli committed
936
937
938
939
		if (aup->tx_full) {
			aup->tx_full = 0;
			netif_wake_queue(dev);
		}
Linus Torvalds's avatar
Linus Torvalds committed
940
	}
Florian Fainelli's avatar
Florian Fainelli committed
941
}
Linus Torvalds's avatar
Linus Torvalds committed
942

Florian Fainelli's avatar
Florian Fainelli committed
943
944
945
946
947
948
/*
 * Au1000 interrupt service routine.
 */
static irqreturn_t au1000_interrupt(int irq, void *dev_id)
{
	struct net_device *dev = dev_id;
Linus Torvalds's avatar
Linus Torvalds committed
949

Florian Fainelli's avatar
Florian Fainelli committed
950
951
952
953
954
	/* Handle RX interrupts first to minimize chance of overrun */

	au1000_rx(dev);
	au1000_tx_ack(dev);
	return IRQ_RETVAL(1);
Linus Torvalds's avatar
Linus Torvalds committed
955
956
957
958
959
}

static int au1000_open(struct net_device *dev)
{
	int retval;
960
	struct au1000_private *aup = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
961

962
	netif_dbg(aup, drv, dev, "open: dev=%p\n", dev);
Linus Torvalds's avatar
Linus Torvalds committed
963

964
965
966
	retval = request_irq(dev->irq, au1000_interrupt, 0,
					dev->name, dev);
	if (retval) {
967
		netdev_err(dev, "unable to get IRQ %d\n", dev->irq);
968
969
970
		return retval;
	}

971
972
	retval = au1000_init(dev);
	if (retval) {
973
		netdev_err(dev, "error in au1000_init\n");
Linus Torvalds's avatar
Linus Torvalds committed
974
975
976
977
		free_irq(dev->irq, dev);
		return retval;
	}

978
979
980
981
	if (aup->phy_dev) {
		/* cause the PHY state machine to schedule a link state check */
		aup->phy_dev->state = PHY_CHANGELINK;
		phy_start(aup->phy_dev);
Linus Torvalds's avatar
Linus Torvalds committed
982
983
	}

984
	netif_start_queue(dev);
Linus Torvalds's avatar
Linus Torvalds committed
985

986
	netif_dbg(aup, drv, dev, "open: Initialization done.\n");
Linus Torvalds's avatar
Linus Torvalds committed
987
988
989
990
991
992

	return 0;
}

static int au1000_close(struct net_device *dev)
{
993
	unsigned long flags;
994
	struct au1000_private *const aup = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
995

996
	netif_dbg(aup, drv, dev, "close: dev=%p\n", dev);
Linus Torvalds's avatar
Linus Torvalds committed
997

998
999
	if (aup->phy_dev)
		phy_stop(aup->phy_dev);
Linus Torvalds's avatar
Linus Torvalds committed
1000
1001

	spin_lock_irqsave(&aup->lock, flags);
1002

Florian Fainelli's avatar
Florian Fainelli committed
1003
	au1000_reset_mac_unlocked(dev);
1004

Linus Torvalds's avatar
Linus Torvalds committed
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
	/* stop the device */
	netif_stop_queue(dev);

	/* disable the interrupt */
	free_irq(dev->irq, dev);
	spin_unlock_irqrestore(&aup->lock, flags);

	return 0;
}

/*
 * Au1000 transmit routine.
 */
1018
static netdev_tx_t au1000_tx(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
1019
{
1020
	struct au1000_private *aup = netdev_priv(dev);
1021
	struct net_device_stats *ps = &dev->stats;
1022
	struct tx_dma *ptxd;
Linus Torvalds's avatar
Linus Torvalds committed
1023
	u32 buff_stat;
1024
	struct db_dest *pDB;
Linus Torvalds's avatar
Linus Torvalds committed
1025
1026
	int i;

1027
1028
	netif_dbg(aup, tx_queued, dev, "tx: aup %x len=%d, data=%p, head %d\n",
				(unsigned)aup, skb->len,
Linus Torvalds's avatar
Linus Torvalds committed
1029
1030
1031
1032
1033
1034
1035
1036
				skb->data, aup->tx_head);

	ptxd = aup->tx_dma_ring[aup->tx_head];
	buff_stat = ptxd->buff_stat;
	if (buff_stat & TX_DMA_ENABLE) {
		/* We've wrapped around and the transmitter is still busy */
		netif_stop_queue(dev);
		aup->tx_full = 1;
1037
		return NETDEV_TX_BUSY;
1038
	} else if (buff_stat & TX_T_DONE) {
1039
		au1000_update_tx_stats(dev, ptxd->status);
Linus Torvalds's avatar
Linus Torvalds committed
1040
1041
1042
1043
1044
1045
1046
1047
1048
		ptxd->len = 0;
	}

	if (aup->tx_full) {
		aup->tx_full = 0;
		netif_wake_queue(dev);
	}

	pDB = aup->tx_db_inuse[aup->tx_head];
1049
	skb_copy_from_linear_data(skb, (void *)pDB->vaddr, skb->len);
Linus Torvalds's avatar
Linus Torvalds committed
1050
	if (skb->len < ETH_ZLEN) {
Florian Fainelli's avatar
Florian Fainelli committed
1051
		for (i = skb->len; i < ETH_ZLEN; i++)
Linus Torvalds's avatar
Linus Torvalds committed
1052
			((char *)pDB->vaddr)[i] = 0;
Florian Fainelli's avatar
Florian Fainelli committed
1053

Linus Torvalds's avatar
Linus Torvalds committed
1054
		ptxd->len = ETH_ZLEN;
1055
	} else
Florian Fainelli's avatar
Florian Fainelli committed
1056
		ptxd->len = skb->len;
Linus Torvalds's avatar
Linus Torvalds committed
1057

Florian Fainelli's avatar
Florian Fainelli committed
1058
1059
	ps->tx_packets++;
	ps->tx_bytes += ptxd->len;
Linus Torvalds's avatar
Linus Torvalds committed
1060

Florian Fainelli's avatar
Florian Fainelli committed
1061
	ptxd->buff_stat = pDB->dma_addr | TX_DMA_ENABLE;
1062
	wmb(); /* drain writebuffer */
Florian Fainelli's avatar
Florian Fainelli committed
1063
1064
	dev_kfree_skb(skb);
	aup->tx_head = (aup->tx_head + 1) & (NUM_TX_DMA - 1);
1065
	return NETDEV_TX_OK;
Linus Torvalds's avatar
Linus Torvalds committed
1066
1067
1068
1069