1 /* $NetBSD: if_le_pci.c,v 1.43 2005/12/11 12:22:49 christos Exp $ */
2
3 /*-
4 * SPDX-License-Identifier: BSD-2-Clause AND BSD-3-Clause
5 *
6 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
11 * Simulation Facility, NASA Ames Research Center.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 /*-
36 * Copyright (c) 1992, 1993
37 * The Regents of the University of California. All rights reserved.
38 *
39 * This code is derived from software contributed to Berkeley by
40 * Ralph Campbell and Rick Macklem.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
50 * 3. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * SUCH DAMAGE.
65 */
66
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/bus.h>
70 #include <sys/endian.h>
71 #include <sys/kernel.h>
72 #include <sys/lock.h>
73 #include <sys/module.h>
74 #include <sys/mutex.h>
75 #include <sys/resource.h>
76 #include <sys/rman.h>
77 #include <sys/socket.h>
78
79 #include <net/ethernet.h>
80 #include <net/if.h>
81 #include <net/if_media.h>
82
83 #include <machine/bus.h>
84 #include <machine/resource.h>
85
86 #include <dev/pci/pcireg.h>
87 #include <dev/pci/pcivar.h>
88
89 #include <dev/le/lancereg.h>
90 #include <dev/le/lancevar.h>
91 #include <dev/le/am79900var.h>
92
93 #define AMD_VENDOR 0x1022
94 #define AMD_PCNET_PCI 0x2000
95 #define AMD_PCNET_HOME 0x2001
96 #define PCNET_MEMSIZE (32*1024)
97 #define PCNET_PCI_RDP 0x10
98 #define PCNET_PCI_RAP 0x12
99 #define PCNET_PCI_BDP 0x16
100
101 struct le_pci_softc {
102 struct am79900_softc sc_am79900; /* glue to MI code */
103
104 struct resource *sc_rres;
105
106 struct resource *sc_ires;
107 void *sc_ih;
108
109 bus_dma_tag_t sc_pdmat;
110 bus_dma_tag_t sc_dmat;
111 bus_dmamap_t sc_dmam;
112 };
113
114 static device_probe_t le_pci_probe;
115 static device_attach_t le_pci_attach;
116 static device_detach_t le_pci_detach;
117 static device_resume_t le_pci_resume;
118 static device_suspend_t le_pci_suspend;
119
120 static device_method_t le_pci_methods[] = {
121 /* Device interface */
122 DEVMETHOD(device_probe, le_pci_probe),
123 DEVMETHOD(device_attach, le_pci_attach),
124 DEVMETHOD(device_detach, le_pci_detach),
125 /* We can just use the suspend method here. */
126 DEVMETHOD(device_shutdown, le_pci_suspend),
127 DEVMETHOD(device_suspend, le_pci_suspend),
128 DEVMETHOD(device_resume, le_pci_resume),
129
130 { 0, 0 }
131 };
132
133 DEFINE_CLASS_0(le, le_pci_driver, le_pci_methods, sizeof(struct le_pci_softc));
134 DRIVER_MODULE(le, pci, le_pci_driver, 0, 0);
135 MODULE_DEPEND(le, ether, 1, 1, 1);
136
137 static const int le_home_supmedia[] = {
138 IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0, 0)
139 };
140
141 static const int le_pci_supmedia[] = {
142 IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0),
143 IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, IFM_FDX, 0),
144 IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, 0),
145 IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, 0),
146 IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, 0),
147 IFM_MAKEWORD(IFM_ETHER, IFM_10_5, IFM_FDX, 0)
148 };
149
150 static void le_pci_wrbcr(struct lance_softc *, uint16_t, uint16_t);
151 static uint16_t le_pci_rdbcr(struct lance_softc *, uint16_t);
152 static void le_pci_wrcsr(struct lance_softc *, uint16_t, uint16_t);
153 static uint16_t le_pci_rdcsr(struct lance_softc *, uint16_t);
154 static int le_pci_mediachange(struct lance_softc *);
155 static void le_pci_hwreset(struct lance_softc *);
156 static bus_dmamap_callback_t le_pci_dma_callback;
157
158 static void
le_pci_wrbcr(struct lance_softc * sc,uint16_t port,uint16_t val)159 le_pci_wrbcr(struct lance_softc *sc, uint16_t port, uint16_t val)
160 {
161 struct le_pci_softc *lesc = (struct le_pci_softc *)sc;
162
163 bus_write_2(lesc->sc_rres, PCNET_PCI_RAP, port);
164 bus_barrier(lesc->sc_rres, PCNET_PCI_RAP, 2, BUS_SPACE_BARRIER_WRITE);
165 bus_write_2(lesc->sc_rres, PCNET_PCI_BDP, val);
166 }
167
168 static uint16_t
le_pci_rdbcr(struct lance_softc * sc,uint16_t port)169 le_pci_rdbcr(struct lance_softc *sc, uint16_t port)
170 {
171 struct le_pci_softc *lesc = (struct le_pci_softc *)sc;
172
173 bus_write_2(lesc->sc_rres, PCNET_PCI_RAP, port);
174 bus_barrier(lesc->sc_rres, PCNET_PCI_RAP, 2, BUS_SPACE_BARRIER_WRITE);
175 return (bus_read_2(lesc->sc_rres, PCNET_PCI_BDP));
176 }
177
178 static void
le_pci_wrcsr(struct lance_softc * sc,uint16_t port,uint16_t val)179 le_pci_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val)
180 {
181 struct le_pci_softc *lesc = (struct le_pci_softc *)sc;
182
183 bus_write_2(lesc->sc_rres, PCNET_PCI_RAP, port);
184 bus_barrier(lesc->sc_rres, PCNET_PCI_RAP, 2, BUS_SPACE_BARRIER_WRITE);
185 bus_write_2(lesc->sc_rres, PCNET_PCI_RDP, val);
186 }
187
188 static uint16_t
le_pci_rdcsr(struct lance_softc * sc,uint16_t port)189 le_pci_rdcsr(struct lance_softc *sc, uint16_t port)
190 {
191 struct le_pci_softc *lesc = (struct le_pci_softc *)sc;
192
193 bus_write_2(lesc->sc_rres, PCNET_PCI_RAP, port);
194 bus_barrier(lesc->sc_rres, PCNET_PCI_RAP, 2, BUS_SPACE_BARRIER_WRITE);
195 return (bus_read_2(lesc->sc_rres, PCNET_PCI_RDP));
196 }
197
198 static int
le_pci_mediachange(struct lance_softc * sc)199 le_pci_mediachange(struct lance_softc *sc)
200 {
201 struct ifmedia *ifm = &sc->sc_media;
202 uint16_t reg;
203
204 if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
205 return (EINVAL);
206
207 if (IFM_SUBTYPE(ifm->ifm_media) == IFM_HPNA_1)
208 le_pci_wrbcr(sc, LE_BCR49,
209 (le_pci_rdbcr(sc, LE_BCR49) & ~LE_B49_PHYSEL) | 0x1);
210 else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO)
211 le_pci_wrbcr(sc, LE_BCR2,
212 le_pci_rdbcr(sc, LE_BCR2) | LE_B2_ASEL);
213 else {
214 le_pci_wrbcr(sc, LE_BCR2,
215 le_pci_rdbcr(sc, LE_BCR2) & ~LE_B2_ASEL);
216
217 reg = le_pci_rdcsr(sc, LE_CSR15);
218 reg &= ~LE_C15_PORTSEL(LE_PORTSEL_MASK);
219 if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10_T)
220 reg |= LE_C15_PORTSEL(LE_PORTSEL_10T);
221 else
222 reg |= LE_C15_PORTSEL(LE_PORTSEL_AUI);
223 le_pci_wrcsr(sc, LE_CSR15, reg);
224 }
225
226 reg = le_pci_rdbcr(sc, LE_BCR9);
227 if (IFM_OPTIONS(ifm->ifm_media) & IFM_FDX) {
228 reg |= LE_B9_FDEN;
229 /*
230 * Allow FDX on AUI only if explicitly chosen,
231 * not in autoselect mode.
232 */
233 if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10_5)
234 reg |= LE_B9_AUIFD;
235 else
236 reg &= ~LE_B9_AUIFD;
237 } else
238 reg &= ~LE_B9_FDEN;
239 le_pci_wrbcr(sc, LE_BCR9, reg);
240
241 return (0);
242 }
243
244 static void
le_pci_hwreset(struct lance_softc * sc)245 le_pci_hwreset(struct lance_softc *sc)
246 {
247
248 /*
249 * Chip is stopped. Set software style to PCnet-PCI (32-bit).
250 * Actually, am79900.c implements ILACC support (hence its
251 * name) but unfortunately VMware does not. As far as this
252 * driver is concerned that should not make a difference
253 * though, as the settings used have the same meaning for
254 * both, ILACC and PCnet-PCI (note that there would be a
255 * difference for the ADD_FCS/NO_FCS bit if used).
256 */
257 le_pci_wrbcr(sc, LE_BCR20, LE_B20_SSTYLE_PCNETPCI2);
258 }
259
260 static void
le_pci_dma_callback(void * xsc,bus_dma_segment_t * segs,int nsegs,int error)261 le_pci_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
262 {
263 struct lance_softc *sc = (struct lance_softc *)xsc;
264
265 if (error != 0)
266 return;
267 KASSERT(nsegs == 1, ("%s: bad DMA segment count", __func__));
268 sc->sc_addr = segs[0].ds_addr;
269 }
270
271 static int
le_pci_probe(device_t dev)272 le_pci_probe(device_t dev)
273 {
274
275 if (pci_get_vendor(dev) != AMD_VENDOR)
276 return (ENXIO);
277
278 switch (pci_get_device(dev)) {
279 case AMD_PCNET_PCI:
280 device_set_desc(dev, "AMD PCnet-PCI");
281 /* Let pcn(4) win. */
282 return (BUS_PROBE_LOW_PRIORITY);
283 case AMD_PCNET_HOME:
284 device_set_desc(dev, "AMD PCnet-Home");
285 /* Let pcn(4) win. */
286 return (BUS_PROBE_LOW_PRIORITY);
287 default:
288 return (ENXIO);
289 }
290 }
291
292 static int
le_pci_attach(device_t dev)293 le_pci_attach(device_t dev)
294 {
295 struct le_pci_softc *lesc;
296 struct lance_softc *sc;
297 int error, i;
298
299 lesc = device_get_softc(dev);
300 sc = &lesc->sc_am79900.lsc;
301
302 LE_LOCK_INIT(sc, device_get_nameunit(dev));
303
304 pci_enable_busmaster(dev);
305
306 i = PCIR_BAR(0);
307 lesc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
308 &i, RF_ACTIVE);
309 if (lesc->sc_rres == NULL) {
310 device_printf(dev, "cannot allocate registers\n");
311 error = ENXIO;
312 goto fail_mtx;
313 }
314
315 i = 0;
316 if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
317 &i, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
318 device_printf(dev, "cannot allocate interrupt\n");
319 error = ENXIO;
320 goto fail_rres;
321 }
322
323 error = bus_dma_tag_create(
324 bus_get_dma_tag(dev), /* parent */
325 1, 0, /* alignment, boundary */
326 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
327 BUS_SPACE_MAXADDR, /* highaddr */
328 NULL, NULL, /* filter, filterarg */
329 BUS_SPACE_MAXSIZE_32BIT, /* maxsize */
330 0, /* nsegments */
331 BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
332 0, /* flags */
333 NULL, NULL, /* lockfunc, lockarg */
334 &lesc->sc_pdmat);
335 if (error != 0) {
336 device_printf(dev, "cannot allocate parent DMA tag\n");
337 goto fail_ires;
338 }
339
340 sc->sc_memsize = PCNET_MEMSIZE;
341 /*
342 * For Am79C970A, Am79C971 and Am79C978 the init block must be 2-byte
343 * aligned and the ring descriptors must be 16-byte aligned when using
344 * a 32-bit software style.
345 */
346 error = bus_dma_tag_create(
347 lesc->sc_pdmat, /* parent */
348 16, 0, /* alignment, boundary */
349 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
350 BUS_SPACE_MAXADDR, /* highaddr */
351 NULL, NULL, /* filter, filterarg */
352 sc->sc_memsize, /* maxsize */
353 1, /* nsegments */
354 sc->sc_memsize, /* maxsegsize */
355 0, /* flags */
356 NULL, NULL, /* lockfunc, lockarg */
357 &lesc->sc_dmat);
358 if (error != 0) {
359 device_printf(dev, "cannot allocate buffer DMA tag\n");
360 goto fail_pdtag;
361 }
362
363 error = bus_dmamem_alloc(lesc->sc_dmat, (void **)&sc->sc_mem,
364 BUS_DMA_WAITOK | BUS_DMA_COHERENT, &lesc->sc_dmam);
365 if (error != 0) {
366 device_printf(dev, "cannot allocate DMA buffer memory\n");
367 goto fail_dtag;
368 }
369
370 sc->sc_addr = 0;
371 error = bus_dmamap_load(lesc->sc_dmat, lesc->sc_dmam, sc->sc_mem,
372 sc->sc_memsize, le_pci_dma_callback, sc, 0);
373 if (error != 0 || sc->sc_addr == 0) {
374 device_printf(dev, "cannot load DMA buffer map\n");
375 goto fail_dmem;
376 }
377
378 sc->sc_flags = LE_BSWAP;
379 sc->sc_conf3 = 0;
380
381 sc->sc_mediastatus = NULL;
382 switch (pci_get_device(dev)) {
383 case AMD_PCNET_HOME:
384 sc->sc_mediachange = le_pci_mediachange;
385 sc->sc_supmedia = le_home_supmedia;
386 sc->sc_nsupmedia = sizeof(le_home_supmedia) / sizeof(int);
387 sc->sc_defaultmedia = le_home_supmedia[0];
388 break;
389 default:
390 sc->sc_mediachange = le_pci_mediachange;
391 sc->sc_supmedia = le_pci_supmedia;
392 sc->sc_nsupmedia = sizeof(le_pci_supmedia) / sizeof(int);
393 sc->sc_defaultmedia = le_pci_supmedia[0];
394 }
395
396 /*
397 * Extract the physical MAC address from the ROM.
398 */
399 bus_read_region_1(lesc->sc_rres, 0, sc->sc_enaddr,
400 sizeof(sc->sc_enaddr));
401
402 sc->sc_copytodesc = lance_copytobuf_contig;
403 sc->sc_copyfromdesc = lance_copyfrombuf_contig;
404 sc->sc_copytobuf = lance_copytobuf_contig;
405 sc->sc_copyfrombuf = lance_copyfrombuf_contig;
406 sc->sc_zerobuf = lance_zerobuf_contig;
407
408 sc->sc_rdcsr = le_pci_rdcsr;
409 sc->sc_wrcsr = le_pci_wrcsr;
410 sc->sc_hwreset = le_pci_hwreset;
411 sc->sc_hwinit = NULL;
412 sc->sc_hwintr = NULL;
413 sc->sc_nocarrier = NULL;
414
415 error = am79900_config(&lesc->sc_am79900, device_get_name(dev),
416 device_get_unit(dev));
417 if (error != 0) {
418 device_printf(dev, "cannot attach Am79900\n");
419 goto fail_dmap;
420 }
421
422 error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE,
423 NULL, am79900_intr, sc, &lesc->sc_ih);
424 if (error != 0) {
425 device_printf(dev, "cannot set up interrupt\n");
426 goto fail_am79900;
427 }
428
429 return (0);
430
431 fail_am79900:
432 am79900_detach(&lesc->sc_am79900);
433 fail_dmap:
434 bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
435 fail_dmem:
436 bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
437 fail_dtag:
438 bus_dma_tag_destroy(lesc->sc_dmat);
439 fail_pdtag:
440 bus_dma_tag_destroy(lesc->sc_pdmat);
441 fail_ires:
442 bus_release_resource(dev, SYS_RES_IRQ,
443 rman_get_rid(lesc->sc_ires), lesc->sc_ires);
444 fail_rres:
445 bus_release_resource(dev, SYS_RES_IOPORT,
446 rman_get_rid(lesc->sc_rres), lesc->sc_rres);
447 fail_mtx:
448 LE_LOCK_DESTROY(sc);
449 return (error);
450 }
451
452 static int
le_pci_detach(device_t dev)453 le_pci_detach(device_t dev)
454 {
455 struct le_pci_softc *lesc;
456 struct lance_softc *sc;
457
458 lesc = device_get_softc(dev);
459 sc = &lesc->sc_am79900.lsc;
460
461 bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih);
462 am79900_detach(&lesc->sc_am79900);
463 bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
464 bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
465 bus_dma_tag_destroy(lesc->sc_dmat);
466 bus_dma_tag_destroy(lesc->sc_pdmat);
467 bus_release_resource(dev, SYS_RES_IRQ,
468 rman_get_rid(lesc->sc_ires), lesc->sc_ires);
469 bus_release_resource(dev, SYS_RES_IOPORT,
470 rman_get_rid(lesc->sc_rres), lesc->sc_rres);
471 LE_LOCK_DESTROY(sc);
472
473 return (0);
474 }
475
476 static int
le_pci_suspend(device_t dev)477 le_pci_suspend(device_t dev)
478 {
479 struct le_pci_softc *lesc;
480
481 lesc = device_get_softc(dev);
482
483 lance_suspend(&lesc->sc_am79900.lsc);
484
485 return (0);
486 }
487
488 static int
le_pci_resume(device_t dev)489 le_pci_resume(device_t dev)
490 {
491 struct le_pci_softc *lesc;
492
493 lesc = device_get_softc(dev);
494
495 lance_resume(&lesc->sc_am79900.lsc);
496
497 return (0);
498 }
499