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