FreeBSD/Linux Kernel Cross Reference
sys/ppc/ethersaturn.c
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 static ushort*etcr=(ushort*)Etcr;
69 static ushort*etsr=(ushort*)Etsr;
70 static ushort*ercr=(ushort*)Ercr;
71 static ushort*ersr=(ushort*)Ersr;
72 static ushort*eimr=(ushort*)Eimr;
73 static ushort*eisr=(ushort*)Eisr;
74 static ushort*miicr=(ushort*)Miicr;
75 static ushort*miirdr=(ushort*)Miirdr;
76
77 static void
78 txfill(Ether*ether, Ctlr*ctlr)
79 {
80 int len;
81 Block *b;
82 ushort*dst;
83
84 while(ctlr->ntx<Ntx){
85 if((b=qget(ether->oq)) == nil)
86 break;
87
88 len = BLEN(b);
89 dst = (ushort*)(Ethermem+(ctlr->txempty+Nrx)*Etherfsize);
90 *dst = len;
91 memmove(&dst[1], b->rp, len);
92 ctlr->ntx++;
93 ctlr->txempty++;
94 if(ctlr->txempty==Ntx)
95 ctlr->txempty = 0;
96 freeb(b);
97 }
98 }
99
100 static void
101 txrestart(Ctlr*ctlr)
102 {
103 if(ctlr->ntx==0 || ctlr->txbusy)
104 return;
105 ctlr->txbusy = 1;
106 *etcr = Etcr_txstart|Etcr_retries|(ctlr->txfull+Nrx);
107 }
108
109 static void interrupt(Ureg*, void*);
110
111 static void
112 transmit(Ether*ether)
113 {
114 Ctlr *ctlr;
115
116 ctlr = ether->ctlr;
117 ilock(ctlr);
118 txfill(ether, ctlr);
119 txrestart(ctlr);
120 iunlock(ctlr);
121
122 }
123
124 static void
125 interrupt(Ureg*, void*arg)
126 {
127 Ctlr*ctlr;
128 Ether*ether = arg;
129 Etherpkt*pkt;
130 ushort ie;
131 int rx, len;
132 Block *b;
133
134 ctlr = ether->ctlr;
135 if(!ctlr->active)
136 return; /* not ours */
137 ctlr->interrupts++;
138
139 ilock(ctlr);
140 ie = *eisr;
141 *eisr = ie;
142 intack();
143
144 if(ie==0)
145 iprint("interrupt: no interrupt source?\n");
146
147 if(ie&Ei_txdone){
148 if((*etcr&Etcr_txstart)==0){
149 if(ctlr->txbusy){
150 ctlr->txbusy = 0;
151 ctlr->ntx--;
152 ctlr->txfull++;
153 if(ctlr->txfull==Ntx)
154 ctlr->txfull = 0;
155 }
156 txrestart(ctlr);
157 txfill(ether, ctlr);
158 txrestart(ctlr);
159 }
160 else
161 iprint("interrupt: bogus tx interrupt\n");
162 ie &= ~Ei_txdone;
163 }
164
165 if(ie&Ei_rxdone){
166 rx=*ersr&Ersr_rxfpmask;
167 while(ctlr->rxlast!=rx){
168
169 ctlr->rxlast++;
170 if(ctlr->rxlast >= Nrx)
171 ctlr->rxlast = 0;
172
173 pkt = (Etherpkt*)(Ethermem+ctlr->rxlast*Etherfsize);
174 len = *(ushort*)pkt;
175 if((b = iallocb(len+sizeof(ushort))) != nil){
176 memmove(b->wp, pkt, len+sizeof(ushort));
177 b->rp += sizeof(ushort);
178 b->wp = b->rp + len;
179 etheriq(ether, b, 1);
180 }else
181 ether->soverflows++;
182 rx=*ersr&Ersr_rxfpmask;
183 }
184 ie &= ~Ei_rxdone;
185 }
186
187 if(ie&Ei_txretry){
188 iprint("ethersaturn: txretry!\n");
189 ie &= ~Ei_txretry;
190 ctlr->txbusy = 0;
191 txrestart(ctlr);
192 }
193
194 ie &= ~Ei_txcrs;
195 if(ie)
196 iprint("interrupt: unhandled interrupts %.4uX\n", ie);
197 iunlock(ctlr);
198 }
199
200 static int
201 reset(Ether* ether)
202 {
203 Ctlr*ctlr;
204
205 *ercr = 0;
206 ctlr = malloc(sizeof(*ctlr));
207 memset(ctlr, 0, sizeof(*ctlr));
208 ctlr->active = 1;
209
210 ether->ctlr = ctlr;
211 ether->transmit = transmit;
212 ether->interrupt = interrupt;
213 ether->irq = Vecether;
214 ether->arg = ether;
215 memmove(ether->ea, (ushort*)Emacaddr0, Eaddrlen);
216
217 *ercr = Ercr_rxenab|Ercr_auienab|(Nrx-1);
218 *eimr = Ei_rxdone|Ei_txretry|Ei_txdone;
219
220 iprint("reset: ercr %.4uX\n", *ercr);
221 return 0;
222 }
223
224 void
225 ethersaturnlink(void)
226 {
227 addethercard("saturn", reset);
228 }
229
Cache object: 5c7b5df719f249130305a955e230f202
|