1/* $NetBSD: if_le_pci.c,v 1.52 2014/03/29 19:28:24 christos Exp $ */
2
3/*-
4 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
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.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
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.
19 *
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.
31 */
32
33/*-
34 * Copyright (c) 1992, 1993
35 * The Regents of the University of California. All rights reserved.
36 *
37 * This code is derived from software contributed to Berkeley by
38 * Ralph Campbell and Rick Macklem.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
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.
51 *
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
62 * SUCH DAMAGE.
63 *
64 * @(#)if_le.c 8.2 (Berkeley) 11/16/93
65 */
66
67#include <sys/cdefs.h>
68__KERNEL_RCSID(0, "$NetBSD: if_le_pci.c,v 1.52 2014/03/29 19:28:24 christos Exp $");
69
70#include <sys/param.h>
71#include <sys/systm.h>
72#include <sys/mbuf.h>
73#include <sys/syslog.h>
74#include <sys/socket.h>
75#include <sys/device.h>
76
77#include <net/if.h>
78#include <net/if_ether.h>
79#include <net/if_media.h>
80
81#include <sys/cpu.h>
82#include <sys/bus.h>
83#include <sys/intr.h>
84
85#include <dev/pci/pcireg.h>
86#include <dev/pci/pcivar.h>
87#include <dev/pci/pcidevs.h>
88
89#include <dev/ic/lancereg.h>
90#include <dev/ic/lancevar.h>
91#include <dev/ic/am79900reg.h>
92#include <dev/ic/am79900var.h>
93
94#include <dev/pci/if_levar.h>
95
96static int le_pci_match(device_t, cfdata_t, void *);
97static void le_pci_attach(device_t, device_t, void *);
98static int le_pci_mediachange(struct lance_softc *);
99
100CFATTACH_DECL_NEW(le_pci, sizeof(struct le_softc),
101 le_pci_match, le_pci_attach, NULL, NULL);
102
103/*
104 * PCI constants.
105 * XXX These should be in a common file!
106 */
107#define PCI_CBIO PCI_BAR(0) /* Configuration Base IO Address */
108
109#define LE_PCI_MEMSIZE 16384
110
111static int le_pci_supmedia[] = {
112 IFM_ETHER|IFM_AUTO,
113 IFM_ETHER|IFM_AUTO|IFM_FDX,
114 IFM_ETHER|IFM_10_T,
115 IFM_ETHER|IFM_10_T|IFM_FDX,
116 IFM_ETHER|IFM_10_5,
117 IFM_ETHER|IFM_10_5|IFM_FDX,
118};
119
120static void
121le_pci_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val)
122{
123 struct le_softc *lesc = (struct le_softc *)sc;
124 bus_space_tag_t iot = lesc->sc_iot;
125 bus_space_handle_t ioh = lesc->sc_ioh;
126
127 bus_space_write_2(iot, ioh, lesc->sc_rap, port);
128 bus_space_write_2(iot, ioh, lesc->sc_rdp, val);
129}
130
131static uint16_t
132le_pci_rdcsr(struct lance_softc *sc, uint16_t port)
133{
134 struct le_softc *lesc = (struct le_softc *)sc;
135 bus_space_tag_t iot = lesc->sc_iot;
136 bus_space_handle_t ioh = lesc->sc_ioh;
137 uint16_t val;
138
139 bus_space_write_2(iot, ioh, lesc->sc_rap, port);
140 val = bus_space_read_2(iot, ioh, lesc->sc_rdp);
141 return (val);
142}
143
144static int
145le_pci_mediachange(struct lance_softc *sc)
146{
147 struct le_softc *lesc = (struct le_softc *)sc;
148 bus_space_tag_t iot = lesc->sc_iot;
149 bus_space_handle_t ioh = lesc->sc_ioh;
150 int newmedia = sc->sc_media.ifm_media;
151 uint16_t reg;
152
153 if (IFM_SUBTYPE(newmedia) !=
154 IFM_SUBTYPE(lesc->sc_currentmedia)) {
155 if (IFM_SUBTYPE(newmedia) == IFM_AUTO) {
156 /* switch to autoselect - BCR2 bit 1 */
157 bus_space_write_2(iot, ioh, PCNET_PCI_RAP, 2);
158 reg = bus_space_read_2(iot, ioh, PCNET_PCI_BDP);
159 reg |= 2;
160 bus_space_write_2(iot, ioh, PCNET_PCI_RAP, 2);
161 bus_space_write_2(iot, ioh, PCNET_PCI_BDP, reg);
162 } else {
163 /* force media type (in init block) */
164 lance_reset(sc);
165 if (IFM_SUBTYPE(newmedia) == IFM_10_T)
166 sc->sc_initmodemedia = 1; /* UTP */
167 else
168 sc->sc_initmodemedia = 0; /* AUI */
169 lance_init(&sc->sc_ethercom.ec_if);
170
171 if (IFM_SUBTYPE(lesc->sc_currentmedia) == IFM_AUTO) {
172 /* take away autoselect - BCR2 bit 1 */
173 bus_space_write_2(iot, ioh, PCNET_PCI_RAP, 2);
174 reg = bus_space_read_2(iot, ioh, PCNET_PCI_BDP);
175 reg &= ~2;
176 bus_space_write_2(iot, ioh, PCNET_PCI_RAP, 2);
177 bus_space_write_2(iot, ioh, PCNET_PCI_BDP, reg);
178 }
179 }
180
181 }
182
183 if ((IFM_OPTIONS(newmedia) ^ IFM_OPTIONS(lesc->sc_currentmedia))
184 & IFM_FDX) {
185 /* toggle full duplex - BCR9 */
186 bus_space_write_2(iot, ioh, PCNET_PCI_RAP, 9);
187 reg = bus_space_read_2(iot, ioh, PCNET_PCI_BDP);
188 if (IFM_OPTIONS(newmedia) & IFM_FDX) {
189 reg |= 1; /* FDEN */
190 /* allow FDX on AUI only if explicitly chosen,
191 not in autoselect mode */
192 if (IFM_SUBTYPE(newmedia) == IFM_10_5)
193 reg |= 2; /* AUIFD */
194 else
195 reg &= ~2;
196 } else
197 reg &= ~1;
198 bus_space_write_2(iot, ioh, PCNET_PCI_RAP, 9);
199 bus_space_write_2(iot, ioh, PCNET_PCI_BDP, reg);
200 }
201
202 lesc->sc_currentmedia = newmedia;
203 return (0);
204}
205
206static int
207le_pci_match(device_t parent, cfdata_t cf, void *aux)
208{
209 struct pci_attach_args *pa = aux;
210
211 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_AMD)
212 return (0);
213
214 switch (PCI_PRODUCT(pa->pa_id)) {
215 case PCI_PRODUCT_AMD_PCNET_PCI:
216 return (1);
217 }
218
219 return (0);
220}
221
222static void
223le_pci_attach(device_t parent, device_t self, void *aux)
224{
225 struct le_softc *lesc = device_private(self);
226 struct lance_softc *sc = &lesc->sc_am79900.lsc;
227 struct pci_attach_args *pa = aux;
228 pci_intr_handle_t ih;
229 bus_space_tag_t iot;
230 bus_space_handle_t ioh;
231 bus_dma_tag_t dmat = pa->pa_dmat;
232 bus_dma_segment_t seg;
233 pci_chipset_tag_t pc = pa->pa_pc;
234 pcireg_t csr;
235 int i, rseg;
236 const char *model, *intrstr;
237 char intrbuf[PCI_INTRSTR_LEN];
238
239 sc->sc_dev = self;
240
241 switch (PCI_PRODUCT(pa->pa_id)) {
242 case PCI_PRODUCT_AMD_PCNET_PCI:
243 model = "PCnet-PCI Ethernet";
244 lesc->sc_rap = PCNET_PCI_RAP;
245 lesc->sc_rdp = PCNET_PCI_RDP;
246 break;
247
248 default:
249 model = "unknown model!";
250 }
251
252 aprint_normal(": %s\n", model);
253
254 if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0,
255 &iot, &ioh, NULL, NULL)) {
256 aprint_error_dev(self, "can't map I/O space\n");
257 return;
258 }
259
260 /*
261 * Extract the physical MAC address from the ROM.
262 */
263 for (i = 0; i < sizeof(sc->sc_enaddr); i++)
264 sc->sc_enaddr[i] = bus_space_read_1(iot, ioh, i);
265
266 lesc->sc_iot = iot;
267 lesc->sc_ioh = ioh;
268 lesc->sc_dmat = dmat;
269
270 /*
271 * Allocate a DMA area for the card.
272 */
273 if (bus_dmamem_alloc(dmat, LE_PCI_MEMSIZE, PAGE_SIZE, 0, &seg, 1,
274 &rseg, BUS_DMA_NOWAIT)) {
275 aprint_error_dev(self, "couldn't allocate memory for card\n");
276 return;
277 }
278 if (bus_dmamem_map(dmat, &seg, rseg, LE_PCI_MEMSIZE,
279 (void **)&sc->sc_mem,
280 BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
281 aprint_error_dev(self, "couldn't map memory for card\n");
282 return;
283 }
284
285 /*
286 * Create and load the DMA map for the DMA area.
287 */
288 if (bus_dmamap_create(dmat, LE_PCI_MEMSIZE, 1,
289 LE_PCI_MEMSIZE, 0, BUS_DMA_NOWAIT, &lesc->sc_dmam)) {
290 aprint_error_dev(self, "couldn't create DMA map\n");
291 bus_dmamem_free(dmat, &seg, rseg);
292 return;
293 }
294 if (bus_dmamap_load(dmat, lesc->sc_dmam,
295 sc->sc_mem, LE_PCI_MEMSIZE, NULL, BUS_DMA_NOWAIT)) {
296 aprint_error_dev(self, "coundn't load DMA map\n");
297 bus_dmamem_free(dmat, &seg, rseg);
298 return;
299 }
300
301 sc->sc_conf3 = 0;
302 sc->sc_addr = lesc->sc_dmam->dm_segs[0].ds_addr;
303 sc->sc_memsize = LE_PCI_MEMSIZE;
304
305 sc->sc_copytodesc = lance_copytobuf_contig;
306 sc->sc_copyfromdesc = lance_copyfrombuf_contig;
307 sc->sc_copytobuf = lance_copytobuf_contig;
308 sc->sc_copyfrombuf = lance_copyfrombuf_contig;
309 sc->sc_zerobuf = lance_zerobuf_contig;
310
311 sc->sc_rdcsr = le_pci_rdcsr;
312 sc->sc_wrcsr = le_pci_wrcsr;
313 sc->sc_hwinit = NULL;
314
315 sc->sc_supmedia = le_pci_supmedia;
316 sc->sc_nsupmedia = sizeof(le_pci_supmedia) / sizeof(int);
317 sc->sc_defaultmedia = le_pci_supmedia[0];
318 sc->sc_mediachange = le_pci_mediachange;
319 lesc->sc_currentmedia = le_pci_supmedia[0];
320
321 aprint_normal("%s", device_xname(self));
322 am79900_config(&lesc->sc_am79900);
323
324 /* Chip is stopped. Set "software style" to 32-bit. */
325 bus_space_write_2(iot, ioh, PCNET_PCI_RAP, 20);
326 bus_space_write_2(iot, ioh, PCNET_PCI_BDP, 2);
327
328 /* Enable the card. */
329 csr = pci_conf_read(pc, pa->pa_tag,
330 PCI_COMMAND_STATUS_REG);
331 pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
332 csr | PCI_COMMAND_MASTER_ENABLE);
333
334 /* Map and establish the interrupt. */
335 if (pci_intr_map(pa, &ih)) {
336 aprint_error_dev(self, "couldn't map interrupt\n");
337 return;
338 }
339 intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf));
340 lesc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, am79900_intr, sc);
341 if (lesc->sc_ih == NULL) {
342 aprint_error_dev(self, "couldn't establish interrupt");
343 if (intrstr != NULL)
344 aprint_error(" at %s", intrstr);
345 aprint_error("\n");
346 return;
347 }
348 aprint_normal_dev(self, "interrupting at %s\n", intrstr);
349}
350