1 /* $NetBSD: if_en_pci.c,v 1.32 2009/05/12 08:23:00 cegger Exp $ */
5 * Copyright (c) 1996 Charles D. Cranor and Washington University.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Charles D. Cranor and
19 * Washington University.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 * i f _ e n _ p c i . c
39 * author: Chuck Cranor <chuck@ccrc.wustl.edu>
40 * started: spring, 1996.
42 * PCI glue for the eni155p card.
45 #include <sys/cdefs.h>
46 __KERNEL_RCSID(0, "$NetBSD: if_en_pci.c,v 1.32 2009/05/12 08:23:00 cegger Exp $");
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/device.h>
52 #include <sys/socket.h>
53 #include <sys/socketvar.h>
57 #include <dev/pci/pcivar.h>
58 #include <dev/pci/pcireg.h>
59 #include <dev/pci/pcidevs.h>
61 #include <dev/ic/midwayreg.h>
62 #include <dev/ic/midwayvar.h>
70 /* bus independent stuff */
71 struct en_softc esc
; /* includes "device" structure */
74 void *sc_ih
; /* interrupt handle */
75 pci_chipset_tag_t en_pc
; /* for PCI calls */
80 * local defines (PCI specific stuff)
83 #if !defined(MIDWAY_ENIONLY)
84 static void eni_get_macaddr(struct en_pci_softc
*, struct pci_attach_args
*);
86 #if !defined(MIDWAY_ADPONLY)
87 static void adp_get_macaddr(struct en_pci_softc
*, struct pci_attach_args
*);
91 * address of config base memory address register in PCI config space
92 * (this is card specific)
98 * tonga (pci bridge). ENI cards only!
101 #define EN_TONGA 0x60 /* PCI config addr of tonga reg */
103 #define TONGA_SWAP_DMA 0x80 /* endian swap control */
104 #define TONGA_SWAP_BYTE 0x40
105 #define TONGA_SWAP_WORD 0x20
108 * adaptec pci bridge. ADP cards only!
111 #define ADP_PCIREG 0x050040 /* PCI control register */
113 #define ADP_PCIREG_RESET 0x1 /* reset card */
114 #define ADP_PCIREG_IENABLE 0x2 /* interrupt enable */
115 #define ADP_PCIREG_SWAP_WORD 0x4 /* swap byte on slave access */
116 #define ADP_PCIREG_SWAP_DMA 0x8 /* swap bytes on DMA */
122 static int en_pci_match(device_t
, cfdata_t
, void *);
123 static void en_pci_attach(device_t
, device_t
, void *);
126 * PCI autoconfig attachments
129 CFATTACH_DECL(en_pci
, sizeof(struct en_pci_softc
),
130 en_pci_match
, en_pci_attach
, NULL
, NULL
);
132 #if !defined(MIDWAY_ENIONLY)
134 static void adp_busreset(void *);
137 * bus specific reset function [ADP only!]
140 static void adp_busreset(void *v
)
142 struct en_softc
*sc
= (struct en_softc
*) v
;
145 bus_space_write_4(sc
->en_memt
, sc
->en_base
, ADP_PCIREG
, ADP_PCIREG_RESET
);
146 DELAY(1000); /* let it reset */
147 dummy
= bus_space_read_4(sc
->en_memt
, sc
->en_base
, ADP_PCIREG
);
148 bus_space_write_4(sc
->en_memt
, sc
->en_base
, ADP_PCIREG
,
149 (ADP_PCIREG_SWAP_WORD
|ADP_PCIREG_SWAP_DMA
|ADP_PCIREG_IENABLE
));
150 dummy
= bus_space_read_4(sc
->en_memt
, sc
->en_base
, ADP_PCIREG
);
151 if ((dummy
& (ADP_PCIREG_SWAP_WORD
|ADP_PCIREG_SWAP_DMA
)) !=
152 (ADP_PCIREG_SWAP_WORD
|ADP_PCIREG_SWAP_DMA
))
153 printf("adp_busreset: Adaptec ATM did NOT reset!\n");
158 /***********************************************************************/
165 en_pci_match(device_t parent
, cfdata_t match
, void *aux
)
167 struct pci_attach_args
*pa
= (struct pci_attach_args
*) aux
;
169 #if !defined(MIDWAY_ADPONLY)
170 if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_EFFICIENTNETS
&&
171 (PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_EFFICIENTNETS_ENI155PF
||
172 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_EFFICIENTNETS_ENI155PA
))
176 #if !defined(MIDWAY_ENIONLY)
177 if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_ADP
&&
178 (PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_ADP_AIC5900
||
179 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_ADP_AIC5905
))
188 en_pci_attach(device_t parent
, device_t self
, void *aux
)
190 struct en_pci_softc
*scp
= device_private(self
);
191 struct en_softc
*sc
= &scp
->esc
;
192 struct pci_attach_args
*pa
= aux
;
193 pci_intr_handle_t ih
;
197 aprint_naive(": ATM controller\n");
200 sc
->is_adaptec
= (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_ADP
) ? 1 : 0;
201 scp
->en_pc
= pa
->pa_pc
;
204 * make sure bus mastering is enabled
206 pci_conf_write(pa
->pa_pc
, pa
->pa_tag
, PCI_COMMAND_STATUS_REG
,
207 pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, PCI_COMMAND_STATUS_REG
) |
208 PCI_COMMAND_MASTER_ENABLE
);
214 if (pci_intr_map(pa
, &ih
)) {
215 aprint_error_dev(&sc
->sc_dev
, "couldn't map interrupt\n");
218 intrstr
= pci_intr_string(scp
->en_pc
, ih
);
219 scp
->sc_ih
= pci_intr_establish(scp
->en_pc
, ih
, IPL_NET
, en_intr
, sc
);
220 if (scp
->sc_ih
== NULL
) {
221 aprint_error_dev(&sc
->sc_dev
, "couldn't establish interrupt\n");
223 aprint_error(" at %s", intrstr
);
227 aprint_normal_dev(&sc
->sc_dev
, "interrupting at %s\n", intrstr
);
228 sc
->ipl
= 1; /* XXX */
234 retval
= pci_mapreg_map(pa
, PCI_CBMA
,
235 PCI_MAPREG_TYPE_MEM
| PCI_MAPREG_MEM_TYPE_32BIT
, 0,
236 &sc
->en_memt
, &sc
->en_base
, NULL
, &sc
->en_obmemsz
);
238 aprint_error_dev(&sc
->sc_dev
, "couldn't map memory\n");
246 #if !defined(MIDWAY_ENIONLY)
247 if (sc
->is_adaptec
) {
248 adp_get_macaddr(scp
, pa
);
249 sc
->en_busreset
= adp_busreset
;
254 #if !defined(MIDWAY_ADPONLY)
255 if (!sc
->is_adaptec
) {
256 eni_get_macaddr(scp
, pa
);
257 sc
->en_busreset
= NULL
;
258 pci_conf_write(scp
->en_pc
, pa
->pa_tag
, EN_TONGA
,
259 (TONGA_SWAP_DMA
|TONGA_SWAP_WORD
));
264 * done PCI specific stuff
277 struct en_pci_softc
*psc
= (struct en_pci_softc
*)sc
;
284 #if !defined(MIDWAY_ENIONLY)
286 #if defined(__FreeBSD__)
287 #define bus_space_read_1(t, h, o) \
288 ((void)t, (*(volatile u_int8_t *)((h) + (o))))
292 adp_get_macaddr(struct en_pci_softc
*scp
, struct pci_attach_args
*pa
)
294 struct en_softc
* sc
= (struct en_softc
*)scp
;
297 for (lcv
= 0; lcv
< sizeof(sc
->macaddr
); lcv
++)
298 sc
->macaddr
[lcv
] = bus_space_read_1(sc
->en_memt
, sc
->en_base
,
299 MID_ADPMACOFF
+ lcv
);
302 #endif /* MIDWAY_ENIONLY */
304 #if !defined(MIDWAY_ADPONLY)
307 * Read station (MAC) address from serial EEPROM.
308 * derived from linux drivers/atm/eni.c by Werner Almesberger, EPFL LRC.
310 #define EN_PROM_MAGIC 0x0c
311 #define EN_PROM_DATA 0x02
312 #define EN_PROM_CLK 0x01
316 eni_get_macaddr(struct en_pci_softc
*scp
, struct pci_attach_args
*pa
)
318 struct en_softc
*sc
= (struct en_softc
*)scp
;
319 pci_chipset_tag_t id
= scp
->en_pc
;
320 pcitag_t tag
= pa
->pa_tag
;
322 u_int32_t data
, t_data
;
325 t_data
= pci_conf_read(id
, tag
, EN_TONGA
) & 0xffffff00;
327 data
= EN_PROM_MAGIC
| EN_PROM_DATA
| EN_PROM_CLK
;
328 pci_conf_write(id
, tag
, EN_TONGA
, data
);
330 for (i
= 0; i
< sizeof(sc
->macaddr
); i
++){
331 /* start operation */
332 data
|= EN_PROM_DATA
;
333 pci_conf_write(id
, tag
, EN_TONGA
, data
);
334 data
|= EN_PROM_CLK
;
335 pci_conf_write(id
, tag
, EN_TONGA
, data
);
336 data
&= ~EN_PROM_DATA
;
337 pci_conf_write(id
, tag
, EN_TONGA
, data
);
338 data
&= ~EN_PROM_CLK
;
339 pci_conf_write(id
, tag
, EN_TONGA
, data
);
340 /* send address with serial line */
341 address
= ((i
+ EN_ESI
) << 1) + 1;
342 for ( j
= 7 ; j
>= 0 ; j
--){
343 data
= (address
>> j
) & 1 ? data
| EN_PROM_DATA
:
344 data
& ~EN_PROM_DATA
;
345 pci_conf_write(id
, tag
, EN_TONGA
, data
);
346 data
|= EN_PROM_CLK
;
347 pci_conf_write(id
, tag
, EN_TONGA
, data
);
348 data
&= ~EN_PROM_CLK
;
349 pci_conf_write(id
, tag
, EN_TONGA
, data
);
352 data
|= EN_PROM_DATA
;
353 pci_conf_write(id
, tag
, EN_TONGA
, data
);
354 data
|= EN_PROM_CLK
;
355 pci_conf_write(id
, tag
, EN_TONGA
, data
);
356 data
= pci_conf_read(id
, tag
, EN_TONGA
);
357 data
&= ~EN_PROM_CLK
;
358 pci_conf_write(id
, tag
, EN_TONGA
, data
);
359 data
|= EN_PROM_DATA
;
360 pci_conf_write(id
, tag
, EN_TONGA
, data
);
364 for ( j
= 7 ; j
>= 0 ; j
--){
366 data
|= EN_PROM_DATA
;
367 pci_conf_write(id
, tag
, EN_TONGA
, data
);
368 data
|= EN_PROM_CLK
;
369 pci_conf_write(id
, tag
, EN_TONGA
, data
);
370 data
= pci_conf_read(id
, tag
, EN_TONGA
);
371 if(data
& EN_PROM_DATA
) tmp
|= 1;
372 data
&= ~EN_PROM_CLK
;
373 pci_conf_write(id
, tag
, EN_TONGA
, data
);
374 data
|= EN_PROM_DATA
;
375 pci_conf_write(id
, tag
, EN_TONGA
, data
);
378 data
|= EN_PROM_DATA
;
379 pci_conf_write(id
, tag
, EN_TONGA
, data
);
380 data
|= EN_PROM_CLK
;
381 pci_conf_write(id
, tag
, EN_TONGA
, data
);
382 data
= pci_conf_read(id
, tag
, EN_TONGA
);
383 data
&= ~EN_PROM_CLK
;
384 pci_conf_write(id
, tag
, EN_TONGA
, data
);
385 data
|= EN_PROM_DATA
;
386 pci_conf_write(id
, tag
, EN_TONGA
, data
);
388 sc
->macaddr
[i
] = tmp
;
391 data
&= ~EN_PROM_DATA
;
392 pci_conf_write(id
, tag
, EN_TONGA
, data
);
394 pci_conf_write(id
, tag
, EN_TONGA
, data
);
395 data
|= EN_PROM_DATA
;
396 pci_conf_write(id
, tag
, EN_TONGA
, data
);
397 pci_conf_write(id
, tag
, EN_TONGA
, t_data
);
400 #endif /* !MIDWAY_ADPONLY */