Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "u.h"
2
#include "../port/lib.h"
3
#include "mem.h"
4
#include "dat.h"
5
#include "fns.h"
6
#include "io.h"
7
#include "../port/error.h"
8
#include "../port/netif.h"
9
#include "msaturn.h"
10
 
11
#include "etherif.h"
12
 
13
enum{
14
	Etcr = Saturn + 0x0c00,
15
	Etsr = Saturn + 0x0c02,
16
	Ercr = Saturn + 0x0c04,
17
	Ersr = Saturn + 0x0c06,
18
	Eisr = Saturn + 0x0d04,
19
	Eimr = Saturn + 0x0d06,
20
	Emacaddr0 = Saturn + 0x0e02,
21
	Miicr = Saturn + 0x0f02,
22
	Miiwdr = Saturn + 0x0f04,
23
	Miirdr = Saturn + 0x0f06,
24
 
25
	Ethermem = 0xf2c00000,
26
	Etherfsize = 0x2000,
27
	Nrx = 14,
28
	Ntx = 2,		// Nrx + Ntx must be 16
29
 
30
	Ersr_rxfpmask = 0xf,
31
	Ersr_rxevent = RBIT(0, ushort),
32
	Etcr_txfpmask = 0xf,
33
	Ercr_rxenab = RBIT(0, ushort),
34
	Ercr_auienab = RBIT(2, ushort),
35
	Etcr_txstart = RBIT(1, ushort),
36
	Etcr_retries = 0xf<<8,
37
	Ei_txecall = RBIT(0, ushort),
38
	Ei_txretry = RBIT(2, ushort),
39
	Ei_txdefer = RBIT(3, ushort),
40
	Ei_txcrs = RBIT(4, ushort),
41
	Ei_txdone = RBIT(5, ushort),
42
	Ei_rxcrcerr = RBIT(8, ushort),
43
	Ei_rxdrib = RBIT(9, ushort),
44
	Ei_rxdone = RBIT(10, ushort),
45
	Ei_rxshort = RBIT(11, ushort),
46
	Ei_rxlong = RBIT(12, ushort),
47
 
48
	Miicr_regshift = 6,
49
	Miicr_read = RBIT(10, ushort),
50
	Miicr_preambledis = RBIT(12, ushort),
51
	Miicr_accack = RBIT(14, ushort),
52
	Miicr_accbsy = RBIT(15, ushort),
53
};
54
 
55
typedef struct {
56
	Lock;
57
	int		txbusy;
58
	int		txempty;
59
	int		txfull;
60
	int		ntx;			/* number of entries in transmit ring */
61
	int		rxlast;
62
 
63
	int		active;
64
	ulong	interrupts;	/* statistics */
65
	ulong	overflows;
66
} Ctlr;
67
 
68
uchar etheraddr[6] = { 0x90, 0x85, 0x82, 0x32, 0x83, 0x00};
69
static ushort*etcr=(ushort*)Etcr;
70
static ushort*etsr=(ushort*)Etsr;
71
static ushort*ercr=(ushort*)Ercr;
72
static ushort*ersr=(ushort*)Ersr;
73
static ushort*eimr=(ushort*)Eimr;
74
static ushort*eisr=(ushort*)Eisr;
75
static ushort*miicr=(ushort*)Miicr;
76
static ushort*miirdr=(ushort*)Miirdr;
77
 
78
static void
79
txfill(Ether*ether, Ctlr*ctlr)
80
{
81
	int len;
82
	Block *b;
83
	ushort*dst;
84
 
85
	while(ctlr->ntx<Ntx){
86
		if((b=qget(ether->oq)) == nil)
87
			break;
88
 
89
		len = BLEN(b);
90
		dst = (ushort*)(Ethermem+(ctlr->txempty+Nrx)*Etherfsize);
91
		*dst = len;
92
		memmove(&dst[1], b->rp, len);
93
		ctlr->ntx++;
94
		ctlr->txempty++;
95
		if(ctlr->txempty==Ntx)
96
			ctlr->txempty = 0;
97
		freeb(b);
98
	}
99
}
100
 
101
static void
102
txrestart(Ctlr*ctlr)
103
{
104
	if(ctlr->ntx==0 || ctlr->txbusy)
105
		return;
106
	ctlr->txbusy = 1;
107
	*etcr = Etcr_txstart|Etcr_retries|(ctlr->txfull+Nrx);
108
}
109
 
110
static void interrupt(Ureg*, void*);
111
 
112
static void
113
transmit(Ether*ether)
114
{
115
	Ctlr *ctlr;
116
 
117
	ctlr = ether->ctlr;
118
	ilock(ctlr);
119
	txfill(ether, ctlr);
120
	txrestart(ctlr);
121
	iunlock(ctlr);
122
 
123
}
124
 
125
static void
126
interrupt(Ureg*, void*arg)
127
{
128
	Ctlr*ctlr;
129
	Ether*ether = arg;
130
	Etherpkt*pkt;
131
	ushort ie;
132
	int rx, len;
133
	Block *b;
134
 
135
	ctlr = ether->ctlr;
136
	if(!ctlr->active)
137
		return;	/* not ours */
138
	ctlr->interrupts++;
139
 
140
	ilock(ctlr);
141
	ie = *eisr;
142
	*eisr = ie;
143
	intack();
144
 
145
	if(ie==0)
146
		iprint("interrupt: no interrupt source?\n");
147
 
148
	if(ie&Ei_txdone){
149
		if((*etcr&Etcr_txstart)==0){
150
			if(ctlr->txbusy){
151
				ctlr->txbusy = 0;
152
				ctlr->ntx--;
153
				ctlr->txfull++;
154
				if(ctlr->txfull==Ntx)
155
					ctlr->txfull = 0;
156
			}
157
			txrestart(ctlr);
158
			txfill(ether, ctlr);
159
			txrestart(ctlr);
160
		}
161
		else
162
			iprint("interrupt: bogus tx interrupt\n");
163
		ie &= ~Ei_txdone;
164
	}
165
 
166
	if(ie&Ei_rxdone){
167
		rx=*ersr&Ersr_rxfpmask;
168
		while(ctlr->rxlast!=rx){
169
 
170
			ctlr->rxlast++;
171
			if(ctlr->rxlast >= Nrx)
172
				ctlr->rxlast = 0;
173
 
174
			pkt = (Etherpkt*)(Ethermem+ctlr->rxlast*Etherfsize);
175
			len = *(ushort*)pkt;
176
			if((b = iallocb(len+sizeof(ushort))) != nil){
177
				memmove(b->wp, pkt, len+sizeof(ushort));
178
				b->rp += sizeof(ushort);
179
				b->wp = b->rp + len;
180
				etheriq(ether, b, 1);
181
			}else
182
				ether->soverflows++;
183
			rx=*ersr&Ersr_rxfpmask;
184
		}
185
		ie &= ~Ei_rxdone;
186
	}
187
 
188
	if(ie&Ei_txretry){
189
		iprint("ethersaturn: txretry!\n");
190
		ie &= ~Ei_txretry;
191
		ctlr->txbusy = 0;
192
		txrestart(ctlr);
193
	}
194
 
195
	ie &= ~Ei_txcrs;
196
	if(ie)
197
		iprint("interrupt: unhandled interrupts %.4uX\n", ie);
198
	iunlock(ctlr);
199
}
200
 
201
static int
202
reset(Ether* ether)
203
{
204
	Ctlr*ctlr;
205
 
206
	*ercr = 0;
207
	ctlr = malloc(sizeof(*ctlr));
208
	memset(ctlr, 0, sizeof(*ctlr));
209
	ctlr->active = 1;
210
 
211
	ether->ctlr = ctlr;
212
	ether->transmit = transmit;
213
	ether->interrupt = interrupt;
214
	ether->irq = Vecether;
215
	ether->arg = ether;
216
	memmove(ether->ea, (ushort*)Emacaddr0, Eaddrlen);
217
 
218
	*ercr = Ercr_rxenab|Ercr_auienab|(Nrx-1);
219
	*eimr = Ei_rxdone|Ei_txretry|Ei_txdone;
220
 
221
	iprint("reset: ercr %.4uX\n", *ercr);
222
	return 0;
223
}
224
 
225
void
226
ethersaturnlink(void)
227
{
228
	addethercard("saturn", reset);
229
}
230