1 /* $NetBSD: if_le_pci.c,v 1.48 2008/04/04 12:25:07 tsutsui Exp $ */
4 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
9 * Simulation Facility, NASA Ames Research Center.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
34 * Copyright (c) 1992, 1993
35 * The Regents of the University of California. All rights reserved.
37 * This code is derived from software contributed to Berkeley by
38 * Ralph Campbell and Rick Macklem.
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 * 3. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * @(#)if_le.c 8.2 (Berkeley) 11/16/93
67 #include <sys/cdefs.h>
68 __KERNEL_RCSID(0, "$NetBSD: if_le_pci.c,v 1.48 2008/04/04 12:25:07 tsutsui Exp $");
70 #include <sys/param.h>
71 #include <sys/systm.h>
73 #include <sys/syslog.h>
74 #include <sys/socket.h>
75 #include <sys/device.h>
77 #include <uvm/uvm_extern.h>
80 #include <net/if_ether.h>
81 #include <net/if_media.h>
87 #include <dev/pci/pcireg.h>
88 #include <dev/pci/pcivar.h>
89 #include <dev/pci/pcidevs.h>
91 #include <dev/ic/lancereg.h>
92 #include <dev/ic/lancevar.h>
93 #include <dev/ic/am79900reg.h>
94 #include <dev/ic/am79900var.h>
96 #include <dev/pci/if_levar.h>
98 static int le_pci_match(device_t
, cfdata_t
, void *);
99 static void le_pci_attach(device_t
, device_t
, void *);
100 static int le_pci_mediachange(struct lance_softc
*);
102 CFATTACH_DECL_NEW(le_pci
, sizeof(struct le_softc
),
103 le_pci_match
, le_pci_attach
, NULL
, NULL
);
107 * XXX These should be in a common file!
109 #define PCI_CBIO 0x10 /* Configuration Base IO Address */
111 #define LE_PCI_MEMSIZE 16384
113 static int le_pci_supmedia
[] = {
115 IFM_ETHER
|IFM_AUTO
|IFM_FDX
,
117 IFM_ETHER
|IFM_10_T
|IFM_FDX
,
119 IFM_ETHER
|IFM_10_5
|IFM_FDX
,
123 le_pci_wrcsr(struct lance_softc
*sc
, uint16_t port
, uint16_t val
)
125 struct le_softc
*lesc
= (struct le_softc
*)sc
;
126 bus_space_tag_t iot
= lesc
->sc_iot
;
127 bus_space_handle_t ioh
= lesc
->sc_ioh
;
129 bus_space_write_2(iot
, ioh
, lesc
->sc_rap
, port
);
130 bus_space_write_2(iot
, ioh
, lesc
->sc_rdp
, val
);
134 le_pci_rdcsr(struct lance_softc
*sc
, uint16_t port
)
136 struct le_softc
*lesc
= (struct le_softc
*)sc
;
137 bus_space_tag_t iot
= lesc
->sc_iot
;
138 bus_space_handle_t ioh
= lesc
->sc_ioh
;
141 bus_space_write_2(iot
, ioh
, lesc
->sc_rap
, port
);
142 val
= bus_space_read_2(iot
, ioh
, lesc
->sc_rdp
);
147 le_pci_mediachange(struct lance_softc
*sc
)
149 struct le_softc
*lesc
= (struct le_softc
*)sc
;
150 bus_space_tag_t iot
= lesc
->sc_iot
;
151 bus_space_handle_t ioh
= lesc
->sc_ioh
;
152 int newmedia
= sc
->sc_media
.ifm_media
;
155 if (IFM_SUBTYPE(newmedia
) !=
156 IFM_SUBTYPE(lesc
->sc_currentmedia
)) {
157 if (IFM_SUBTYPE(newmedia
) == IFM_AUTO
) {
158 /* switch to autoselect - BCR2 bit 1 */
159 bus_space_write_2(iot
, ioh
, PCNET_PCI_RAP
, 2);
160 reg
= bus_space_read_2(iot
, ioh
, PCNET_PCI_BDP
);
162 bus_space_write_2(iot
, ioh
, PCNET_PCI_RAP
, 2);
163 bus_space_write_2(iot
, ioh
, PCNET_PCI_BDP
, reg
);
165 /* force media type (in init block) */
167 if (IFM_SUBTYPE(newmedia
) == IFM_10_T
)
168 sc
->sc_initmodemedia
= 1; /* UTP */
170 sc
->sc_initmodemedia
= 0; /* AUI */
171 lance_init(&sc
->sc_ethercom
.ec_if
);
173 if (IFM_SUBTYPE(lesc
->sc_currentmedia
) == IFM_AUTO
) {
174 /* take away autoselect - BCR2 bit 1 */
175 bus_space_write_2(iot
, ioh
, PCNET_PCI_RAP
, 2);
176 reg
= bus_space_read_2(iot
, ioh
, PCNET_PCI_BDP
);
178 bus_space_write_2(iot
, ioh
, PCNET_PCI_RAP
, 2);
179 bus_space_write_2(iot
, ioh
, PCNET_PCI_BDP
, reg
);
185 if ((IFM_OPTIONS(newmedia
) ^ IFM_OPTIONS(lesc
->sc_currentmedia
))
187 /* toggle full duplex - BCR9 */
188 bus_space_write_2(iot
, ioh
, PCNET_PCI_RAP
, 9);
189 reg
= bus_space_read_2(iot
, ioh
, PCNET_PCI_BDP
);
190 if (IFM_OPTIONS(newmedia
) & IFM_FDX
) {
192 /* allow FDX on AUI only if explicitly chosen,
193 not in autoselect mode */
194 if (IFM_SUBTYPE(newmedia
) == IFM_10_5
)
195 reg
|= 2; /* AUIFD */
200 bus_space_write_2(iot
, ioh
, PCNET_PCI_RAP
, 9);
201 bus_space_write_2(iot
, ioh
, PCNET_PCI_BDP
, reg
);
204 lesc
->sc_currentmedia
= newmedia
;
209 le_pci_match(device_t parent
, cfdata_t cf
, void *aux
)
211 struct pci_attach_args
*pa
= aux
;
213 if (PCI_VENDOR(pa
->pa_id
) != PCI_VENDOR_AMD
)
216 switch (PCI_PRODUCT(pa
->pa_id
)) {
217 case PCI_PRODUCT_AMD_PCNET_PCI
:
225 le_pci_attach(device_t parent
, device_t self
, void *aux
)
227 struct le_softc
*lesc
= device_private(self
);
228 struct lance_softc
*sc
= &lesc
->sc_am79900
.lsc
;
229 struct pci_attach_args
*pa
= aux
;
230 pci_intr_handle_t ih
;
232 bus_space_handle_t ioh
;
233 bus_dma_tag_t dmat
= pa
->pa_dmat
;
234 bus_dma_segment_t seg
;
235 pci_chipset_tag_t pc
= pa
->pa_pc
;
238 const char *model
, *intrstr
;
242 switch (PCI_PRODUCT(pa
->pa_id
)) {
243 case PCI_PRODUCT_AMD_PCNET_PCI
:
244 model
= "PCnet-PCI Ethernet";
245 lesc
->sc_rap
= PCNET_PCI_RAP
;
246 lesc
->sc_rdp
= PCNET_PCI_RDP
;
250 model
= "unknown model!";
253 aprint_normal(": %s\n", model
);
255 if (pci_mapreg_map(pa
, PCI_CBIO
, PCI_MAPREG_TYPE_IO
, 0,
256 &iot
, &ioh
, NULL
, NULL
)) {
257 aprint_error_dev(self
, "can't map I/O space\n");
262 * Extract the physical MAC address from the ROM.
264 for (i
= 0; i
< sizeof(sc
->sc_enaddr
); i
++)
265 sc
->sc_enaddr
[i
] = bus_space_read_1(iot
, ioh
, i
);
269 lesc
->sc_dmat
= dmat
;
272 * Allocate a DMA area for the card.
274 if (bus_dmamem_alloc(dmat
, LE_PCI_MEMSIZE
, PAGE_SIZE
, 0, &seg
, 1,
275 &rseg
, BUS_DMA_NOWAIT
)) {
276 aprint_error_dev(self
, "couldn't allocate memory for card\n");
279 if (bus_dmamem_map(dmat
, &seg
, rseg
, LE_PCI_MEMSIZE
,
280 (void **)&sc
->sc_mem
,
281 BUS_DMA_NOWAIT
|BUS_DMA_COHERENT
)) {
282 aprint_error_dev(self
, "couldn't map memory for card\n");
287 * Create and load the DMA map for the DMA area.
289 if (bus_dmamap_create(dmat
, LE_PCI_MEMSIZE
, 1,
290 LE_PCI_MEMSIZE
, 0, BUS_DMA_NOWAIT
, &lesc
->sc_dmam
)) {
291 aprint_error_dev(self
, "couldn't create DMA map\n");
292 bus_dmamem_free(dmat
, &seg
, rseg
);
295 if (bus_dmamap_load(dmat
, lesc
->sc_dmam
,
296 sc
->sc_mem
, LE_PCI_MEMSIZE
, NULL
, BUS_DMA_NOWAIT
)) {
297 aprint_error_dev(self
, "coundn't load DMA map\n");
298 bus_dmamem_free(dmat
, &seg
, rseg
);
303 sc
->sc_addr
= lesc
->sc_dmam
->dm_segs
[0].ds_addr
;
304 sc
->sc_memsize
= LE_PCI_MEMSIZE
;
306 sc
->sc_copytodesc
= lance_copytobuf_contig
;
307 sc
->sc_copyfromdesc
= lance_copyfrombuf_contig
;
308 sc
->sc_copytobuf
= lance_copytobuf_contig
;
309 sc
->sc_copyfrombuf
= lance_copyfrombuf_contig
;
310 sc
->sc_zerobuf
= lance_zerobuf_contig
;
312 sc
->sc_rdcsr
= le_pci_rdcsr
;
313 sc
->sc_wrcsr
= le_pci_wrcsr
;
314 sc
->sc_hwinit
= NULL
;
316 sc
->sc_supmedia
= le_pci_supmedia
;
317 sc
->sc_nsupmedia
= sizeof(le_pci_supmedia
) / sizeof(int);
318 sc
->sc_defaultmedia
= le_pci_supmedia
[0];
319 sc
->sc_mediachange
= le_pci_mediachange
;
320 lesc
->sc_currentmedia
= le_pci_supmedia
[0];
322 aprint_normal("%s", device_xname(self
));
323 am79900_config(&lesc
->sc_am79900
);
325 /* Chip is stopped. Set "software style" to 32-bit. */
326 bus_space_write_2(iot
, ioh
, PCNET_PCI_RAP
, 20);
327 bus_space_write_2(iot
, ioh
, PCNET_PCI_BDP
, 2);
329 /* Enable the card. */
330 csr
= pci_conf_read(pc
, pa
->pa_tag
,
331 PCI_COMMAND_STATUS_REG
);
332 pci_conf_write(pc
, pa
->pa_tag
, PCI_COMMAND_STATUS_REG
,
333 csr
| PCI_COMMAND_MASTER_ENABLE
);
335 /* Map and establish the interrupt. */
336 if (pci_intr_map(pa
, &ih
)) {
337 aprint_error_dev(self
, "couldn't map interrupt\n");
340 intrstr
= pci_intr_string(pc
, ih
);
341 lesc
->sc_ih
= pci_intr_establish(pc
, ih
, IPL_NET
, am79900_intr
, sc
);
342 if (lesc
->sc_ih
== NULL
) {
343 aprint_error_dev(self
, "couldn't establish interrupt");
345 aprint_error(" at %s", intrstr
);
349 aprint_normal_dev(self
, "interrupting at %s\n", intrstr
);