3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
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.
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.
21 * Copyright 1994-1998 Network Computing Services, Inc.
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
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.11 2008/03/01 22:03:13 swildner Exp $
31 * Efficient ENI adapter support
32 * -----------------------------
34 * Module supports PCI interface to ENI adapter
38 #include <netproto/atm/kern_include.h>
40 #include "eni_stats.h"
45 * Typedef local functions
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 static void eni_pci_shutdown (void *, int);
53 static void eni_pci_reset (Eni_unit
*);
56 * Used by kernel to return number of claimed devices
58 static u_long eni_nunits
;
60 static struct pci_device eni_pci_device
= {
68 COMPAT_PCI_DRIVER (eni_pci
, eni_pci_device
);
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.
77 * config_id PCI config token
78 * device_id contents of PCI device ID register
81 * string Identifying string if we will handle this device
82 * NULL unrecognized vendor/device
86 eni_pci_probe ( pcici_t config_id
, pcidi_t device_id
)
89 if ( (device_id
& 0xFFFF) == EFF_VENDOR_ID
) {
90 switch ( (device_id
>> 16) ) {
92 return ( "Efficient ENI ATM Adapter" );
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.
111 * Write bits to SEEPROM
113 #define WRITE_SEEPROM() ( \
115 (void) pci_conf_write ( eup->eu_pcitag, SEEPROM, \
117 DELAY(SEPROM_DELAY); \
121 * Stobe first the DATA, then the CLK lines high
123 #define STROBE_HIGH() ( \
125 eup->eu_sevar |= SEPROM_DATA; WRITE_SEEPROM(); \
126 eup->eu_sevar |= SEPROM_CLK; WRITE_SEEPROM(); \
130 * Strobe first the CLK, then the DATA lines high
132 #define INV_STROBE_HIGH() ( \
134 eup->eu_sevar |= SEPROM_CLK; WRITE_SEEPROM(); \
135 eup->eu_sevar |= SEPROM_DATA; WRITE_SEEPROM(); \
139 * Strobe first the CLK, then the DATA lines low - companion to
142 #define STROBE_LOW() ( \
144 eup->eu_sevar &= ~SEPROM_CLK; WRITE_SEEPROM(); \
145 eup->eu_sevar &= ~SEPROM_DATA; WRITE_SEEPROM(); \
149 * Strobe first the DATA, then the CLK lines low - companion to
152 #define INV_STROBE_LOW() ( \
154 eup->eu_sevar &= ~SEPROM_DATA; WRITE_SEEPROM(); \
155 eup->eu_sevar &= ~SEPROM_CLK; WRITE_SEEPROM(); \
159 * Strobe the CLK line high, then low
161 #define STROBE_CLK() ( \
163 eup->eu_sevar |= SEPROM_CLK; WRITE_SEEPROM(); \
164 eup->eu_sevar &= ~SEPROM_CLK; WRITE_SEEPROM(); \
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.
175 * eup pointer to per unit structure
182 eni_get_ack(Eni_unit
*eup
)
188 * Read DATA line from SEPROM
190 eup
->eu_sevar
= pci_conf_read ( eup
->eu_pcitag
, SEEPROM
);
191 DELAY ( SEPROM_DELAY
);
192 ack
= eup
->eu_sevar
& SEPROM_DATA
;
194 eup
->eu_sevar
&= ~SEPROM_CLK
;
196 eup
->eu_sevar
|= SEPROM_DATA
;
203 * Read a byte from the SEEPROM. Data is read as 8 bits. There are two types
204 * of read operations. The first is a single byte read, the second is
205 * multiple sequential bytes read. Both cycles begin with a 'START' operation,
206 * followed by a memory address word. Following the memory address, the
207 * SEEPROM will send a data byte, followed by an ACK. If the host responds
208 * with a 'STOP' operation, then a single byte cycle is performed. If the
209 * host responds with an 'ACK', then the memory address is incremented, and
210 * the next sequential memory byte is serialized.
213 * eup pointer to per unit structure
216 * val value of byte read from SEEPROM
220 eni_get_sebyte(Eni_unit
*eup
)
229 for ( i
= 0; i
< 8; i
++ ) {
230 /* Shift bits to left so the next bit goes to position 0 */
232 /* Indicate we're ready to read bit */
235 * Read DATA line from SEPROM
237 data
= pci_conf_read ( eup
->eu_pcitag
, SEEPROM
);
238 DELAY ( SEPROM_DELAY
);
239 /* (Possibly) mask bit into accumulating value */
240 if ( data
& SEPROM_DATA
)
241 rval
|= 1; /* If DATA bit '1' */
242 /* Indicate we're done reading this bit */
246 /* Return acquired byte */
251 * The AT24C01 is a 1024 bit part organized as 128 words by 8 bits.
252 * We will read the entire contents into the per unit structure. Later,
253 * we'll retrieve the MAC address and serial number from the data read.
256 * eup pointer to per unit structure
263 eni_read_seeprom(Eni_unit
*eup
)
271 eup
->eu_sevar
= SEPROM_DATA
| SEPROM_CLK
;
274 /* Loop for all bytes */
275 for ( i
= 0; i
< SEPROM_SIZE
; i
++ ) {
276 /* Send START operation */
281 * Send address. Addresses are sent as 7 bits plus
284 addr
= ((i
) << 1) + 1;
286 * Start with high order bit first working toward low
289 for ( j
= 7; j
>= 0; j
-- ) {
290 /* Set current bit value */
291 eup
->eu_sevar
= ( addr
>> j
) & 1 ?
292 eup
->eu_sevar
| SEPROM_DATA
:
293 eup
->eu_sevar
& ~SEPROM_DATA
;
295 /* Indicate we've sent it */
299 * We expect a zero ACK after sending the address
301 if ( !eni_get_ack ( eup
) ) {
302 /* Address okay - read data byte */
303 eup
->eu_seeprom
[i
] = eni_get_sebyte ( eup
);
304 /* Grab but ignore the ACK op */
305 (void) eni_get_ack ( eup
);
307 /* Address ACK was bad - can't retrieve data byte */
308 eup
->eu_seeprom
[i
] = 0xff;
316 * The kernel has found a device which we are willing to support.
317 * We are now being called to do any necessary work to make the
318 * device initially usable. In our case, this means allocating
319 * structure memory, configuring registers, mapping device
320 * memory, setting pointers, registering with the core services,
321 * and doing the initial PDU processing configuration.
324 * config_id PCI device token
325 * unit instance of the unit
332 eni_pci_attach ( pcici_t config_id
, int unit
)
342 if ( unit
>= ENI_MAX_UNITS
) {
343 log ( LOG_ERR
, "%s%d: too many devices\n",
344 ENI_DEV_NAME
, unit
);
349 * Make sure this isn't a duplicate unit
351 if ( eni_units
[unit
] != NULL
)
355 * Allocate a new unit structure
357 eup
= (Eni_unit
*) atm_dev_alloc ( sizeof(Eni_unit
), sizeof(int), 0 );
362 * Start initializing it
365 eup
->eu_mtu
= ENI_IFF_MTU
;
366 eup
->eu_pcitag
= config_id
;
367 eup
->eu_ioctl
= eni_atm_ioctl
;
368 eup
->eu_instvcc
= eni_instvcc
;
369 eup
->eu_openvcc
= eni_openvcc
;
370 eup
->eu_closevcc
= eni_closevcc
;
371 eup
->eu_output
= eni_output
;
372 eup
->eu_vcc_pool
= &eni_vcc_pool
;
373 eup
->eu_nif_pool
= &eni_nif_pool
;
376 * Enable Memory Mapping / Bus Mastering
378 val
= pci_conf_read(config_id
, PCI_COMMAND_STATUS_REG
);
379 val
|= (PCIM_CMD_MEMEN
| PCIM_CMD_BUSMASTEREN
);
380 pci_conf_write(config_id
, PCI_COMMAND_STATUS_REG
, val
);
385 val
= pci_conf_read(config_id
, PCI_COMMAND_STATUS_REG
);
386 if ((val
& PCIM_CMD_MEMEN
) == 0) {
387 log(LOG_ERR
, "%s%d: memory mapping not enabled\n",
391 if ( ( pci_map_mem ( config_id
, PCI_MAP_REG_START
, &va
, &pa
) ) == 0 )
393 log(LOG_ERR
, "%s%d: unable to map memory\n",
398 * Map okay - retain address assigned
400 eup
->eu_base
= (Eni_mem
)va
;
401 eup
->eu_ram
= (Eni_mem
)(eup
->eu_base
+ RAM_OFFSET
);
404 * Map memory structures into adapter space
406 eup
->eu_suni
= (Eni_mem
)(eup
->eu_base
+ SUNI_OFFSET
);
407 eup
->eu_midway
= (Eni_mem
)(eup
->eu_base
+ MIDWAY_OFFSET
);
408 eup
->eu_vcitbl
= (VCI_Table
*)(eup
->eu_base
+ VCITBL_OFFSET
);
409 eup
->eu_rxdma
= (Eni_mem
)(eup
->eu_base
+ RXQUEUE_OFFSET
);
410 eup
->eu_txdma
= (Eni_mem
)(eup
->eu_base
+ TXQUEUE_OFFSET
);
411 eup
->eu_svclist
= (Eni_mem
)(eup
->eu_base
+ SVCLIST_OFFSET
);
412 eup
->eu_servread
= 0;
415 * Reset the midway chip
417 eup
->eu_midway
[MIDWAY_ID
] = MIDWAY_RESET
;
420 * Size and test adapter memory. Initialize our adapter memory
423 if ( eni_init_memory ( eup
) < 0 ) {
425 * Adapter memory test failed. Clean up and
428 log(LOG_ERR
, "%s%d: memory test failed\n",
434 * Read the contents of the SEEPROM
436 eni_read_seeprom ( eup
);
438 * Copy MAC address to PIF and config structures
440 KM_COPY ( (caddr_t
)&eup
->eu_seeprom
[SEPROM_MAC_OFF
],
441 (caddr_t
)&eup
->eu_pif
.pif_macaddr
, sizeof(struct mac_addr
) );
442 eup
->eu_config
.ac_macaddr
= eup
->eu_pif
.pif_macaddr
;
445 * Copy serial number into config space
447 eup
->eu_config
.ac_serial
=
448 ntohl(*(u_long
*)&eup
->eu_seeprom
[SEPROM_SN_OFF
]);
451 * Convert Endianess on DMA
453 val
= pci_conf_read ( config_id
, PCI_CONTROL_REG
);
454 val
|= ENDIAN_SWAP_DMA
;
455 pci_conf_write ( config_id
, PCI_CONTROL_REG
, val
);
460 if ( !pci_map_int ( config_id
, eni_intr
, (void *)eup
) )
462 log(LOG_ERR
, "%s%d: unable to map interrupt\n",
468 * Setup some of the adapter configuration
473 val
= eup
->eu_midway
[MIDWAY_ID
];
474 eup
->eu_config
.ac_vendor
= VENDOR_ENI
;
475 eup
->eu_config
.ac_vendapi
= VENDAPI_ENI_1
;
476 eup
->eu_config
.ac_device
= DEV_ENI_155P
;
477 eup
->eu_config
.ac_media
= val
& MEDIA_MASK
? MEDIA_UTP155
: MEDIA_OC3C
;
478 eup
->eu_pif
.pif_pcr
= ATM_PCR_OC3C
;
479 eup
->eu_config
.ac_bustype
= BUS_PCI
;
480 eup
->eu_config
.ac_busslot
= config_id
->bus
<< 8 | config_id
->slot
;
483 * Make a hw version number from the ID register values.
484 * Format: {Midway ID}.{Mother board ID}.{Daughter board ID}
486 ksnprintf ( eup
->eu_config
.ac_hard_vers
,
487 sizeof ( eup
->eu_config
.ac_hard_vers
),
489 (val
>> ID_SHIFT
) & ID_MASK
,
490 (val
>> MID_SHIFT
) & MID_MASK
,
491 (val
>> DID_SHIFT
) & DID_MASK
);
494 * There is no software version number
496 eup
->eu_config
.ac_firm_vers
[0] = '\0';
499 * Save device ram info for user-level programs
500 * NOTE: This really points to start of EEPROM
501 * and includes all the device registers in the
504 eup
->eu_config
.ac_ram
= (long)eup
->eu_base
;
505 eup
->eu_config
.ac_ramsize
= eup
->eu_ramsize
+ ENI_REG_SIZE
;
508 * Setup max VPI/VCI values
510 eup
->eu_pif
.pif_maxvpi
= ENI_MAX_VPI
;
511 eup
->eu_pif
.pif_maxvci
= ENI_MAX_VCI
;
514 * Register this interface with ATM core services
516 if ( atm_physif_register
517 ( (Cmn_unit
*)eup
, ENI_DEV_NAME
, eni_services
) != 0 )
520 * Registration failed - back everything out
522 log(LOG_ERR
, "%s%d: atm_physif_register failed\n",
527 eni_units
[unit
] = eup
;
530 * Add hook to out shutdown function
532 EVENTHANDLER_REGISTER(shutdown_post_sync
, eni_pci_shutdown
, eup
,
533 SHUTDOWN_PRI_DRIVER
);
536 * Initialize driver processing
538 if ( eni_init ( eup
) ) {
539 log(LOG_ERR
, "%s%d: adapter init failed\n",
548 * Attach failed - clean up
551 (void) pci_unmap_int(config_id
);
557 * Device reset routine
560 * eup pointer to per unit structure
567 eni_pci_reset(Eni_unit
*eup
)
571 * We should really close down any open VCI's and
572 * release all memory (TX and RX) buffers. For now,
573 * we assume we're shutting the card down for good.
576 if (eup
->eu_midway
) {
578 * Issue RESET command to Midway chip
580 eup
->eu_midway
[MIDWAY_ID
] = MIDWAY_RESET
;
583 * Delay to allow everything to terminate
585 DELAY ( MIDWAY_DELAY
);
592 * Device shutdown routine
595 * howto type of shutdown
596 * eup pointer to device unit structure
603 eni_pci_shutdown (void *eup
, int howto
)
606 /* Do device reset */
607 eni_pci_reset ( eup
);