]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/zynq/etherzynq.c
kernel: cleanup the software mouse cursor mess
[plan9front.git] / sys / src / 9 / zynq / etherzynq.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/netif.h"
8 #include "../port/etherif.h"
9
10 #define Rbsz            ROUNDUP(sizeof(Etherpkt)+16, 64)
11
12 enum {
13         RXRING = 0x200,
14         TXRING = 0x200,
15         Linkdelay = 500,
16         MDC_DIV = 6,
17 };
18
19 enum {
20         NET_CTRL,
21         NET_CFG,
22         NET_STATUS,
23         DMA_CFG = 4,
24         TX_STATUS,
25         RX_QBAR,
26         TX_QBAR,
27         RX_STATUS,
28         INTR_STATUS,
29         INTR_EN,
30         INTR_DIS,
31         INTR_MASK,
32         PHY_MAINT,
33         RX_PAUSEQ,
34         TX_PAUSEQ,
35         HASH_BOT = 32,
36         HASH_TOP,
37         SPEC_ADDR1_BOT,
38         SPEC_ADDR1_TOP,
39 };
40
41 enum {
42         MDCTRL,
43         MDSTATUS,
44         MDID1,
45         MDID2,
46         MDAUTOADV,
47         MDAUTOPART,
48         MDAUTOEX,
49         MDAUTONEXT,
50         MDAUTOLINK,
51         MDGCTRL,
52         MDGSTATUS,
53         MDPHYCTRL = 0x1f,
54 };
55
56 enum {
57         /* NET_CTRL */
58         RXEN = 1<<2,
59         TXEN = 1<<3,
60         MDEN = 1<<4,
61         STARTTX = 1<<9,
62         /* NET_CFG */
63         SPEED = 1<<0,
64         FDEN = 1<<1,
65         COPYALLEN = 1<<4,
66         MCASTHASHEN = 1<<6,
67         UCASTHASHEN = 1<<7,
68         RX1536EN = 1<<8,
69         GIGE_EN = 1<<10,
70         RXCHKSUMEN = 1<<24,
71         /* NET_STATUS */
72         PHY_IDLE = 1<<2,
73         /* DMA_CFG */
74         TXCHKSUMEN  = 1<<11,
75         /* TX_STATUS */
76         TXCOMPL = 1<<5,
77         /* INTR_{EN,DIS} */
78         MGMTDONE = 1<<0,
79         RXCOMPL = 1<<1,
80         RXUSED = 1<<2,
81         TXUNDER = 1<<4,
82         RXOVER = 1<<10,
83         /* MDCTRL */
84         MDRESET = 1<<15,
85         AUTONEG = 1<<12,
86         FULLDUP = 1<<8,
87         /* MDSTATUS */
88         LINK = 1<<2,
89         /* MDGSTATUS */
90         RECVOK = 3<<12,
91 };
92
93 enum {
94         RxUsed = 1,
95         TxUsed = 1<<31,
96         FrameEnd = 1<<15,
97 };
98
99 enum {
100         GEM0_CLK_CTRL = 0x140/4,
101 };
102
103 typedef struct Ctlr Ctlr;
104
105 struct Ctlr {
106         ulong *r;
107         Rendez phy;
108         int phyaddr;
109         int rxconsi, rxprodi, txi;
110         ulong *rxr, *txr;
111         Block **rxs, **txs;
112         Lock txlock;
113         int attach;
114 };
115
116 static int
117 phyidle(void *v)
118 {
119         return ((Ctlr*)v)->r[NET_STATUS] & PHY_IDLE;
120 }
121
122 static void
123 mdwrite(Ctlr *c, int r, u16int v)
124 {
125         sleep(&c->phy, phyidle, c);
126         c->r[PHY_MAINT] = 1<<30 | 1<<28 | 1<<17 | c->phyaddr << 23 | r << 18 | v;
127         sleep(&c->phy, phyidle, c);
128 }
129
130 static u16int
131 mdread(Ctlr *c, int r)
132 {
133         sleep(&c->phy, phyidle, c);
134         c->r[PHY_MAINT] = 1<<30 | 1<< 29 | 1<<17 | c->phyaddr << 23 | r << 18;
135         sleep(&c->phy, phyidle, c);
136         return c->r[PHY_MAINT];
137 }
138
139 static void
140 ethproc(void *ved)
141 {
142         Ether *edev;
143         Ctlr *c;
144         char *sp, *dpl;
145         u16int v;
146         
147         edev = ved;
148         c = edev->ctlr;
149         mdwrite(c, MDCTRL, AUTONEG);
150         for(;;){
151                 if((mdread(c, MDSTATUS) & LINK) == 0){
152                         edev->link = 0;
153                         print("eth: no link\n");
154                         while((mdread(c, MDSTATUS) & LINK) == 0)
155                                 tsleep(&up->sleep, return0, nil, Linkdelay);
156                 }
157                 v = mdread(c, MDPHYCTRL);
158                 if((v & 0x40) != 0){
159                         sp = "1000BASE-T";
160                         while((mdread(c, MDGSTATUS) & RECVOK) != RECVOK)
161                                 ;
162                         edev->mbps = 1000;
163                         c->r[NET_CFG] |= GIGE_EN;
164                         slcr[GEM0_CLK_CTRL] = 1 << 20 | 8 << 8 | 1;
165                 }else if((v & 0x20) != 0){
166                         sp = "100BASE-TX";
167                         edev->mbps = 100;
168                         c->r[NET_CFG] = c->r[NET_CFG] & ~GIGE_EN | SPEED;
169                         slcr[GEM0_CLK_CTRL] = 5 << 20 | 8 << 8 | 1;
170                 }else if((v & 0x10) != 0){
171                         sp = "10BASE-T";
172                         edev->mbps = 10;
173                         c->r[NET_CFG] = c->r[NET_CFG] & ~(GIGE_EN | SPEED);
174                         slcr[GEM0_CLK_CTRL] = 20 << 20 | 20 << 8 | 1;
175                 }else
176                         sp = "???";
177                 if((v & 0x08) != 0){
178                         dpl = "full";
179                         c->r[NET_CFG] |= FDEN;
180                 }else{
181                         dpl = "half";
182                         c->r[NET_CFG] &= ~FDEN;
183                 }
184                 edev->link = 1;
185                 print("eth: %s %s duplex link\n", sp, dpl);
186                 while((mdread(c, MDSTATUS) & LINK) != 0)
187                         tsleep(&up->sleep, return0, nil, Linkdelay);
188         }
189 }
190
191 static int
192 replenish(Ctlr *c)
193 {
194         Block *bp;
195         int i;
196         ulong *r;
197         
198         while(c->rxprodi != c->rxconsi){
199                 i = c->rxprodi;
200                 bp = iallocb(Rbsz);
201                 if(bp == nil){
202                         print("eth: out of memory for receive buffers\n");
203                         return -1;
204                 }
205                 c->rxs[i] = bp;
206                 r = &c->rxr[2 * i];
207                 r[0] = RxUsed | PADDR(bp->rp);
208                 if(i == RXRING - 1)
209                         r[0] |= 2;
210                 r[1] = 0;
211                 cleandse(bp->base, bp->lim);
212                 clean2pa(PADDR(bp->base), PADDR(bp->lim));
213                 r[0] &= ~RxUsed;
214                 c->rxprodi = (c->rxprodi + 1) & (RXRING - 1);
215         }
216         return 0;
217 }
218
219 static void
220 ethrx(Ether *edev)
221 {
222         Ctlr *c;
223         ulong *r;
224         Block *bp;
225
226         c = edev->ctlr;
227 //      print("rx! %p %p\n", PADDR(&c->rxr[2 * c->rxconsi]), c->r[RX_QBAR]);
228         for(;;){
229                 r = &c->rxr[2 * c->rxconsi];
230                 if((r[0] & RxUsed) == 0)
231                         break;
232                 if((r[1] & FrameEnd) == 0)
233                         print("eth: partial frame received -- shouldn't happen\n");
234                 bp = c->rxs[c->rxconsi];
235                 bp->wp = bp->rp + (r[1] & 0x1fff);
236                 invaldse(bp->rp, bp->wp);
237                 inval2pa(PADDR(bp->rp), PADDR(bp->wp));
238                 etheriq(edev, bp);
239                 c->rxconsi = (c->rxconsi + 1) & (RXRING - 1);
240                 replenish(c);
241         }
242 }
243
244 static void
245 ethtx(Ether *edev)
246 {
247         Ctlr *c;
248         ulong *r;
249         Block *bp;
250         
251         c = edev->ctlr;
252         ilock(&c->txlock);
253         for(;;){
254                 r = &c->txr[2 * c->txi];
255                 if((r[1] & TxUsed) == 0){
256                         print("eth: transmit buffer full\n");
257                         break;
258                 }
259                 bp = qget(edev->oq);
260                 if(bp == nil)
261                         break;
262                 if(c->txs[c->txi] != nil)
263                         freeb(c->txs[c->txi]);
264                 c->txs[c->txi] = bp;
265                 cleandse(bp->rp, bp->wp);
266                 clean2pa(PADDR(bp->rp), PADDR(bp->wp));
267                 r[0] = PADDR(bp->rp);
268                 r[1] = BLEN(bp) | FrameEnd | TxUsed;
269                 if(r == c->txr + 2 * (TXRING - 1))
270                         r[1] |= 1<<30;
271                 coherence();
272                 r[1] &= ~TxUsed;
273                 coherence();
274                 c->r[NET_CTRL] |= STARTTX;
275                 c->txi = (c->txi + 1) & (TXRING - 1);
276         }
277         iunlock(&c->txlock);
278 }
279
280 static void
281 ethirq(Ureg *, void *arg)
282 {
283         Ether *edev;
284         Ctlr *c;
285         ulong fl;
286         
287         edev = arg;
288         c = edev->ctlr;
289         fl = c->r[INTR_STATUS];
290         c->r[INTR_STATUS] = fl;
291         if((fl & MGMTDONE) != 0)
292                 wakeup(&c->phy);
293         if((fl & TXUNDER) != 0)
294                 ethtx(edev);
295         if((fl & RXCOMPL) != 0)
296                 ethrx(edev);
297         if((fl & RXUSED) != 0)
298                 print("eth: DMA read RX descriptor with used bit set, shouldn't happen\n");
299         if((fl & RXOVER) != 0)
300                 print("eth: RX overrun, shouldn't happen\n");
301 }
302
303 static void
304 ethprom(void *arg, int on)
305 {
306         Ether *edev;
307         Ctlr *c;
308
309         edev = arg;
310         c = edev->ctlr;
311         if(on)
312                 c->r[NET_CFG] |= COPYALLEN;
313         else
314                 c->r[NET_CFG] &= ~COPYALLEN;
315 }
316
317 static void
318 ethmcast(void *arg, uchar *ea, int on)
319 {
320         Ether *edev;
321         Ctlr *c;
322         u64int a;
323         uchar x;
324
325         edev = arg;
326         c = edev->ctlr;
327         if(edev->nmaddr == 0){
328                 c->r[NET_CFG] &= ~MCASTHASHEN;
329                 c->r[HASH_BOT] = 0;
330                 c->r[HASH_TOP] = 0;
331         }
332         if(!on)
333                 return;
334         a = (u64int)ea[0]     | (u64int)ea[1]<<8  | (u64int)ea[2]<<16 |
335             (u64int)ea[3]<<24 | (u64int)ea[4]<<32 | (u64int)ea[5]<<40;
336         x = a ^ (a>>6) ^ (a>>12) ^ (a>>18) ^ (a>>24) ^ (a>>30) ^ (a>>36) ^ (a>>42);
337         x &= 63;
338         if(x < 32)
339                 c->r[HASH_BOT] |= 1<<x;
340         else
341                 c->r[HASH_TOP] |= 1<<(x-32);
342         c->r[NET_CFG] |= MCASTHASHEN;
343 }
344
345 static int
346 ethinit(Ether *edev)
347 {
348         Ctlr *c;
349         int i;
350         
351         c = edev->ctlr;
352         c->r[NET_CTRL] = 0;
353         c->r[RX_STATUS] = 0xf;
354         c->r[TX_STATUS] = 0xff;
355         c->r[INTR_DIS] = 0x7FFFEFF;
356         c->r[NET_CFG] = MDC_DIV << 18 | FDEN | SPEED | RX1536EN | GIGE_EN | RXCHKSUMEN;
357         c->r[SPEC_ADDR1_BOT] = edev->ea[0] | edev->ea[1] << 8 | edev->ea[2] << 16 | edev->ea[3] << 24;
358         c->r[SPEC_ADDR1_TOP] = edev->ea[4] | edev->ea[5] << 8;
359         c->r[DMA_CFG] = TXCHKSUMEN | (Rbsz/64) << 16 | 1 << 10 | 3 << 8 | 0x10;
360
361         c->rxr = ucalloc(8 * RXRING);
362         c->txr = ucalloc(8 * TXRING);
363         c->rxs = xspanalloc(4 * RXRING, 4, 0);
364         c->txs = xspanalloc(4 * TXRING, 4, 0);
365         for(i = 0; i < 2 * RXRING; ){
366                 c->rxr[i++] = 1;
367                 c->rxr[i++] = 0;
368         }
369         c->rxconsi = 1;
370         replenish(c);
371         c->rxconsi = 0;
372         replenish(c);
373         for(i = 0; i < 2 * TXRING; ){
374                 c->txr[i++] = 0;
375                 c->txr[i++] = 1<<31;
376         }
377         c->txr[2 * (TXRING - 1)] |= 1<<30;
378         c->r[RX_QBAR] = PADDR(c->rxr);
379         c->r[TX_QBAR] = PADDR(c->txr);
380         
381         c->r[NET_CTRL] = MDEN | TXEN | RXEN;
382         c->r[INTR_EN] = MGMTDONE | TXUNDER | RXCOMPL | RXUSED | RXOVER;
383         return 0;
384 }
385
386 static void
387 ethattach(Ether *edev)
388 {
389         Ctlr *c;
390
391         c = edev->ctlr;
392         if(c->attach)
393                 return;
394         c->attach = 1;
395         kproc("ethproc", ethproc, edev);
396 }
397
398 static int
399 etherpnp(Ether *edev)
400 {
401         static Ctlr ct;
402         static uchar mac[] = {0x0e, 0xa7, 0xde, 0xad, 0xbe, 0xef};
403         
404         if(ct.r != nil)
405                 return -1;
406
407         memmove(edev->ea, mac, 6);
408         edev->ctlr = &ct;
409         edev->port = ETH0_BASE;
410         ct.r = vmap(edev->port, BY2PG);
411         edev->irq = ETH0IRQ;
412         edev->ctlr = &ct;
413         edev->transmit = ethtx;
414         edev->attach = ethattach;
415         edev->promiscuous = ethprom;
416         edev->multicast = ethmcast;
417         edev->arg = edev;
418         edev->mbps = 1000;
419         
420         if(ethinit(edev) < 0){
421                 edev->ctlr = nil;
422                 return -1;
423         }
424
425         intrenable(edev->irq, ethirq, edev, LEVEL, edev->name);
426         return 0;
427 }
428
429 void
430 etherzynqlink(void)
431 {
432         addethercard("eth", etherpnp);
433 }