aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/adm8668/files/arch/mips/adm8668/net.h
blob: c7aef8cf6ebf7969529532455056dd9c8d3c64c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
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
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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
/*
 * originally drivers/net/tulip/tulip.h
 *   Copyright 2000,2001  The Linux Kernel Team
 *   Written/copyright 1994-2001 by Donald Becker.
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 */

#ifndef __NET_TULIP_H__
#define __NET_TULIP_H__

#include <linux/module.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/mii.h>
#include <linux/crc32.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <asm/unaligned.h>
#include <asm/uaccess.h>

/* undefine, or define to various debugging levels (>4 == obscene levels) */
#define TULIP_DEBUG 1
#define	VALID_INTR	0x0001a451
#define	ADM8668_WAN_IRQ		8
#define	ADM8668_LAN_IRQ		7
#define	ADM8668_WAN_MACADDR	0xb00205ac
#define	ADM8668_LAN_MACADDR	0xb0020404

/* Offsets to the Command and Status Registers, "CSRs".  All accesses
   must be longword instructions and quadword aligned. */
enum tulip_offsets {
	CSR0 = 0,
	CSR1 = 0x08,
	CSR2 = 0x10,
	CSR3 = 0x18,
	CSR4 = 0x20,
	CSR5 = 0x28,
	CSR6 = 0x30,
	CSR7 = 0x38,
	CSR8 = 0x40,
	CSR9 = 0x48,
	CSR10 = 0x50,
	CSR11 = 0x58,
	CSR12 = 0x60,
	CSR13 = 0x68,
	CSR14 = 0x70,
	CSR15 = 0x78,
	CSR18 = 0x88,
	CSR19 = 0x8c,
	CSR20 = 0x90,
	CSR27 = 0xAC,
	CSR28 = 0xB0,
};

#define RxPollInt (RxIntr|RxNoBuf|RxDied|RxJabber)

/* The bits in the CSR5 status registers, mostly interrupt sources. */
enum status_bits {
	TimerInt = 0x800,
	SystemError = 0x2000,
	TPLnkFail = 0x1000,
	TPLnkPass = 0x10,
	NormalIntr = 0x10000,
	AbnormalIntr = 0x8000,
	RxJabber = 0x200,
	RxDied = 0x100,
	RxNoBuf = 0x80,
	RxIntr = 0x40,
	TxFIFOUnderflow = 0x20,
	RxErrIntr = 0x10,
	TxJabber = 0x08,
	TxNoBuf = 0x04,
	TxDied = 0x02,
	TxIntr = 0x01,
};

/* bit mask for CSR5 TX/RX process state */
#define CSR5_TS	0x00700000
#define CSR5_RS	0x000e0000

enum tulip_mode_bits {
	TxThreshold		= (1 << 22),
	FullDuplex		= (1 << 9),
	TxOn			= 0x2000,
	AcceptBroadcast		= 0x0100,
	AcceptAllMulticast	= 0x0080,
	AcceptAllPhys		= 0x0040,
	AcceptRunt		= 0x0008,
	RxOn			= 0x0002,
	RxTx			= (TxOn | RxOn),
};

/* The Tulip Rx and Tx buffer descriptors. */
struct tulip_rx_desc {
	__le32 status;
	__le32 length;
	__le32 buffer1;
	__le32 buffer2;
};

struct tulip_tx_desc {
	__le32 status;
	__le32 length;
	__le32 buffer1;
	__le32 buffer2;		/* We use only buffer 1.  */
};

enum desc_status_bits {
	DescOwned    = 0x80000000,
	DescWholePkt = 0x60000000,
	DescEndPkt   = 0x40000000,
	DescStartPkt = 0x20000000,
	DescEndRing  = 0x02000000,
	DescUseLink  = 0x01000000,

	/*
	 * Error summary flag is logical or of 'CRC Error', 'Collision Seen',
	 * 'Frame Too Long', 'Runt' and 'Descriptor Error' flags generated
	 * within tulip chip.
	 */
	RxDescErrorSummary = 0x8000,
	RxDescCRCError = 0x0002,
	RxDescCollisionSeen = 0x0040,

	/*
	 * 'Frame Too Long' flag is set if packet length including CRC exceeds
	 * 1518.  However, a full sized VLAN tagged frame is 1522 bytes
	 * including CRC.
	 *
	 * The tulip chip does not block oversized frames, and if this flag is
	 * set on a receive descriptor it does not indicate the frame has been
	 * truncated.  The receive descriptor also includes the actual length.
	 * Therefore we can safety ignore this flag and check the length
	 * ourselves.
	 */
	RxDescFrameTooLong = 0x0080,
	RxDescRunt = 0x0800,
	RxDescDescErr = 0x4000,
	RxWholePkt   = 0x00000300,
	/*
	 * Top three bits of 14 bit frame length (status bits 27-29) should
	 * never be set as that would make frame over 2047 bytes. The Receive
	 * Watchdog flag (bit 4) may indicate the length is over 2048 and the
	 * length field is invalid.
	 */
	RxLengthOver2047 = 0x38000010
};

/* Keep the ring sizes a power of two for efficiency.
   Making the Tx ring too large decreases the effectiveness of channel
   bonding and packet priority.
   There are no ill effects from too-large receive rings. */

#define TX_RING_SIZE	32
#define RX_RING_SIZE	128

/* The receiver on the DC21143 rev 65 can fail to close the last
 * receive descriptor in certain circumstances (see errata) when
 * using MWI. This can only occur if the receive buffer ends on
 * a cache line boundary, so the "+ 4" below ensures it doesn't.
 */
#define PKT_BUF_SZ	(1536 + 4)	/* Size of each temporary Rx buffer. */

/* Ring-wrap flag in length field, use for last ring entry.
	0x01000000 means chain on buffer2 address,
	0x02000000 means use the ring start address in CSR2/3.
   Note: Some work-alike chips do not function correctly in chained mode.
   The ASIX chip works only in chained mode.
   Thus we indicates ring mode, but always write the 'next' field for
   chained mode as well.
*/
#define DESC_RING_WRAP 0x02000000

struct ring_info {
	struct sk_buff	*skb;
	dma_addr_t	mapping;
};

struct tulip_private {
	struct tulip_rx_desc *rx_ring;
	struct tulip_tx_desc *tx_ring;
	dma_addr_t rx_ring_dma;
	dma_addr_t tx_ring_dma;
	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
	struct ring_info tx_buffers[TX_RING_SIZE];
	/* The addresses of receive-in-place skbuffs. */
	struct ring_info rx_buffers[RX_RING_SIZE];
	struct napi_struct napi;
	struct net_device_stats stats;
	struct timer_list oom_timer;    /* Out of memory timer. */
	u32 mc_filter[2];
	spinlock_t lock;
	unsigned int cur_rx, cur_tx;	/* The next free ring entry */
	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
	unsigned int csr0;	/* CSR0 setting. */
	unsigned int csr6;	/* Current CSR6 control settings. */
	void (*link_change) (struct net_device * dev, int csr5);
	struct platform_device *pdev;
	unsigned long nir;
	void __iomem *base_addr;
	int pad0;		/* Used for 8-byte alignment */
	struct net_device *dev;
};


/* interrupt.c */
irqreturn_t tulip_interrupt(int irq, void *dev_instance);
int tulip_refill_rx(struct net_device *dev);
int tulip_poll(struct napi_struct *napi, int budget);

/* tulip_core.c */
extern int tulip_debug;
void oom_timer(unsigned long data);

static inline void tulip_start_rxtx(struct tulip_private *tp)
{
	void __iomem *ioaddr = tp->base_addr;
	iowrite32(tp->csr6 | RxTx, ioaddr + CSR6);
	barrier();
	(void) ioread32(ioaddr + CSR6); /* mmio sync */
}

static inline void tulip_stop_rxtx(struct tulip_private *tp)
{
	void __iomem *ioaddr = tp->base_addr;
	u32 csr6 = ioread32(ioaddr + CSR6);

	if (csr6 & RxTx) {
		unsigned i=1300/10;
		iowrite32(csr6 & ~RxTx, ioaddr + CSR6);
		barrier();
		/* wait until in-flight frame completes.
		 * Max time @ 10BT: 1500*8b/10Mbps == 1200us (+ 100us margin)
		 * Typically expect this loop to end in < 50 us on 100BT.
		 */
		while (--i && (ioread32(ioaddr + CSR5) & (CSR5_TS|CSR5_RS)))
			udelay(10);

		if (!i)
			printk(KERN_DEBUG "fixme: tulip_stop_rxtx() failed"
					" (CSR5 0x%x CSR6 0x%x)\n",
					ioread32(ioaddr + CSR5),
					ioread32(ioaddr + CSR6));
	}
}

static inline void tulip_restart_rxtx(struct tulip_private *tp)
{
	tulip_stop_rxtx(tp);
	udelay(5);
	tulip_start_rxtx(tp);
}

static inline void tulip_tx_timeout_complete(struct tulip_private *tp, void __iomem *ioaddr)
{
	/* Stop and restart the chip's Tx processes. */
	tulip_restart_rxtx(tp);
	/* Trigger an immediate transmit demand. */
	iowrite32(0, ioaddr + CSR1);

	tp->stats.tx_errors++;
}

#endif /* __NET_TULIP_H__ */