Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / dev / atm / hea / eni.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
8  * This Host ATM Research Platform ("HARP") file (the "Software") is
9  * made available by Network Computing Services, Inc. ("NetworkCS")
10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
11  * support of any kind.
12  *
13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17  * In no event shall NetworkCS be responsible for any damages, including
18  * but not limited to consequential damages, arising from or relating to
19  * any use of the Software or related support.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/sys/dev/hea/eni.c,v 1.10 1999/08/28 00:41:42 peter Exp $
27  *
28  */
29
30 /*
31  * Efficient ENI adapter support
32  * -----------------------------
33  *
34  * Module supports PCI interface to ENI adapter
35  *
36  */
37
38 #include <netatm/kern_include.h>
39
40 #include <dev/hea/eni_stats.h>
41 #include <dev/hea/eni.h>
42 #include <dev/hea/eni_var.h>
43
44 #ifndef lint
45 __RCSID("@(#) $FreeBSD: src/sys/dev/hea/eni.c,v 1.10 1999/08/28 00:41:42 peter Exp $");
46 #endif
47
48 /*
49  * Typedef local functions
50  */
51 static const char       *eni_pci_probe __P((pcici_t, pcidi_t));
52 static void     eni_pci_attach __P((pcici_t, int));
53 static int      eni_get_ack __P((Eni_unit *));
54 static int      eni_get_sebyte __P((Eni_unit *));
55 static void     eni_read_seeprom __P((Eni_unit *));
56 #ifdef  __FreeBSD__
57 #if BSD < 199506
58 static int      eni_pci_shutdown __P((struct kern_devconf *, int));
59 #else
60 static void     eni_pci_shutdown __P((void *, int));
61 #endif
62 static void     eni_pci_reset __P((Eni_unit *));
63 #endif  /* __FreeBSD__ */
64
65 /*
66  * Used by kernel to return number of claimed devices
67  */
68 #ifdef  __FreeBSD__
69 static u_long eni_nunits;
70
71 static struct pci_device eni_pci_device = {
72         ENI_DEV_NAME,
73         eni_pci_probe,
74         eni_pci_attach,
75         &eni_nunits,
76 #if BSD < 199506
77         eni_pci_shutdown
78 #else
79         NULL
80 #endif
81 };
82
83 COMPAT_PCI_DRIVER (eni_pci, eni_pci_device);
84 #endif  /* __FreeBSD__ */
85
86 /*
87  * Called by kernel with PCI device_id which was read from the PCI
88  * register set. If the identified vendor is Efficient, see if we
89  * recognize the particular device. If so, return an identifying string,
90  * if not, return null.
91  *
92  * Arguments:
93  *      config_id       PCI config token
94  *      device_id       contents of PCI device ID register
95  *
96  * Returns:
97  *      string          Identifying string if we will handle this device
98  *      NULL            unrecognized vendor/device
99  *
100  */
101 static const char *
102 eni_pci_probe ( pcici_t config_id, pcidi_t device_id )
103 {
104
105         if ( (device_id & 0xFFFF) == EFF_VENDOR_ID ) {
106                 switch ( (device_id >> 16) ) {
107                         case EFF_DEV_ID:
108                                 return ( "Efficient ENI ATM Adapter" );
109 /* NOTREACHED */
110                                 break;
111                 }
112         }
113
114         return ( NULL );
115 }
116
117 /*
118  * The ENI-155p adapter uses an ATMEL AT24C01 serial EEPROM to store
119  * configuration information. The SEEPROM is accessed via two wires,
120  * CLOCK and DATA, which are accessible via the PCI configuration
121  * registers. The following macros manipulate the lines to access the
122  * SEEPROM. See http://www.atmel.com/atmel/products/prod162.htm for
123  * a description of the AT24C01 part. Value to be read/written is
124  * part of the per unit structure.
125  */
126 /*
127  * Write bits to SEEPROM
128  */
129 #define WRITE_SEEPROM() (                                               \
130     {                                                                   \
131         (void) pci_conf_write ( eup->eu_pcitag, SEEPROM,                \
132                 eup->eu_sevar );                                        \
133         DELAY(SEPROM_DELAY);                                            \
134     }                                                                   \
135 )
136 /*
137  * Stobe first the DATA, then the CLK lines high
138  */
139 #define STROBE_HIGH()   (                                               \
140     {                                                                   \
141         eup->eu_sevar |= SEPROM_DATA; WRITE_SEEPROM();                  \
142         eup->eu_sevar |= SEPROM_CLK;  WRITE_SEEPROM();                  \
143     }                                                                   \
144 )
145 /*
146  * Strobe first the CLK, then the DATA lines high
147  */
148 #define INV_STROBE_HIGH()       (                                       \
149     {                                                                   \
150         eup->eu_sevar |= SEPROM_CLK;  WRITE_SEEPROM();                  \
151         eup->eu_sevar |= SEPROM_DATA; WRITE_SEEPROM();                  \
152     }                                                                   \
153 )
154 /*
155  * Strobe first the CLK, then the DATA lines low - companion to
156  * STROBE_HIGH()
157  */
158 #define STROBE_LOW()    (                                               \
159     {                                                                   \
160         eup->eu_sevar &= ~SEPROM_CLK;  WRITE_SEEPROM();                 \
161         eup->eu_sevar &= ~SEPROM_DATA; WRITE_SEEPROM();                 \
162     }                                                                   \
163 )
164 /*
165  * Strobe first the DATA, then the CLK lines low - companion to
166  * INV_STROBE_HIGH()
167  */
168 #define INV_STROBE_LOW()        (                                       \
169     {                                                                   \
170         eup->eu_sevar &= ~SEPROM_DATA; WRITE_SEEPROM();                 \
171         eup->eu_sevar &= ~SEPROM_CLK;  WRITE_SEEPROM();                 \
172     }                                                                   \
173 )
174 /*
175  * Strobe the CLK line high, then low
176  */
177 #define STROBE_CLK()    (                                               \
178     {                                                                   \
179         eup->eu_sevar |= SEPROM_CLK;   WRITE_SEEPROM();                 \
180         eup->eu_sevar &= ~SEPROM_CLK;  WRITE_SEEPROM();                 \
181     }                                                                   \
182 )
183
184 /*
185  * Look for a positive ACK from the SEEPROM. Cycle begins by asserting
186  * the DATA line, then the CLK line. The DATA line is then read to
187  * retrieve the ACK status, and then the cycle is finished by deasserting
188  * the CLK line, and asserting the DATA line.
189  *
190  * Arguments:
191  *      eup             pointer to per unit structure
192  *
193  * Returns:
194  *      0/1             value of ACK
195  *
196  */
197 static int
198 eni_get_ack ( eup )
199         Eni_unit        *eup;
200 {
201         int             ack;
202
203         STROBE_HIGH();
204         /*
205          * Read DATA line from SEPROM
206          */
207         eup->eu_sevar = pci_conf_read ( eup->eu_pcitag, SEEPROM );
208         DELAY ( SEPROM_DELAY );
209         ack = eup->eu_sevar & SEPROM_DATA;
210
211         eup->eu_sevar &= ~SEPROM_CLK;
212         WRITE_SEEPROM ();
213         eup->eu_sevar |= SEPROM_DATA;
214         WRITE_SEEPROM ();
215
216         return ( ack );
217 }
218
219 /*
220  * Read a byte from the SEEPROM. Data is read as 8 bits. There are two types
221  * of read operations. The first is a single byte read, the second is
222  * multiple sequential bytes read. Both cycles begin with a 'START' operation,
223  * followed by a memory address word. Following the memory address, the
224  * SEEPROM will send a data byte, followed by an ACK. If the host responds
225  * with a 'STOP' operation, then a single byte cycle is performed. If the
226  * host responds with an 'ACK', then the memory address is incremented, and
227  * the next sequential memory byte is serialized.
228  *
229  * Arguments:
230  *      eup             pointer to per unit structure
231  *
232  * Returns:
233  *      val             value of byte read from SEEPROM
234  *
235  */
236 static int
237 eni_get_sebyte( eup )
238         Eni_unit        *eup;
239 {
240         int     i;
241         int     data;
242         int     rval;
243
244         /* Initial value */
245         rval = 0;
246         /* Read 8 bits */
247         for ( i = 0; i < 8; i++ ) {
248                 /* Shift bits to left so the next bit goes to position 0 */
249                 rval <<= 1;
250                 /* Indicate we're ready to read bit */
251                 STROBE_HIGH();
252                 /*
253                  * Read DATA line from SEPROM
254                  */
255                 data = pci_conf_read ( eup->eu_pcitag, SEEPROM );
256                 DELAY ( SEPROM_DELAY );
257                 /* (Possibly) mask bit into accumulating value */
258                 if ( data & SEPROM_DATA )
259                         rval |= 1;              /* If DATA bit '1' */
260                 /* Indicate we're done reading this bit */
261                 STROBE_LOW();
262         }
263
264         /* Return acquired byte */
265         return ( rval );
266 }
267
268 /*
269  * The AT24C01 is a 1024 bit part organized as 128 words by 8 bits.
270  * We will read the entire contents into the per unit structure. Later,
271  * we'll retrieve the MAC address and serial number from the data read.
272  *
273  * Arguments:
274  *      eup             pointer to per unit structure
275  *
276  * Returns:
277  *      none
278  *
279  */
280 static void
281 eni_read_seeprom ( eup )
282         Eni_unit        *eup;
283 {
284         int     addr;
285         int     i, j;
286
287         /*
288          * Set initial state
289          */
290         eup->eu_sevar = SEPROM_DATA | SEPROM_CLK;
291         WRITE_SEEPROM ();
292
293         /* Loop for all bytes */
294         for ( i = 0; i < SEPROM_SIZE ; i++ ) {
295                 /* Send START operation */
296                 STROBE_HIGH();
297                 INV_STROBE_LOW();
298
299                 /*
300                  * Send address. Addresses are sent as 7 bits plus
301                  * last bit high.
302                  */
303                 addr = ((i) << 1) + 1;
304                 /*
305                  * Start with high order bit first working toward low
306                  * order bit.
307                  */
308                 for ( j = 7; j >= 0; j-- ) {
309                         /* Set current bit value */
310                         eup->eu_sevar = ( addr >> j ) & 1 ?
311                             eup->eu_sevar | SEPROM_DATA :
312                                 eup->eu_sevar & ~SEPROM_DATA;
313                         WRITE_SEEPROM ();
314                         /* Indicate we've sent it */
315                         STROBE_CLK();
316                 }
317                 /*
318                  * We expect a zero ACK after sending the address
319                  */
320                 if ( !eni_get_ack ( eup ) ) {
321                         /* Address okay - read data byte */
322                         eup->eu_seeprom[i] = eni_get_sebyte ( eup );
323                         /* Grab but ignore the ACK op */
324                         (void) eni_get_ack ( eup );
325                 } else {
326                         /* Address ACK was bad - can't retrieve data byte */
327                         eup->eu_seeprom[i] = 0xff;
328                 }
329         }
330
331         return;
332 }
333
334 /*
335  * The kernel has found a device which we are willing to support.
336  * We are now being called to do any necessary work to make the
337  * device initially usable. In our case, this means allocating
338  * structure memory, configuring registers, mapping device
339  * memory, setting pointers, registering with the core services,
340  * and doing the initial PDU processing configuration.
341  *
342  * Arguments:
343  *      config_id               PCI device token
344  *      unit                    instance of the unit
345  *
346  * Returns:
347  *      none            
348  *
349  */
350 static void
351 eni_pci_attach ( pcici_t config_id, int unit )
352 {
353         vm_offset_t     va;
354         vm_offset_t     pa;
355         Eni_unit        *eup;
356         long            val;
357
358         /*
359          * Just checking...
360          */
361         if ( unit >= ENI_MAX_UNITS ) {
362                 log ( LOG_ERR, "%s%d: too many devices\n",
363                         ENI_DEV_NAME, unit );
364                 return;
365         }
366
367         /*
368          * Make sure this isn't a duplicate unit
369          */
370         if ( eni_units[unit] != NULL )
371                 return;
372
373         /*
374          * Allocate a new unit structure
375          */
376         eup = (Eni_unit *) atm_dev_alloc ( sizeof(Eni_unit), sizeof(int), 0 );
377         if ( eup == NULL )
378                 return;
379
380         /*
381          * Start initializing it
382          */
383         eup->eu_unit = unit;
384         eup->eu_mtu = ENI_IFF_MTU;
385         eup->eu_pcitag = config_id;
386         eup->eu_ioctl = eni_atm_ioctl;
387         eup->eu_instvcc = eni_instvcc;
388         eup->eu_openvcc = eni_openvcc;
389         eup->eu_closevcc = eni_closevcc;
390         eup->eu_output = eni_output;
391         eup->eu_vcc_pool = &eni_vcc_pool;
392         eup->eu_nif_pool = &eni_nif_pool;
393
394         /*
395          * Enable Memory Mapping / Bus Mastering 
396          */
397         val = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG);
398         val |= (PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
399         pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, val);
400
401         /*
402          * Map in adapter RAM
403          */
404         val = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG);
405         if ((val & PCIM_CMD_MEMEN) == 0) {
406                 log(LOG_ERR, "%s%d: memory mapping not enabled\n", 
407                         ENI_DEV_NAME, unit);
408                 goto failed;
409         }
410         if ( ( pci_map_mem ( config_id, PCI_MAP_REG_START, &va, &pa ) ) == 0 )
411         {
412                 log(LOG_ERR, "%s%d: unable to map memory\n", 
413                         ENI_DEV_NAME, unit);
414                 goto failed;
415         }
416         /*
417          * Map okay - retain address assigned
418          */
419         eup->eu_base = (Eni_mem)va;
420         eup->eu_ram = (Eni_mem)(eup->eu_base + RAM_OFFSET);
421
422         /*
423          * Map memory structures into adapter space
424          */
425         eup->eu_suni = (Eni_mem)(eup->eu_base + SUNI_OFFSET);
426         eup->eu_midway = (Eni_mem)(eup->eu_base + MIDWAY_OFFSET);
427         eup->eu_vcitbl = (VCI_Table *)(eup->eu_base + VCITBL_OFFSET);
428         eup->eu_rxdma = (Eni_mem)(eup->eu_base + RXQUEUE_OFFSET);
429         eup->eu_txdma = (Eni_mem)(eup->eu_base + TXQUEUE_OFFSET);
430         eup->eu_svclist = (Eni_mem)(eup->eu_base + SVCLIST_OFFSET);
431         eup->eu_servread = 0;
432
433         /*
434          * Reset the midway chip
435          */
436         eup->eu_midway[MIDWAY_ID] = MIDWAY_RESET;
437
438         /*
439          * Size and test adapter memory. Initialize our adapter memory
440          * allocater.
441          */
442         if ( eni_init_memory ( eup ) < 0 ) {
443                 /*
444                  * Adapter memory test failed. Clean up and
445                  * return.
446                  */
447                 log(LOG_ERR, "%s%d: memory test failed\n", 
448                         ENI_DEV_NAME, unit);
449                 goto failed;
450         }
451
452         /*
453          * Read the contents of the SEEPROM
454          */
455         eni_read_seeprom ( eup );
456         /*
457          * Copy MAC address to PIF and config structures
458          */
459         KM_COPY ( (caddr_t)&eup->eu_seeprom[SEPROM_MAC_OFF],
460             (caddr_t)&eup->eu_pif.pif_macaddr, sizeof(struct mac_addr) );
461         eup->eu_config.ac_macaddr = eup->eu_pif.pif_macaddr;
462
463         /*
464          * Copy serial number into config space
465          */
466         eup->eu_config.ac_serial =
467                 ntohl(*(u_long *)&eup->eu_seeprom[SEPROM_SN_OFF]);
468
469         /*
470          * Convert Endianess on DMA
471          */
472         val = pci_conf_read ( config_id, PCI_CONTROL_REG );
473         val |= ENDIAN_SWAP_DMA;
474         pci_conf_write ( config_id, PCI_CONTROL_REG, val );
475
476         /*
477          * Map interrupt in
478          */
479         if ( !pci_map_int ( config_id, eni_intr, (void *)eup, &net_imask ) )
480         {
481                 log(LOG_ERR, "%s%d: unable to map interrupt\n", 
482                         ENI_DEV_NAME, unit);
483                 goto failed;
484         }
485
486         /*
487          * Setup some of the adapter configuration
488          */
489         /*
490          * Get MIDWAY ID
491          */
492         val = eup->eu_midway[MIDWAY_ID];
493         eup->eu_config.ac_vendor = VENDOR_ENI;
494         eup->eu_config.ac_vendapi = VENDAPI_ENI_1;
495         eup->eu_config.ac_device = DEV_ENI_155P;
496         eup->eu_config.ac_media = val & MEDIA_MASK ? MEDIA_UTP155 : MEDIA_OC3C;
497         eup->eu_pif.pif_pcr = ATM_PCR_OC3C;
498         eup->eu_config.ac_bustype = BUS_PCI;
499         eup->eu_config.ac_busslot = config_id->bus << 8 | config_id->slot;
500
501         /*
502          * Make a hw version number from the ID register values.
503          * Format: {Midway ID}.{Mother board ID}.{Daughter board ID}
504          */
505         snprintf ( eup->eu_config.ac_hard_vers,
506             sizeof ( eup->eu_config.ac_hard_vers ),
507                 "%ld/%ld/%ld",
508                 (val >> ID_SHIFT) & ID_MASK,
509                 (val >> MID_SHIFT) & MID_MASK,
510                 (val >> DID_SHIFT) & DID_MASK );
511
512         /*
513          * There is no software version number
514          */
515         eup->eu_config.ac_firm_vers[0] = '\0';
516
517         /*
518          * Save device ram info for user-level programs
519          * NOTE: This really points to start of EEPROM
520          * and includes all the device registers in the
521          * lower 2 Megabytes.
522          */
523         eup->eu_config.ac_ram = (long)eup->eu_base;
524         eup->eu_config.ac_ramsize = eup->eu_ramsize + ENI_REG_SIZE;
525
526         /*
527          * Setup max VPI/VCI values
528          */
529         eup->eu_pif.pif_maxvpi = ENI_MAX_VPI;
530         eup->eu_pif.pif_maxvci = ENI_MAX_VCI;
531
532         /*
533          * Register this interface with ATM core services
534          */
535         if ( atm_physif_register
536                 ( (Cmn_unit *)eup, ENI_DEV_NAME, eni_services ) != 0 )
537         {
538                 /*
539                  * Registration failed - back everything out
540                  */
541                 log(LOG_ERR, "%s%d: atm_physif_register failed\n", 
542                         ENI_DEV_NAME, unit);
543                 goto failed;
544         }
545
546         eni_units[unit] = eup;
547
548 #if BSD >= 199506
549         /*
550          * Add hook to out shutdown function
551          */
552         EVENTHANDLER_REGISTER(shutdown_post_sync, eni_pci_shutdown, eup,
553                               SHUTDOWN_PRI_DEFAULT);
554         
555 #endif
556
557         /*
558          * Initialize driver processing
559          */
560         if ( eni_init ( eup ) ) {
561                 log(LOG_ERR, "%s%d: adapter init failed\n", 
562                         ENI_DEV_NAME, unit);
563                 goto failed;
564         }
565
566         return;
567
568 failed:
569         /*
570          * Attach failed - clean up
571          */
572         eni_pci_reset(eup);
573         (void) pci_unmap_int(config_id);
574         atm_dev_free(eup);
575         return;
576 }
577
578 /*
579  * Device reset routine
580  *
581  * Arguments:
582  *      eup                     pointer to per unit structure
583  *
584  * Returns:
585  *      none
586  *
587  */
588 static void
589 eni_pci_reset ( eup )
590         Eni_unit *eup;
591 {
592
593         /*
594          * We should really close down any open VCI's and
595          * release all memory (TX and RX) buffers. For now,
596          * we assume we're shutting the card down for good.
597          */
598
599         if (eup->eu_midway) {
600                 /*
601                  * Issue RESET command to Midway chip
602                  */
603                 eup->eu_midway[MIDWAY_ID] = MIDWAY_RESET;
604
605                 /*
606                  * Delay to allow everything to terminate
607                  */
608                 DELAY ( MIDWAY_DELAY );
609         }
610
611         return;
612 }
613
614 #ifdef  __FreeBSD__
615 #if BSD < 199506
616 /*
617  * Device shutdown routine
618  *
619  * Arguments:
620  *      kdc             pointer to device's configuration table
621  *      force           forced shutdown flag
622  *
623  * Returns:
624  *      none
625  *
626  */
627 static int
628 eni_pci_shutdown ( kdc, force )
629         struct kern_devconf     *kdc;
630         int                     force;
631 {
632         Eni_unit        *eup = NULL;
633
634         if ( kdc->kdc_unit < eni_nunits ) {
635
636                 eup = eni_units[kdc->kdc_unit];
637                 if ( eup != NULL ) {
638                         /* Do device reset */
639                         eni_pci_reset ( eup );
640                 }
641         }
642
643         (void) dev_detach ( kdc );
644         return ( 0 );
645 }
646 #else
647 /*
648  * Device shutdown routine
649  *
650  * Arguments:
651  *      howto           type of shutdown
652  *      eup             pointer to device unit structure
653  *
654  * Returns:
655  *      none
656  *
657  */
658 static void
659 eni_pci_shutdown ( eup, howto )
660         void    *eup;
661         int     howto;
662 {
663
664         /* Do device reset */
665         eni_pci_reset ( eup );
666
667 }
668 #endif  /* BSD < 199506 */
669 #endif  /* __FreeBSD__ */