]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/ppc/ethersaturn.c
a439b4215612b5f18f8fe89dd69b1d4af89cb065
[plan9front.git] / sys / src / 9 / 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 "../port/etherif.h"
10
11 #include "msaturn.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->irq = Vecether;
213         ether->arg = ether;
214         memmove(ether->ea, (ushort*)Emacaddr0, Eaddrlen);
215
216         *ercr = Ercr_rxenab|Ercr_auienab|(Nrx-1);
217         *eimr = Ei_rxdone|Ei_txretry|Ei_txdone;
218         
219         iprint("reset: ercr %.4uX\n", *ercr);
220
221         intrenable(ether->irq, interrupt, ether, ether->name);
222
223         return 0;
224 }
225
226 void
227 ethersaturnlink(void)
228 {
229         addethercard("saturn", reset);
230 }
231