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