xref: /minix/minix/drivers/net/dec21140A/dec21140A.c (revision ef8d499e)
1 /*
2  * dec21041.c
3  *
4  * This file contains an ethernet device driver for DEC  21140A
5  * fast ethernet controllers as emulated by VirtualPC 2007. It is not
6  * intended to support the real card, as much more error checking
7  * and testing would be needed. It supports both bridged and NAT mode.
8  *
9  * Created:	Mar 2008 by Nicolas Tittley <first.last@ google's mail>
10  */
11 
12 #include <minix/drivers.h>
13 #include <minix/netdriver.h>
14 
15 #include <machine/pci.h>
16 #include <assert.h>
17 
18 #include "dec21140A.h"
19 
20 static u32_t io_inl(u16_t);
21 static void io_outl(u16_t, u32_t);
22 
23 static int do_init(unsigned int, netdriver_addr_t *, uint32_t *,
24 	unsigned int *);
25 static void do_stop(void);
26 static int do_send(struct netdriver_data *, size_t);
27 static ssize_t do_recv(struct netdriver_data *, size_t);
28 static void do_intr(unsigned int);
29 
30 static int de_probe(dpeth_t *, unsigned int skip);
31 static void de_conf_addr(dpeth_t *, netdriver_addr_t *);
32 static void de_init_buf(dpeth_t *);
33 static void de_reset(const dpeth_t *);
34 static void de_hw_conf(const dpeth_t *);
35 static void de_start(const dpeth_t *);
36 static void de_setup_frame(const dpeth_t *, const netdriver_addr_t *);
37 static u16_t de_read_rom(const dpeth_t *, u8_t, u8_t);
38 
39 static dpeth_t de_state;
40 
41 static const struct netdriver de_table = {
42 	.ndr_name	= "dec",
43 	.ndr_init	= do_init,
44 	.ndr_stop	= do_stop,
45 	.ndr_recv	= do_recv,
46 	.ndr_send	= do_send,
47 	.ndr_intr	= do_intr
48 };
49 
50 int main(int argc, char *argv[])
51 {
52   env_setargs(argc, argv);
53 
54   netdriver_task(&de_table);
55 
56   return 0;
57 }
58 
59 static void de_init_hw(dpeth_t *dep, netdriver_addr_t *addr)
60 {
61   de_reset(dep);
62   de_conf_addr(dep, addr);
63   de_init_buf(dep);
64 
65   /* Set the interrupt handler policy. Request interrupts not to be reenabled
66    * automatically. Return the IRQ line number when an interrupt occurs.
67    */
68   dep->de_hook = dep->de_irq;
69   sys_irqsetpolicy(dep->de_irq, 0, &dep->de_hook);
70   sys_irqenable(&dep->de_hook);
71 
72   de_reset(dep);
73   de_hw_conf(dep);
74   de_setup_frame(dep, addr);
75   de_start(dep);
76 }
77 
78 static int do_init(unsigned int instance, netdriver_addr_t *addr,
79 	uint32_t *caps, unsigned int *ticks)
80 {
81 /* Initialize the DEC 21140A driver. */
82   dpeth_t *dep;
83 
84   dep = &de_state;
85   memset(dep, 0, sizeof(*dep));
86 
87   if (!de_probe(dep, instance))
88     return ENXIO;
89 
90   de_init_hw(dep, addr);
91 
92   *caps = NDEV_CAP_MCAST | NDEV_CAP_BCAST;
93   return OK;
94 }
95 
96 static int de_probe(dpeth_t *dep, unsigned int skip)
97 {
98   int r, devind;
99   u16_t vid, did;
100 
101   DEBUG(printf("PROBING..."));
102 
103   pci_init();
104 
105   r= pci_first_dev(&devind, &vid, &did);
106   if (r == 0)
107     return FALSE;
108 
109   while (skip--)
110     {
111       r= pci_next_dev(&devind, &vid, &did);
112       if (!r)
113 	return FALSE;
114     }
115 
116   pci_reserve(devind);
117 
118   dep->de_base_port = pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
119   dep->de_irq = pci_attr_r8(devind, PCI_ILR);
120 
121   if (dep->de_base_port < DE_MIN_BASE_ADDR)
122     panic("de_probe: base address invalid: %d", dep->de_base_port);
123 
124   DEBUG(printf("%s: using I/O address 0x%lx, IRQ %d\n",
125 	       netdriver_name(), (unsigned long)dep->de_base_port,
126 	       dep->de_irq));
127 
128   dep->de_type = pci_attr_r8(devind, PCI_REV);
129 
130   /* device validation. We support only the DEC21140A */
131   if(dep->de_type != DEC_21140A){
132     printf("%s: unsupported card type %x\n", netdriver_name(),
133       dep->de_type);
134     return FALSE;
135   }
136 
137   return TRUE;
138 }
139 
140 static u16_t de_read_rom(const dpeth_t *dep, u8_t addr, u8_t nbAddrBits)
141 {
142   u16_t retVal = 0;
143   int i;
144   u32_t csr = 0;
145   u32_t csr2 = 0; /* csr2 is used to hold constant values that are
146 		     setup in the init phase, it makes this a little
147 		     more readable, the following macro is also just
148 		     to clear up the code a little.*/
149 
150 #define EMIT \
151   do { \
152     io_outl(CSR_ADDR(dep, CSR9), csr | csr2); \
153     io_outl(CSR_ADDR(dep, CSR1), 0); \
154   } while(0)
155 
156   /* init */
157   csr = 0;                 EMIT;
158   csr = CSR9_SR;           EMIT;
159   csr = CSR9_SR | CSR9_RD; EMIT;
160 
161   csr2 = CSR9_SR | CSR9_RD;
162   csr = 0;                 EMIT;
163   csr2 |= CSR9_CS;
164 
165   csr = 0;                 EMIT;
166   csr = CSR9_SRC;          EMIT;
167   csr = 0;                 EMIT;
168 
169   /* cmd 110 - Read */
170   csr = CSR9_DI;            EMIT;
171   csr = CSR9_DI | CSR9_SRC; EMIT;
172   csr = CSR9_DI;            EMIT;
173   csr = CSR9_DI | CSR9_SRC; EMIT;
174   csr = CSR9_DI;            EMIT;
175   csr = 0;                  EMIT;
176   csr = CSR9_SRC;           EMIT;
177   csr = 0;                  EMIT;
178 
179   /* addr to read */
180   for(i=nbAddrBits;i!=0;i--){
181     csr = (addr&(1<<(i-1))) != 0 ? CSR9_DI : 0;  EMIT;
182     csr ^= CSR9_SRC; EMIT;
183     csr ^= CSR9_SRC; EMIT;
184   }
185 
186   /* actual read */
187   retVal=0;
188   for(i=0;i<16;i++){
189     retVal <<= 1;
190     csr = CSR9_SRC; EMIT;
191     retVal |= (io_inl(CSR_ADDR(dep, CSR9)) & CSR9_DO) == 0 ? 0 : 1;
192     csr = 0; EMIT;
193   }
194 
195   /* clean up */
196   csr = 0;                 EMIT;
197 
198 #undef EMIT
199   return retVal;
200 }
201 
202 static ssize_t do_recv(struct netdriver_data *data, size_t max)
203 {
204   u32_t size;
205   dpeth_t *dep;
206   de_loc_descr_t *descr;
207 
208   dep = &de_state;
209 
210   descr = &dep->descr[DESCR_RECV][dep->cur_descr[DESCR_RECV]];
211 
212   /* check if packet is in the current descr and only there */
213   if ((descr->descr->des[DES0] & DES0_OWN) ||
214       !(descr->descr->des[DES0] & DES0_FS) ||
215       !(descr->descr->des[DES0] & DES0_LS))
216     return SUSPEND;
217 
218   /*TODO: multi-descr msgs...*/
219   /* We only support packets contained in a single descriptor.
220      Setting the descriptor buffer size to less then
221      ETH_MAX_PACK_SIZE will result in multi-descriptor
222      packets that we won't be able to handle
223   */
224 
225   /* Check for abnormal messages. We assert here
226      because this driver is for a virtualized
227      envrionment where we will not get bad packets
228   */
229   assert(!(descr->descr->des[DES0]&DES0_ES));
230   assert(!(descr->descr->des[DES0]&DES0_RE));
231 
232   /* Copy buffer to user area and clear ownage */
233   size = (descr->descr->des[DES0]&DES0_FL)>>DES0_FL_SHIFT;
234 
235   /* HACK: VPC2007 sends short-sized packets, pad to minimum ethernet length */
236   if(size<60){
237     memset(&descr->buf1[size], 0, 60-size);
238     size=60;
239   }
240 
241   /* Truncate large packets */
242   if (size > max)
243     size = max;
244 
245   netdriver_copyout(data, 0, descr->buf1, size);
246 
247   descr->descr->des[DES0]=DES0_OWN;
248   dep->cur_descr[DESCR_RECV]++;
249   if(dep->cur_descr[DESCR_RECV] >= DE_NB_RECV_DESCR)
250     dep->cur_descr[DESCR_RECV] = 0;
251 
252   DEBUG(printf("Read returned size = %d\n", size));
253 
254   return size;
255 }
256 
257 static void de_conf_addr(dpeth_t *dep, netdriver_addr_t *addr)
258 {
259   u16_t temp16;
260   int i;
261 
262   DEBUG(printf("Reading SROM...\n"));
263 
264   for(i=0;i<(1<<SROM_BITWIDTH)-1;i++){
265     temp16 = de_read_rom(dep, i, SROM_BITWIDTH);
266     dep->srom[i*2] = temp16 & 0xFF;
267     dep->srom[i*2+1] = temp16 >> 8;
268   }
269 
270   /* TODO: validate SROM content */
271   /* acquire MAC addr */
272   DEBUG(printf("Using MAC addr= "));
273   for(i=0;i<6;i++){
274     addr->na_addr[i] = dep->srom[i+DE_SROM_EA_OFFSET];
275     DEBUG(printf("%02X%c", addr->na_addr[i],i!=5?'-':'\n'));
276   }
277   DEBUG(printf("probe success\n"));
278 }
279 
280 static void de_init_buf(dpeth_t *dep)
281 {
282   int i,j,r;
283   vir_bytes descr_vir = (vir_bytes)dep->sendrecv_descr_buf;
284   vir_bytes buffer_vir = (vir_bytes)dep->sendrecv_buf;
285   de_loc_descr_t *loc_descr;
286   phys_bytes temp;
287 
288   for(i=0;i<2;i++){
289     loc_descr = &dep->descr[i][0];
290     for(j=0; j < (i==DESCR_RECV ? DE_NB_RECV_DESCR : DE_NB_SEND_DESCR); j++){
291 
292       /* assign buffer space for descriptor */
293       loc_descr->descr = (void*)descr_vir;
294       descr_vir += sizeof(de_descr_t);
295 
296       /* assign space for buffer */
297       loc_descr->buf1 = (u8_t*)buffer_vir;
298       buffer_vir += (i==DESCR_RECV ? DE_RECV_BUF_SIZE : DE_SEND_BUF_SIZE);
299       loc_descr->buf2 = 0;
300       loc_descr++;
301     }
302   }
303 
304   /* Now that we have buffer space and descriptors, we need to
305      obtain their physical address to pass to the hardware
306   */
307   for(i=0;i<2;i++){
308     loc_descr = &dep->descr[i][0];
309     temp = (i==DESCR_RECV ? DE_RECV_BUF_SIZE : DE_SEND_BUF_SIZE);
310     for(j=0; j < (i==DESCR_RECV ? DE_NB_RECV_DESCR : DE_NB_SEND_DESCR); j++){
311       /* translate buffers physical address */
312       r = sys_umap(SELF, VM_D, (vir_bytes)loc_descr->buf1, temp,
313 		   (phys_bytes *) &(loc_descr->descr->des[DES_BUF1]));
314       if(r != OK) panic("umap failed: %d", r);
315       loc_descr->descr->des[DES_BUF2] = 0;
316       memset(&loc_descr->descr->des[DES0],0,sizeof(u32_t));
317       loc_descr->descr->des[DES1] = temp;
318       if(j==( (i==DESCR_RECV?DE_NB_RECV_DESCR:DE_NB_SEND_DESCR)-1))
319 	loc_descr->descr->des[DES1] |= DES1_ER;
320       if(i==DESCR_RECV)
321 	loc_descr->descr->des[DES0] |= DES0_OWN;
322       loc_descr++;
323     }
324   }
325 
326   /* record physical location of two first descriptor */
327   r = sys_umap(SELF, VM_D, (vir_bytes)dep->descr[DESCR_RECV][0].descr,
328 	       sizeof(de_descr_t), &dep->sendrecv_descr_phys_addr[DESCR_RECV]);
329   if(r != OK) panic("sys_umap failed: %d", r);
330 
331   r = sys_umap(SELF, VM_D, (vir_bytes)dep->descr[DESCR_TRAN][0].descr,
332 	       sizeof(de_descr_t), &dep->sendrecv_descr_phys_addr[DESCR_TRAN]);
333   if(r != OK) panic("sys_umap failed: %d", r);
334 
335   DEBUG(printf("Descr: head tran=[%08X] head recv=[%08X]\n",
336 	       dep->sendrecv_descr_phys_addr[DESCR_TRAN],
337 	       dep->sendrecv_descr_phys_addr[DESCR_RECV]));
338 
339   /* check alignment just to be extra safe */
340   for(i=0;i<2;i++){
341     loc_descr = &dep->descr[i][0];
342     for(j=0;j< (i==DESCR_RECV?DE_NB_RECV_DESCR:DE_NB_SEND_DESCR);j++){
343       r = sys_umap(SELF, VM_D, (vir_bytes)&(loc_descr->descr),
344 			sizeof(de_descr_t), &temp);
345       if(r != OK) panic("sys_umap failed: %d", r);
346 
347       if( ((loc_descr->descr->des[DES_BUF1] & 0x3) != 0) ||
348 	  ((loc_descr->descr->des[DES_BUF2] & 0x3) != 0) ||
349 	  ((temp&0x3)!=0) )
350 	panic("alignment error: 0x%lx", temp);
351 
352       loc_descr++;
353     }
354   }
355 
356   /* Init default values */
357   dep->cur_descr[DESCR_TRAN]=1;
358   dep->cur_descr[DESCR_RECV]=0;
359 }
360 
361 static void do_intr(unsigned int __unused mask)
362 {
363   dpeth_t *dep;
364   u32_t val;
365 
366   dep = &de_state;
367 
368   val = io_inl(CSR_ADDR(dep, CSR5));
369 
370   if(val & CSR5_AIS){
371     panic("Abnormal Int CSR5=: %d", val);
372   }
373 
374   if (val & CSR5_RI)
375     netdriver_recv();
376 
377   if (val & CSR5_TI)
378     netdriver_send();
379 
380   /* ack and reset interrupts */
381   io_outl(CSR_ADDR(dep, CSR5), 0xFFFFFFFF);
382 
383   sys_irqenable(&dep->de_hook);
384 }
385 
386 static void de_reset(const dpeth_t *dep)
387 {
388   io_outl(CSR_ADDR(dep, CSR0), CSR0_SWR);
389 }
390 
391 static void do_stop(void)
392 {
393   de_reset(&de_state);
394 }
395 
396 static void de_hw_conf(const dpeth_t *dep)
397 {
398   u32_t val;
399 
400   /* CSR0 - global host bus prop */
401   val = CSR0_BAR | CSR0_CAL_8;
402   io_outl(CSR_ADDR(dep, CSR0), val);
403 
404   /* CSR3 - Receive list BAR */
405   val = dep->sendrecv_descr_phys_addr[DESCR_RECV];
406   io_outl(CSR_ADDR(dep, CSR3), val);
407 
408   /* CSR4 - Transmit list BAR */
409   val = dep->sendrecv_descr_phys_addr[DESCR_TRAN];
410   io_outl(CSR_ADDR(dep, CSR4), val);
411 
412   /* CSR7 - interrupt mask */
413   val = CSR7_TI | CSR7_RI | CSR7_AI;
414   io_outl(CSR_ADDR(dep, CSR7), val);
415 
416   /* CSR6 - operating mode register */
417   val = CSR6_MBO | CSR6_PS | CSR6_FD | CSR6_HBD |
418     CSR6_PCS | CSR6_SCR | CSR6_TR_00;
419   io_outl(CSR_ADDR(dep, CSR6), val);
420 }
421 
422 static void de_start(const dpeth_t *dep)
423 {
424   u32_t val;
425   val = io_inl(CSR_ADDR(dep, CSR6)) | CSR6_ST | CSR6_SR;
426   io_outl(CSR_ADDR(dep, CSR6), val);
427 }
428 
429 static void de_setup_frame(const dpeth_t *dep, const netdriver_addr_t *addr)
430 {
431   int i;
432   u32_t val;
433 
434   /* this is not perfect... we assume pass all multicast and only
435      filter non-multicast frames */
436   dep->descr[DESCR_TRAN][0].buf1[0] = 0xFF;
437   dep->descr[DESCR_TRAN][0].buf1[1] = 0xFF;
438   dep->descr[DESCR_TRAN][0].buf1[4] = 0xFF;
439   dep->descr[DESCR_TRAN][0].buf1[5] = 0xFF;
440   dep->descr[DESCR_TRAN][0].buf1[8] = 0xFF;
441   dep->descr[DESCR_TRAN][0].buf1[9] = 0xFF;
442   for(i=1;i<16;i++){
443     memset(&(dep->descr[DESCR_TRAN][0].buf1[12*i]), 0, 12);
444     dep->descr[DESCR_TRAN][0].buf1[12*i+0] = addr->na_addr[0];
445     dep->descr[DESCR_TRAN][0].buf1[12*i+1] = addr->na_addr[1];
446     dep->descr[DESCR_TRAN][0].buf1[12*i+4] = addr->na_addr[2];
447     dep->descr[DESCR_TRAN][0].buf1[12*i+5] = addr->na_addr[3];
448     dep->descr[DESCR_TRAN][0].buf1[12*i+8] = addr->na_addr[4];
449     dep->descr[DESCR_TRAN][0].buf1[12*i+9] = addr->na_addr[5];
450   }
451 
452   dep->descr[DESCR_TRAN][0].descr->des[DES0] = DES0_OWN;
453   dep->descr[DESCR_TRAN][0].descr->des[DES1] = DES1_SET |
454     DE_SETUP_FRAME_SIZE | DES1_IC;
455 
456   /* start transmit process to process setup frame */
457   val = io_inl(CSR_ADDR(dep, CSR6)) | CSR6_ST;
458   io_outl(CSR_ADDR(dep, CSR6), val);
459   io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF);
460 }
461 
462 static int do_send(struct netdriver_data *data, size_t size)
463 {
464   static int setup_done = 0;
465   dpeth_t *dep;
466   de_loc_descr_t *descr = NULL;
467 
468   dep = &de_state;
469 
470   descr = &dep->descr[DESCR_TRAN][dep->cur_descr[DESCR_TRAN]];
471 
472   if(( descr->descr->des[DES0] & DES0_OWN)!=0)
473     return SUSPEND;
474 
475   if(!setup_done && (dep->cur_descr[DESCR_TRAN] == 0) ){
476     dep->descr[DESCR_TRAN][0].descr->des[DES0] = 0;
477     setup_done=1;
478   }
479 
480   netdriver_copyin(data, 0, descr->buf1, size);
481 
482   descr->descr->des[DES1] = (descr->descr->des[DES1]&DES1_ER) |
483     DES1_FS | DES1_LS | DES1_IC | size;
484   descr->descr->des[DES0] = DES0_OWN;
485 
486   dep->cur_descr[DESCR_TRAN]++;
487   if(dep->cur_descr[DESCR_TRAN] >= DE_NB_SEND_DESCR)
488     dep->cur_descr[DESCR_TRAN] = 0;
489 
490   io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF);
491 
492   return OK;
493 }
494 
495 static u32_t io_inl(u16_t port)
496 {
497   u32_t value;
498   int rc;
499   if ((rc = sys_inl(port, &value)) != OK)
500     panic("sys_inl failed: %d", rc);
501   return value;
502 }
503 
504 static void io_outl(u16_t port, u32_t value)
505 {
506   int rc;
507   if ((rc = sys_outl(port, value)) != OK)
508     panic("sys_outl failed: %d", rc);
509 }
510