1/*	$NetBSD: if_epic_pci.c,v 1.39 2011/07/26 20:51:24 dyoung Exp $	*/
2
3/*-
4 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * 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 * PCI bus front-end for the Standard Microsystems Corp. 83C170
35 * Ethernet PCI Integrated Controller (EPIC/100) driver.
36 */
37
38#include <sys/cdefs.h>
39__KERNEL_RCSID(0, "$NetBSD: if_epic_pci.c,v 1.39 2011/07/26 20:51:24 dyoung Exp $");
40
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/mbuf.h>
44#include <sys/malloc.h>
45#include <sys/kernel.h>
46#include <sys/socket.h>
47#include <sys/ioctl.h>
48#include <sys/errno.h>
49#include <sys/device.h>
50
51#include <net/if.h>
52#include <net/if_dl.h>
53#include <net/if_media.h>
54#include <net/if_ether.h>
55
56#include <sys/bus.h>
57#include <sys/intr.h>
58
59#include <dev/mii/miivar.h>
60
61#include <dev/ic/smc83c170reg.h>
62#include <dev/ic/smc83c170var.h>
63
64#include <dev/pci/pcivar.h>
65#include <dev/pci/pcireg.h>
66#include <dev/pci/pcidevs.h>
67
68/*
69 * PCI configuration space registers used by the EPIC.
70 */
71#define EPIC_PCI_IOBA PCI_BAR(0)	/* i/o mapped base */
72#define EPIC_PCI_MMBA PCI_BAR(1)	/* memory mapped base */
73
74struct epic_pci_softc {
75	struct epic_softc sc_epic;	/* real EPIC softc */
76
77	/* PCI-specific goo. */
78	void	*sc_ih;			/* interrupt handle */
79};
80
81static int	epic_pci_match(device_t, cfdata_t, void *);
82static void	epic_pci_attach(device_t, device_t, void *);
83
84CFATTACH_DECL_NEW(epic_pci, sizeof(struct epic_pci_softc),
85    epic_pci_match, epic_pci_attach, NULL, NULL);
86
87static const struct epic_pci_product {
88	uint32_t	epp_prodid;	/* PCI product ID */
89	const char	*epp_name;	/* device name */
90} epic_pci_products[] = {
91	{ PCI_PRODUCT_SMC_83C170,	"SMC 83c170 Fast Ethernet" },
92	{ PCI_PRODUCT_SMC_83C175,	"SMC 83c175 Fast Ethernet" },
93	{ 0,				NULL },
94};
95
96static const struct epic_pci_product *
97epic_pci_lookup(const struct pci_attach_args *pa)
98{
99	const struct epic_pci_product *epp;
100
101	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_SMC)
102		return NULL;
103
104	for (epp = epic_pci_products; epp->epp_name != NULL; epp++)
105		if (PCI_PRODUCT(pa->pa_id) == epp->epp_prodid)
106			return epp;
107
108	return NULL;
109}
110
111static const struct epic_pci_subsys_info {
112	pcireg_t subsysid;
113	int flags;
114} epic_pci_subsys_info[] = {
115	{ PCI_ID_CODE(PCI_VENDOR_SMC, 0xa015), /* SMC9432BTX */
116	  EPIC_HAS_BNC },
117	{ PCI_ID_CODE(PCI_VENDOR_SMC, 0xa024), /* SMC9432BTX1 */
118	  EPIC_HAS_BNC },
119	{ PCI_ID_CODE(PCI_VENDOR_SMC, 0xa016), /* SMC9432FTX */
120	  EPIC_HAS_MII_FIBER | EPIC_DUPLEXLED_ON_694 },
121	{ 0xffffffff,
122	  0 }
123};
124
125static const struct epic_pci_subsys_info *
126epic_pci_subsys_lookup(const struct pci_attach_args *pa)
127{
128	pci_chipset_tag_t pc = pa->pa_pc;
129	pcireg_t reg;
130	const struct epic_pci_subsys_info *esp;
131
132	reg = pci_conf_read(pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
133
134	for (esp = epic_pci_subsys_info; esp->subsysid != 0xffffffff; esp++)
135		if (esp->subsysid == reg)
136			return esp;
137
138	return NULL;
139}
140
141static int
142epic_pci_match(device_t parent, cfdata_t cf, void *aux)
143{
144	struct pci_attach_args *pa = aux;
145
146	if (epic_pci_lookup(pa) != NULL)
147		return 1;
148
149	return 0;
150}
151
152static void
153epic_pci_attach(device_t parent, device_t self, void *aux)
154{
155	struct epic_pci_softc *psc = device_private(self);
156	struct epic_softc *sc = &psc->sc_epic;
157	struct pci_attach_args *pa = aux;
158	pci_chipset_tag_t pc = pa->pa_pc;
159	pci_intr_handle_t ih;
160	const char *intrstr = NULL;
161	const struct epic_pci_product *epp;
162	const struct epic_pci_subsys_info *esp;
163	bus_space_tag_t iot, memt;
164	bus_space_handle_t ioh, memh;
165	int ioh_valid, memh_valid;
166	int error;
167
168	sc->sc_dev = self;
169
170	epp = epic_pci_lookup(pa);
171	if (epp == NULL) {
172		aprint_normal("\n");
173		panic("%s: impossible", __func__);
174	}
175
176	pci_aprint_devinfo_fancy(pa, "Ethernet controller", epp->epp_name, 1);
177
178	/* power up chip */
179	if ((error = pci_activate(pa->pa_pc, pa->pa_tag, self,
180	    NULL)) && error != EOPNOTSUPP) {
181		aprint_error_dev(self, "cannot activate %d\n", error);
182		return;
183	}
184
185	/*
186	 * Map the device.
187	 */
188	ioh_valid = (pci_mapreg_map(pa, EPIC_PCI_IOBA,
189	    PCI_MAPREG_TYPE_IO, 0,
190	    &iot, &ioh, NULL, NULL) == 0);
191	memh_valid = (pci_mapreg_map(pa, EPIC_PCI_MMBA,
192	    PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0,
193	    &memt, &memh, NULL, NULL) == 0);
194
195	if (memh_valid) {
196		sc->sc_st = memt;
197		sc->sc_sh = memh;
198	} else if (ioh_valid) {
199		sc->sc_st = iot;
200		sc->sc_sh = ioh;
201	} else {
202		aprint_error_dev(self, "unable to map device registers\n");
203		return;
204	}
205
206	sc->sc_dmat = pa->pa_dmat;
207
208	/* Make sure bus mastering is enabled. */
209	pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
210	    pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) |
211	    PCI_COMMAND_MASTER_ENABLE);
212
213	/*
214	 * Map and establish our interrupt.
215	 */
216	if (pci_intr_map(pa, &ih)) {
217		aprint_error_dev(self, "unable to map interrupt\n");
218		return;
219	}
220	intrstr = pci_intr_string(pc, ih);
221	psc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, epic_intr, sc);
222	if (psc->sc_ih == NULL) {
223		aprint_error_dev(self, "unable to establish interrupt");
224		if (intrstr != NULL)
225			aprint_error(" at %s", intrstr);
226		aprint_error("\n");
227		return;
228	}
229	aprint_normal_dev(self, "interrupting at %s\n", intrstr);
230
231	esp = epic_pci_subsys_lookup(pa);
232	if (esp)
233		sc->sc_hwflags = esp->flags;
234
235	/*
236	 * Finish off the attach.
237	 */
238	epic_attach(sc);
239}
240