skel of new natsemi driver (still in developments)
[people/sha0/gpxe.git] / src / drivers / net / natsemi.c
1 /* natsemi.c - gPXE driver for the NatSemi DP8381x series. 
2  
3
4 */
5
6 #include <stdint.h>
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <io.h>
10 #include <errno.h>
11 #include <timer.h>
12 #include <byteswap.h>
13 #include <gpxe/pci.h>
14 #include <gpxe/if_ether.h>
15 #include <gpxe/ethernet.h>
16 #include <gpxe/iobuf.h>
17 #include <gpxe/netdevice.h>
18 #include <gpxe/spi_bit.h>
19 #include <gpxe/threewire.h>
20 #include <gpxe/nvo.h>
21
22 #define TX_RING_SIZE 4
23 #define NUM_RX_DESC  4
24
25 struct natsemi_tx {
26         uint32_t link;
27         uint32_t cmdsts;
28         uint32_t bufptr;
29 };
30
31 struct natsemi_rx {
32         uint32_t link;
33         uint32_t cmdsts;
34         uint32_t bufptr;
35 };
36
37 struct natsemi_nic {
38         unsigned short ioaddr;
39         unsigned short tx_next;
40         struct natsemi_tx tx[TX_RING_SIZE];
41         struct natsemi_rx rx[NUM_RX_DESC];
42         struct spi_bit_basher spibit;
43         struct spi_device eeprom;
44         struct nvo_block nvo;
45 };
46
47 /* Tuning Parameters */
48 #define TX_FIFO_THRESH  256     /* In bytes, rounded down to 32 byte units. */
49 #define RX_FIFO_THRESH  4       /* Rx buffer level before first PCI xfer.  */
50 #define RX_DMA_BURST    4       /* Maximum PCI burst, '4' is 256 bytes */
51 #define TX_DMA_BURST    4       /* Calculate as 16<<val. */
52 #define TX_IPG          3       /* This is the only valid value */
53 //#define RX_BUF_LEN_IDX        0       /*  */
54 #define RX_BUF_LEN    8192   /*buffer size should be multiple of 32 */ 
55 #define RX_BUF_PAD 4
56 #define RX_BUF_SIZE 1536
57
58
59 /* NATSEMI: Offsets to the device registers.
60    Unlike software-only systems, device drivers interact with complex hardware.
61    It's not useful to define symbolic names for every register bit in the
62    device.
63 */
64 enum register_offsets {
65     ChipCmd      = 0x00, 
66     ChipConfig   = 0x04, 
67     EECtrl       = 0x08, 
68     PCIBusCfg    = 0x0C,
69     IntrStatus   = 0x10, 
70     IntrMask     = 0x14, 
71     IntrEnable   = 0x18,
72     TxRingPtr    = 0x20, 
73     TxConfig     = 0x24,
74     RxRingPtr    = 0x30,
75     RxConfig     = 0x34, 
76     ClkRun       = 0x3C,
77     WOLCmd       = 0x40, 
78     PauseCmd     = 0x44,
79     RxFilterAddr = 0x48, 
80     RxFilterData = 0x4C,
81     BootRomAddr  = 0x50, 
82     BootRomData  = 0x54, 
83     SiliconRev   = 0x58, 
84     StatsCtrl    = 0x5C,
85     StatsData    = 0x60, 
86     RxPktErrs    = 0x60, 
87     RxMissed     = 0x68, 
88     RxCRCErrs    = 0x64,
89     PCIPM        = 0x44,
90     PhyStatus    = 0xC0, 
91     MIntrCtrl    = 0xC4, 
92     MIntrStatus  = 0xC8,
93
94     /* These are from the spec, around page 78... on a separate table. */
95     PGSEL        = 0xCC, 
96     PMDCSR       = 0xE4, 
97     TSTDAT       = 0xFC, 
98     DSPCFG       = 0xF4, 
99     SDCFG        = 0x8C,
100     BasicControl = 0x80,        
101     BasicStatus  = 0x84
102             
103 };
104
105
106
107
108 /* Bit in ChipCmd. */
109 enum ChipCmdBits {
110     ChipReset = 0x100, 
111     RxReset   = 0x20, 
112     TxReset   = 0x10, 
113     RxOff     = 0x08, 
114     RxOn      = 0x04,
115     TxOff     = 0x02, 
116     TxOn      = 0x01
117 }
118
119
120 /* Bits in the RxMode register. */
121 enum rx_mode_bits {
122     AcceptErr          = 0x20,
123     AcceptRunt         = 0x10,
124     AcceptBroadcast    = 0xC0000000,
125     AcceptMulticast    = 0x00200000, 
126     AcceptAllMulticast = 0x20000000,
127     AcceptAllPhys      = 0x10000000, 
128     AcceptMyPhys       = 0x08000000,
129     RxFilterEnable     = 0x80000000
130 };
131
132 /* Bits in network_desc.status */
133 enum desc_status_bits {
134     DescOwn   = 0x80000000, 
135     DescMore  = 0x40000000, 
136     DescIntr  = 0x20000000,
137     DescNoCRC = 0x10000000,
138     DescPktOK = 0x08000000, 
139     RxTooLong = 0x00400000
140 };
141
142
143
144 /*  EEPROM access */
145 #define EE_M1           0x80    /* Mode select bit 1 */
146 #define EE_M0           0x40    /* Mode select bit 0 */
147 #define EE_CS           0x08    /* EEPROM chip select */
148 #define EE_SK           0x04    /* EEPROM shift clock */
149 #define EE_DI           0x02    /* Data in */
150 #define EE_DO           0x01    /* Data out */
151
152 /* Offsets within EEPROM (these are word offsets) */
153 #define EE_MAC 7
154
155 static uint32_t SavedClkRun;    
156
157
158
159 static const uint8_t rtl_ee_bits[] = {
160         [SPI_BIT_SCLK]  = EE_SK,
161         [SPI_BIT_MOSI]  = EE_DI,
162         [SPI_BIT_MISO]  = EE_DO,
163         [SPI_BIT_SS(0)] = ( EE_CS | EE_M1 ),
164 };
165
166 static int rtl_spi_read_bit ( struct bit_basher *basher,
167                               unsigned int bit_id ) {
168         struct rtl8139_nic *rtl = container_of ( basher, struct rtl8139_nic,
169                                                  spibit.basher );
170         uint8_t mask = rtl_ee_bits[bit_id];
171         uint8_t eereg;
172
173         eereg = inb ( rtl->ioaddr + Cfg9346 );
174         return ( eereg & mask );
175 }
176
177 static void rtl_spi_write_bit ( struct bit_basher *basher,
178                                 unsigned int bit_id, unsigned long data ) {
179         struct rtl8139_nic *rtl = container_of ( basher, struct rtl8139_nic,
180                                                  spibit.basher );
181         uint8_t mask = rtl_ee_bits[bit_id];
182         uint8_t eereg;
183
184         eereg = inb ( rtl->ioaddr + Cfg9346 );
185         eereg &= ~mask;
186         eereg |= ( data & mask );
187         outb ( eereg, rtl->ioaddr + Cfg9346 );
188 }
189
190 static struct bit_basher_operations rtl_basher_ops = {
191         .read = rtl_spi_read_bit,
192         .write = rtl_spi_write_bit,
193 };
194
195 /** Portion of EEPROM available for non-volatile stored options
196  *
197  * We use offset 0x40 (i.e. address 0x20), length 0x40.  This block is
198  * marked as VPD in the rtl8139 datasheets, so we use it only if we
199  * detect that the card is not supporting VPD.
200  */
201 static struct nvo_fragment rtl_nvo_fragments[] = {
202         { 0x20, 0x40 },
203         { 0, 0 }
204 };
205
206 /**
207  * Set up for EEPROM access
208  *
209  * @v NAT               NATSEMI NIC
210  */
211  void nat_init_eeprom ( struct natsemi_nic *nat ) {
212         int ee9356;
213         int vpd;
214
215         /* Initialise three-wire bus */
216         nat->spibit.basher.op = &rtl_basher_ops;
217         rtl->spibit.bus.mode = SPI_MODE_THREEWIRE;
218         init_spi_bit_basher ( &rtl->spibit );
219
220         /* Detect EEPROM type and initialise three-wire device */
221         ee9356 = ( inw ( rtl->ioaddr + RxConfig ) & Eeprom9356 );
222         if ( ee9356 ) {
223                 DBG ( "EEPROM is an AT93C56\n" );
224                 init_at93c56 ( &rtl->eeprom, 16 );
225         } else {
226                 DBG ( "EEPROM is an AT93C46\n" );
227                 init_at93c46 ( &rtl->eeprom, 16 );
228         }
229         rtl->eeprom.bus = &rtl->spibit.bus;
230
231         /* Initialise space for non-volatile options, if available */
232         vpd = ( inw ( rtl->ioaddr + Config1 ) & VPDEnable );
233         if ( vpd ) {
234                 DBG ( "EEPROM in use for VPD; cannot use for options\n" );
235         } else {
236                 rtl->nvo.nvs = &rtl->eeprom.nvs;
237                 rtl->nvo.fragments = rtl_nvo_fragments;
238         }
239 }
240
241 /**
242  * Reset NIC
243  *
244  * @v rtl               NATSEMI NIC
245  *
246  * Issues a hardware reset and waits for the reset to complete.
247  */
248 static void nat_reset ( struct nat_nic *nat ) {
249
250         /* Reset chip */
251         outb ( ChipReset, nat->ioaddr + ChipCmd );
252         mdelay ( 10 );
253         memset ( &nat->tx, 0, sizeof ( nat->tx ) );
254         nat->rx.offset = 0;
255
256         /* Restore PME enable bit */
257         outl(SavedClkRun, nat->ioaddr + ClkRun);
258 }
259
260 /**
261  * Open NIC
262  *
263  * @v netdev            Net device
264  * @ret rc              Return status code
265  */
266 static int nat_open ( struct net_device *netdev ) {
267         struct natsemi_nic *nat = netdev->priv;
268         struct io_buffer *iobuf;
269         int i;
270         
271         /* Disable PME:
272         * The PME bit is initialized from the EEPROM contents.
273         * PCI cards probably have PME disabled, but motherboard
274         * implementations may have PME set to enable WakeOnLan. 
275         * With PME set the chip will scan incoming packets but
276         * nothing will be written to memory. */
277         SavedClkRun = inl(nat->ioaddr + ClkRun);
278         outl(SavedClkRun & ~0x100, nat->ioaddr + ClkRun);
279
280                 
281
282
283         /* Program the MAC address TODO enable this comment */
284         /*
285          for ( i = 0 ; i < ETH_ALEN ; i++ )
286                 outb ( netdev->ll_addr[i], rtl->ioaddr + MAC0 + i );
287         */
288         /* Set up RX ring */
289
290         for (i=0;i<NUM_RX_DESC;i++)
291         {
292
293                 iobuf = alloc_iob ( RX_BUF_SIZE );
294                 if (!iobuf)
295                        return -ENOMEM;  
296                 nat->rx[i].link   = virt_to_bus((i+1 < NUM_RX_DESC) ? &nat->rx[i+1] : &nat->rx[0]);
297                 nat->rx[i].cmdsts = (u32) RX_BUF_SIZE;
298                 nat->rx[i].bufptr = virt_to_bus(iobuf->data);
299         }
300
301
302          /* load Receive Descriptor Register */
303         outl(virt_to_bus(&nat->rx[0]), ioaddr + RxRingPtr);
304         DBG("Natsemi Rx descriptor loaded with: %X\n",inl(nat->ioaddr+RingPtr));                
305
306         /* setup Tx ring */
307         outl(virt_to_bus(&nat->tx[0]),nat->ioaddr+TxRingPtr);
308         DBG("Natsemi Tx descriptor loaded with: %X\n",inl(nat->ioaddr+TxRingPtr));
309
310         /* Enables RX */
311         outl(RxFilterEnable|AcceptBroadcast|AcceptAllMulticast|AcceptMyPhys, nat->ioaddr+RxFilterAddr);
312
313         /* Initialize other registers. */
314         /* Configure the PCI bus bursts and FIFO thresholds. */
315         /* Configure for standard, in-spec Ethernet. */
316         if (inl(nat->ioaddr + ChipConfig) & 0x20000000) {       /* Full duplex */
317                 tx_config = 0xD0801002;
318                 rx_config = 0x10000020;
319         } else {
320                 tx_config = 0x10801002;
321                 rx_config = 0x0020;
322         }
323         outl(tx_config, nat->ioaddr + TxConfig);
324         outl(rx_config, nat->ioaddr + RxConfig);
325
326
327
328         /*start the receiver and transmitter */
329         outl(RxOn|TxOn, nat->ioaddr + ChipCmd);
330
331
332         return 0;
333 }
334
335 /**
336  * Close NIC
337  *
338  * @v netdev            Net device
339  */
340 static void rtl_close ( struct net_device *netdev ) {
341         struct rtl8139_nic *rtl = netdev->priv;
342
343         /* Reset the hardware to disable everything in one go */
344         rtl_reset ( rtl );
345
346         /* Free RX ring */
347         free ( rtl->rx.ring );
348         rtl->rx.ring = NULL;
349 }
350
351 /** 
352  * Transmit packet
353  *
354  * @v netdev    Network device
355  * @v iobuf     I/O buffer
356  * @ret rc      Return status code
357  */
358 static int natsemi_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
359         struct natsemi_nic *nat = netdev->priv;
360
361         /* Check for space in TX ring */
362         if ( nat->tx.iobuf[nat->tx.next] != NULL ) {
363                 printf ( "TX overflow\n" );
364                 return -ENOBUFS;
365         }
366
367         /* Pad and align packet */
368         iob_pad ( iobuf, ETH_ZLEN );
369
370         /* Add to TX ring */
371         DBG ( "TX id %d at %lx+%x\n", rtl->tx.next,
372               virt_to_bus ( iobuf->data ), iob_len ( iobuf ) );
373         rtl->tx.iobuf[rtl->tx.next] = iobuf;
374         outl ( virt_to_bus ( iobuf->data ),
375                rtl->ioaddr + TxAddr0 + 4 * rtl->tx.next );
376         outl ( ( ( ( TX_FIFO_THRESH & 0x7e0 ) << 11 ) | iob_len ( iobuf ) ),
377                rtl->ioaddr + TxStatus0 + 4 * rtl->tx.next );
378         rtl->tx.next = ( rtl->tx.next + 1 ) % TX_RING_SIZE;
379
380         return 0;
381 }
382
383 /** 
384  * Poll for received packets
385  *
386  * @v netdev    Network device
387  * @v rx_quota  Maximum number of packets to receive
388  */
389 static void rtl_poll ( struct net_device *netdev, unsigned int rx_quota ) {
390         struct rtl8139_nic *rtl = netdev->priv;
391         unsigned int status;
392         unsigned int tsad;
393         unsigned int rx_status;
394         unsigned int rx_len;
395         struct io_buffer *rx_iob;
396         int wrapped_len;
397         int i;
398
399         /* Acknowledge interrupts */
400         status = inw ( rtl->ioaddr + IntrStatus );
401         if ( ! status )
402                 return;
403         outw ( status, rtl->ioaddr + IntrStatus );
404
405         /* Handle TX completions */
406         tsad = inw ( rtl->ioaddr + TxSummary );
407         for ( i = 0 ; i < TX_RING_SIZE ; i++ ) {
408                 if ( ( rtl->tx.iobuf[i] != NULL ) && ( tsad & ( 1 << i ) ) ) {
409                         DBG ( "TX id %d complete\n", i );
410                         netdev_tx_complete ( netdev, rtl->tx.iobuf[i] );
411                         rtl->tx.iobuf[i] = NULL;
412                 }
413         }
414
415         /* Handle received packets */
416         while ( rx_quota && ! ( inw ( rtl->ioaddr + ChipCmd ) & RxBufEmpty ) ){
417                 rx_status = * ( ( uint16_t * )
418                                 ( rtl->rx.ring + rtl->rx.offset ) );
419                 rx_len = * ( ( uint16_t * )
420                              ( rtl->rx.ring + rtl->rx.offset + 2 ) );
421                 if ( rx_status & RxOK ) {
422                         DBG ( "RX packet at offset %x+%x\n", rtl->rx.offset,
423                               rx_len );
424
425                         rx_iob = alloc_iob ( rx_len );
426                         if ( ! rx_iob ) {
427                                 /* Leave packet for next call to poll() */
428                                 break;
429                         }
430
431                         wrapped_len = ( ( rtl->rx.offset + 4 + rx_len )
432                                         - RX_BUF_LEN );
433                         if ( wrapped_len < 0 )
434                                 wrapped_len = 0;
435
436                         memcpy ( iob_put ( rx_iob, rx_len - wrapped_len ),
437                                  rtl->rx.ring + rtl->rx.offset + 4,
438                                  rx_len - wrapped_len );
439                         memcpy ( iob_put ( rx_iob, wrapped_len ),
440                                  rtl->rx.ring, wrapped_len );
441
442                         netdev_rx ( netdev, rx_iob );
443                         rx_quota--;
444                 } else {
445                         DBG ( "RX bad packet (status %#04x len %d)\n",
446                               rx_status, rx_len );
447                 }
448                 rtl->rx.offset = ( ( ( rtl->rx.offset + 4 + rx_len + 3 ) & ~3 )
449                                    % RX_BUF_LEN );
450                 outw ( rtl->rx.offset - 16, rtl->ioaddr + RxBufPtr );
451         }
452 }
453
454 #if 0
455 static void rtl_irq(struct nic *nic, irq_action_t action)
456 {
457         unsigned int mask;
458         /* Bit of a guess as to which interrupts we should allow */
459         unsigned int interested = ROK | RER | RXOVW | FOVW | SERR;
460
461         switch ( action ) {
462         case DISABLE :
463         case ENABLE :
464                 mask = inw(rtl->ioaddr + IntrMask);
465                 mask = mask & ~interested;
466                 if ( action == ENABLE ) mask = mask | interested;
467                 outw(mask, rtl->ioaddr + IntrMask);
468                 break;
469         case FORCE :
470                 /* Apparently writing a 1 to this read-only bit of a
471                  * read-only and otherwise unrelated register will
472                  * force an interrupt.  If you ever want to see how
473                  * not to write a datasheet, read the one for the
474                  * RTL8139...
475                  */
476                 outb(EROK, rtl->ioaddr + RxEarlyStatus);
477                 break;
478         }
479 }
480 #endif
481
482 /**
483  * Probe PCI device
484  *
485  * @v pci       PCI device
486  * @v id        PCI ID
487  * @ret rc      Return status code
488  */
489 static int nat_probe ( struct pci_device *pci,
490                        const struct pci_device_id *id __unused ) {
491         struct net_device *netdev;
492         struct natsemi_nic *nat = NULL;
493         int registered_netdev = 0;
494         int rc;
495
496         /* Fix up PCI device */
497         adjust_pci_device ( pci );
498
499         /* Allocate net device */
500         netdev = alloc_etherdev ( sizeof ( *nat ) );
501         if ( ! netdev ) {
502                 rc = -ENOMEM;
503                 goto err;
504         }
505         nat = netdev->priv;
506         pci_set_drvdata ( pci, netdev );
507         netdev->dev = &pci->dev;
508         memset ( nat, 0, sizeof ( *nat ) );
509         nat->ioaddr = pci->ioaddr;
510
511         /* Reset the NIC, set up EEPROM access and read MAC address */
512         nat_reset ( nat );
513         /* commenitng two line below. Have to be included in final natsemi.c TODO*/
514         /*
515         nat_init_eeprom ( rtl );
516         nvs_read ( &nat->eeprom.nvs, EE_MAC, netdev->ll_addr, ETH_ALEN );
517         
518         */
519         
520         /* Point to NIC specific routines */
521         netdev->open     = nat_open;
522         netdev->close    = nat_close;
523         netdev->transmit = nat_transmit;
524         netdev->poll     = nat_poll;
525
526         /* Register network device */
527         if ( ( rc = register_netdev ( netdev ) ) != 0 )
528                 goto err;
529         registered_netdev = 1;
530
531         /* Register non-volatile storagei
532          * uncomment lines below in final version*/
533         /*
534          if ( rtl->nvo.nvs ) {
535                 if ( ( rc = nvo_register ( &rtl->nvo ) ) != 0 )
536                         goto err;
537         }
538         */
539
540         return 0;
541
542  err:
543         /* Disable NIC */
544         if ( nat )
545                 nat_reset ( rtl );
546         if ( registered_netdev )
547                 unregister_netdev ( netdev );
548         /* Free net device */
549         free_netdev ( netdev );
550         return rc;
551 }
552
553 /**
554  * Remove PCI device
555  *
556  * @v pci       PCI device
557  */
558 static void rtl_remove ( struct pci_device *pci ) {
559         struct net_device *netdev = pci_get_drvdata ( pci );
560         struct rtl8139_nic *rtl = netdev->priv;
561
562         if ( rtl->nvo.nvs )
563                 nvo_unregister ( &rtl->nvo );
564         unregister_netdev ( netdev );
565         rtl_reset ( rtl );
566         free_netdev ( netdev );
567 }
568
569 static struct pci_device_id rtl8139_nics[] = {
570 PCI_ROM(0x10ec, 0x8129, "rtl8129",       "Realtek 8129"),
571 PCI_ROM(0x10ec, 0x8139, "rtl8139",       "Realtek 8139"),
572 PCI_ROM(0x10ec, 0x8138, "rtl8139b",      "Realtek 8139B"),
573 PCI_ROM(0x1186, 0x1300, "dfe538",        "DFE530TX+/DFE538TX"),
574 PCI_ROM(0x1113, 0x1211, "smc1211-1",     "SMC EZ10/100"),
575 PCI_ROM(0x1112, 0x1211, "smc1211",       "SMC EZ10/100"),
576 PCI_ROM(0x1500, 0x1360, "delta8139",     "Delta Electronics 8139"),
577 PCI_ROM(0x4033, 0x1360, "addtron8139",   "Addtron Technology 8139"),
578 PCI_ROM(0x1186, 0x1340, "dfe690txd",     "D-Link DFE690TXD"),
579 PCI_ROM(0x13d1, 0xab06, "fe2000vx",      "AboCom FE2000VX"),
580 PCI_ROM(0x1259, 0xa117, "allied8139",    "Allied Telesyn 8139"),
581 PCI_ROM(0x14ea, 0xab06, "fnw3603tx",     "Planex FNW-3603-TX"),
582 PCI_ROM(0x14ea, 0xab07, "fnw3800tx",     "Planex FNW-3800-TX"),
583 PCI_ROM(0xffff, 0x8139, "clone-rtl8139", "Cloned 8139"),
584 };
585
586 struct pci_driver rtl8139_driver __pci_driver = {
587         .ids = rtl8139_nics,
588         .id_count = ( sizeof ( rtl8139_nics ) / sizeof ( rtl8139_nics[0] ) ),
589         .probe = rtl_probe,
590         .remove = rtl_remove,
591 };