1/*	$NetBSD: if_le_pci.c,v 1.50 2010/11/13 13:52:06 uebayasi 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.50 2010/11/13 13:52:06 uebayasi 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
238	sc->sc_dev = self;
239
240	switch (PCI_PRODUCT(pa->pa_id)) {
241	case PCI_PRODUCT_AMD_PCNET_PCI:
242		model = "PCnet-PCI Ethernet";
243		lesc->sc_rap = PCNET_PCI_RAP;
244		lesc->sc_rdp = PCNET_PCI_RDP;
245		break;
246
247	default:
248		model = "unknown model!";
249	}
250
251	aprint_normal(": %s\n", model);
252
253	if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0,
254	    &iot, &ioh, NULL, NULL)) {
255		aprint_error_dev(self, "can't map I/O space\n");
256		return;
257	}
258
259	/*
260	 * Extract the physical MAC address from the ROM.
261	 */
262	for (i = 0; i < sizeof(sc->sc_enaddr); i++)
263		sc->sc_enaddr[i] = bus_space_read_1(iot, ioh, i);
264
265	lesc->sc_iot = iot;
266	lesc->sc_ioh = ioh;
267	lesc->sc_dmat = dmat;
268
269	/*
270	 * Allocate a DMA area for the card.
271	 */
272	if (bus_dmamem_alloc(dmat, LE_PCI_MEMSIZE, PAGE_SIZE, 0, &seg, 1,
273	    &rseg, BUS_DMA_NOWAIT)) {
274		aprint_error_dev(self, "couldn't allocate memory for card\n");
275		return;
276	}
277	if (bus_dmamem_map(dmat, &seg, rseg, LE_PCI_MEMSIZE,
278	    (void **)&sc->sc_mem,
279	    BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
280		aprint_error_dev(self, "couldn't map memory for card\n");
281		return;
282	}
283
284	/*
285	 * Create and load the DMA map for the DMA area.
286	 */
287	if (bus_dmamap_create(dmat, LE_PCI_MEMSIZE, 1,
288	    LE_PCI_MEMSIZE, 0, BUS_DMA_NOWAIT, &lesc->sc_dmam)) {
289		aprint_error_dev(self, "couldn't create DMA map\n");
290		bus_dmamem_free(dmat, &seg, rseg);
291		return;
292	}
293	if (bus_dmamap_load(dmat, lesc->sc_dmam,
294	    sc->sc_mem, LE_PCI_MEMSIZE, NULL, BUS_DMA_NOWAIT)) {
295		aprint_error_dev(self, "coundn't load DMA map\n");
296		bus_dmamem_free(dmat, &seg, rseg);
297		return;
298	}
299
300	sc->sc_conf3 = 0;
301	sc->sc_addr = lesc->sc_dmam->dm_segs[0].ds_addr;
302	sc->sc_memsize = LE_PCI_MEMSIZE;
303
304	sc->sc_copytodesc = lance_copytobuf_contig;
305	sc->sc_copyfromdesc = lance_copyfrombuf_contig;
306	sc->sc_copytobuf = lance_copytobuf_contig;
307	sc->sc_copyfrombuf = lance_copyfrombuf_contig;
308	sc->sc_zerobuf = lance_zerobuf_contig;
309
310	sc->sc_rdcsr = le_pci_rdcsr;
311	sc->sc_wrcsr = le_pci_wrcsr;
312	sc->sc_hwinit = NULL;
313
314	sc->sc_supmedia = le_pci_supmedia;
315	sc->sc_nsupmedia = sizeof(le_pci_supmedia) / sizeof(int);
316	sc->sc_defaultmedia = le_pci_supmedia[0];
317	sc->sc_mediachange = le_pci_mediachange;
318	lesc->sc_currentmedia = le_pci_supmedia[0];
319
320	aprint_normal("%s", device_xname(self));
321	am79900_config(&lesc->sc_am79900);
322
323	/* Chip is stopped. Set "software style" to 32-bit. */
324	bus_space_write_2(iot, ioh, PCNET_PCI_RAP, 20);
325	bus_space_write_2(iot, ioh, PCNET_PCI_BDP, 2);
326
327	/* Enable the card. */
328	csr = pci_conf_read(pc, pa->pa_tag,
329	    PCI_COMMAND_STATUS_REG);
330	pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
331	    csr | PCI_COMMAND_MASTER_ENABLE);
332
333	/* Map and establish the interrupt. */
334	if (pci_intr_map(pa, &ih)) {
335		aprint_error_dev(self, "couldn't map interrupt\n");
336		return;
337	}
338	intrstr = pci_intr_string(pc, ih);
339	lesc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, am79900_intr, sc);
340	if (lesc->sc_ih == NULL) {
341		aprint_error_dev(self, "couldn't establish interrupt");
342		if (intrstr != NULL)
343			aprint_error(" at %s", intrstr);
344		aprint_error("\n");
345		return;
346	}
347	aprint_normal_dev(self, "interrupting at %s\n", intrstr);
348}
349