xref: /openbsd/sys/dev/pci/if_epic_pci.c (revision 059342fc)
1*059342fcSbrad /*	$OpenBSD: if_epic_pci.c,v 1.1 2005/05/10 01:16:32 brad Exp $	*/
2*059342fcSbrad /*	$NetBSD: if_epic_pci.c,v 1.28 2005/02/27 00:27:32 perry Exp $	*/
3*059342fcSbrad 
4*059342fcSbrad /*-
5*059342fcSbrad  * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
6*059342fcSbrad  * All rights reserved.
7*059342fcSbrad  *
8*059342fcSbrad  * This code is derived from software contributed to The NetBSD Foundation
9*059342fcSbrad  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10*059342fcSbrad  * NASA Ames Research Center.
11*059342fcSbrad  *
12*059342fcSbrad  * Redistribution and use in source and binary forms, with or without
13*059342fcSbrad  * modification, are permitted provided that the following conditions
14*059342fcSbrad  * are met:
15*059342fcSbrad  * 1. Redistributions of source code must retain the above copyright
16*059342fcSbrad  *    notice, this list of conditions and the following disclaimer.
17*059342fcSbrad  * 2. Redistributions in binary form must reproduce the above copyright
18*059342fcSbrad  *    notice, this list of conditions and the following disclaimer in the
19*059342fcSbrad  *    documentation and/or other materials provided with the distribution.
20*059342fcSbrad  * 3. All advertising materials mentioning features or use of this software
21*059342fcSbrad  *    must display the following acknowledgement:
22*059342fcSbrad  *	This product includes software developed by the NetBSD
23*059342fcSbrad  *	Foundation, Inc. and its contributors.
24*059342fcSbrad  * 4. Neither the name of The NetBSD Foundation nor the names of its
25*059342fcSbrad  *    contributors may be used to endorse or promote products derived
26*059342fcSbrad  *    from this software without specific prior written permission.
27*059342fcSbrad  *
28*059342fcSbrad  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29*059342fcSbrad  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30*059342fcSbrad  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31*059342fcSbrad  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32*059342fcSbrad  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33*059342fcSbrad  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34*059342fcSbrad  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35*059342fcSbrad  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36*059342fcSbrad  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37*059342fcSbrad  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38*059342fcSbrad  * POSSIBILITY OF SUCH DAMAGE.
39*059342fcSbrad  */
40*059342fcSbrad 
41*059342fcSbrad /*
42*059342fcSbrad  * PCI bus front-end for the Standard Microsystems Corp. 83C170
43*059342fcSbrad  * Ethernet PCI Integrated Controller (EPIC/100) driver.
44*059342fcSbrad  */
45*059342fcSbrad 
46*059342fcSbrad #if 0
47*059342fcSbrad #include <sys/cdefs.h>
48*059342fcSbrad __KERNEL_RCSID(0, "$NetBSD: if_epic_pci.c,v 1.28 2005/02/27 00:27:32 perry Exp $");
49*059342fcSbrad #endif
50*059342fcSbrad 
51*059342fcSbrad #include <sys/param.h>
52*059342fcSbrad #include <sys/systm.h>
53*059342fcSbrad #include <sys/mbuf.h>
54*059342fcSbrad #include <sys/malloc.h>
55*059342fcSbrad #include <sys/kernel.h>
56*059342fcSbrad #include <sys/socket.h>
57*059342fcSbrad #include <sys/ioctl.h>
58*059342fcSbrad #include <sys/errno.h>
59*059342fcSbrad #include <sys/device.h>
60*059342fcSbrad 
61*059342fcSbrad #include <net/if.h>
62*059342fcSbrad #include <net/if_dl.h>
63*059342fcSbrad #include <net/if_types.h>
64*059342fcSbrad 
65*059342fcSbrad #ifdef INET
66*059342fcSbrad #include <netinet/in.h>
67*059342fcSbrad #include <netinet/in_systm.h>
68*059342fcSbrad #include <netinet/in_var.h>
69*059342fcSbrad #include <netinet/ip.h>
70*059342fcSbrad #include <netinet/if_ether.h>
71*059342fcSbrad #endif
72*059342fcSbrad 
73*059342fcSbrad #include <net/if_media.h>
74*059342fcSbrad 
75*059342fcSbrad #include <machine/bus.h>
76*059342fcSbrad #include <machine/intr.h>
77*059342fcSbrad 
78*059342fcSbrad #include <dev/mii/miivar.h>
79*059342fcSbrad 
80*059342fcSbrad #include <dev/ic/smc83c170reg.h>
81*059342fcSbrad #include <dev/ic/smc83c170var.h>
82*059342fcSbrad 
83*059342fcSbrad #include <dev/pci/pcivar.h>
84*059342fcSbrad #include <dev/pci/pcireg.h>
85*059342fcSbrad #include <dev/pci/pcidevs.h>
86*059342fcSbrad 
87*059342fcSbrad /*
88*059342fcSbrad  * PCI configuration space registers used by the EPIC.
89*059342fcSbrad  */
90*059342fcSbrad #define	EPIC_PCI_IOBA		0x10	/* i/o mapped base */
91*059342fcSbrad #define	EPIC_PCI_MMBA		0x14	/* memory mapped base */
92*059342fcSbrad 
93*059342fcSbrad struct epic_pci_softc {
94*059342fcSbrad 	struct epic_softc sc_epic;	/* real EPIC softc */
95*059342fcSbrad 
96*059342fcSbrad 	/* PCI-specific goo. */
97*059342fcSbrad 	void	*sc_ih;			/* interrupt handle */
98*059342fcSbrad };
99*059342fcSbrad 
100*059342fcSbrad static int	epic_pci_match(struct device *, void *, void *);
101*059342fcSbrad static void	epic_pci_attach(struct device *, struct device *, void *);
102*059342fcSbrad 
103*059342fcSbrad struct cfattach epic_pci_ca = {
104*059342fcSbrad 	sizeof(struct epic_pci_softc), epic_pci_match, epic_pci_attach
105*059342fcSbrad };
106*059342fcSbrad 
107*059342fcSbrad static const struct epic_pci_product {
108*059342fcSbrad 	u_int32_t	epp_prodid;	/* PCI product ID */
109*059342fcSbrad 	const char	*epp_name;	/* device name */
110*059342fcSbrad } epic_pci_products[] = {
111*059342fcSbrad 	{ PCI_PRODUCT_SMC_83C170,	"SMC 83c170 Fast Ethernet" },
112*059342fcSbrad 	{ PCI_PRODUCT_SMC_83C175,	"SMC 83c175 Fast Ethernet" },
113*059342fcSbrad 	{ 0,				NULL },
114*059342fcSbrad };
115*059342fcSbrad 
116*059342fcSbrad static const struct epic_pci_product *
117*059342fcSbrad epic_pci_lookup(const struct pci_attach_args *pa)
118*059342fcSbrad {
119*059342fcSbrad 	const struct epic_pci_product *epp;
120*059342fcSbrad 
121*059342fcSbrad 	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_SMC)
122*059342fcSbrad 		return (NULL);
123*059342fcSbrad 
124*059342fcSbrad 	for (epp = epic_pci_products; epp->epp_name != NULL; epp++)
125*059342fcSbrad 		if (PCI_PRODUCT(pa->pa_id) == epp->epp_prodid)
126*059342fcSbrad 			return (epp);
127*059342fcSbrad 
128*059342fcSbrad 	return (NULL);
129*059342fcSbrad }
130*059342fcSbrad 
131*059342fcSbrad static const struct epic_pci_subsys_info {
132*059342fcSbrad 	pcireg_t subsysid;
133*059342fcSbrad 	int flags;
134*059342fcSbrad } epic_pci_subsys_info[] = {
135*059342fcSbrad 	{ PCI_ID_CODE(PCI_VENDOR_SMC, 0xa015), /* SMC9432BTX */
136*059342fcSbrad 	  EPIC_HAS_BNC },
137*059342fcSbrad 	{ PCI_ID_CODE(PCI_VENDOR_SMC, 0xa024), /* SMC9432BTX1 */
138*059342fcSbrad 	  EPIC_HAS_BNC },
139*059342fcSbrad 	{ PCI_ID_CODE(PCI_VENDOR_SMC, 0xa016), /* SMC9432FTX */
140*059342fcSbrad 	  EPIC_HAS_MII_FIBER | EPIC_DUPLEXLED_ON_694 },
141*059342fcSbrad 	{ 0xffffffff,
142*059342fcSbrad 	  0 }
143*059342fcSbrad };
144*059342fcSbrad 
145*059342fcSbrad static const struct epic_pci_subsys_info *
146*059342fcSbrad epic_pci_subsys_lookup(const struct pci_attach_args *pa)
147*059342fcSbrad {
148*059342fcSbrad 	pci_chipset_tag_t pc = pa->pa_pc;
149*059342fcSbrad 	pcireg_t reg;
150*059342fcSbrad 	const struct epic_pci_subsys_info *esp;
151*059342fcSbrad 
152*059342fcSbrad 	reg = pci_conf_read(pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
153*059342fcSbrad 
154*059342fcSbrad 	for (esp = epic_pci_subsys_info; esp->subsysid != 0xffffffff; esp++)
155*059342fcSbrad 		if (esp->subsysid == reg)
156*059342fcSbrad 			return (esp);
157*059342fcSbrad 
158*059342fcSbrad 	return (NULL);
159*059342fcSbrad }
160*059342fcSbrad 
161*059342fcSbrad static int
162*059342fcSbrad epic_pci_match(struct device *parent, void *match, void *aux)
163*059342fcSbrad {
164*059342fcSbrad 	struct pci_attach_args *pa = aux;
165*059342fcSbrad 
166*059342fcSbrad 	if (epic_pci_lookup(pa) != NULL)
167*059342fcSbrad 		return (1);
168*059342fcSbrad 
169*059342fcSbrad 	return (0);
170*059342fcSbrad }
171*059342fcSbrad 
172*059342fcSbrad static void
173*059342fcSbrad epic_pci_attach(struct device *parent, struct device *self, void *aux)
174*059342fcSbrad {
175*059342fcSbrad 	struct epic_pci_softc *psc = (struct epic_pci_softc *)self;
176*059342fcSbrad 	struct epic_softc *sc = &psc->sc_epic;
177*059342fcSbrad 	struct pci_attach_args *pa = aux;
178*059342fcSbrad 	pci_chipset_tag_t pc = pa->pa_pc;
179*059342fcSbrad 	pci_intr_handle_t ih;
180*059342fcSbrad 	const char *intrstr = NULL;
181*059342fcSbrad 	const struct epic_pci_product *epp;
182*059342fcSbrad 	const struct epic_pci_subsys_info *esp;
183*059342fcSbrad 	bus_space_tag_t iot, memt;
184*059342fcSbrad 	bus_space_handle_t ioh, memh;
185*059342fcSbrad 	pcireg_t reg;
186*059342fcSbrad 	int pmreg, ioh_valid, memh_valid;
187*059342fcSbrad 
188*059342fcSbrad 	epp = epic_pci_lookup(pa);
189*059342fcSbrad 	if (epp == NULL) {
190*059342fcSbrad 		printf("\n");
191*059342fcSbrad 		panic(": epic_pci_attach: impossible");
192*059342fcSbrad 	}
193*059342fcSbrad 
194*059342fcSbrad 	if (pci_get_capability(pc, pa->pa_tag, PCI_CAP_PWRMGMT, &pmreg, 0)) {
195*059342fcSbrad 		reg = pci_conf_read(pc, pa->pa_tag, pmreg + PCI_PMCSR);
196*059342fcSbrad 		switch (reg & PCI_PMCSR_STATE_MASK) {
197*059342fcSbrad 		case PCI_PMCSR_STATE_D1:
198*059342fcSbrad 		case PCI_PMCSR_STATE_D2:
199*059342fcSbrad 			printf(": waking up from power state D%d\n",
200*059342fcSbrad 			    sc->sc_dev.dv_xname, reg & PCI_PMCSR_STATE_MASK);
201*059342fcSbrad 			pci_conf_write(pc, pa->pa_tag, pmreg + PCI_PMCSR,
202*059342fcSbrad 			    (reg & ~PCI_PMCSR_STATE_MASK) |
203*059342fcSbrad 			    PCI_PMCSR_STATE_D0);
204*059342fcSbrad 			break;
205*059342fcSbrad 		case PCI_PMCSR_STATE_D3:
206*059342fcSbrad 			/*
207*059342fcSbrad 			 * IO and MEM are disabled. We can't enable
208*059342fcSbrad 			 * the card because the BARs might be invalid.
209*059342fcSbrad 			 */
210*059342fcSbrad 			printf(
211*059342fcSbrad 			    ": unable to wake up from power state D3, "
212*059342fcSbrad 			    "reboot required.\n", sc->sc_dev.dv_xname);
213*059342fcSbrad 			pci_conf_write(pc, pa->pa_tag, pmreg + PCI_PMCSR,
214*059342fcSbrad 			    (reg & ~PCI_PMCSR_STATE_MASK) |
215*059342fcSbrad 			    PCI_PMCSR_STATE_D0);
216*059342fcSbrad 			return;
217*059342fcSbrad 		}
218*059342fcSbrad 	}
219*059342fcSbrad 
220*059342fcSbrad 	/*
221*059342fcSbrad 	 * Map the device.
222*059342fcSbrad 	 */
223*059342fcSbrad 	ioh_valid = (pci_mapreg_map(pa, EPIC_PCI_IOBA,
224*059342fcSbrad 	    PCI_MAPREG_TYPE_IO, 0,
225*059342fcSbrad 	    &iot, &ioh, NULL, NULL, 0) == 0);
226*059342fcSbrad 	memh_valid = (pci_mapreg_map(pa, EPIC_PCI_MMBA,
227*059342fcSbrad 	    PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0,
228*059342fcSbrad 	    &memt, &memh, NULL, NULL, 0) == 0);
229*059342fcSbrad 
230*059342fcSbrad 	if (memh_valid) {
231*059342fcSbrad 		sc->sc_st = memt;
232*059342fcSbrad 		sc->sc_sh = memh;
233*059342fcSbrad 	} else if (ioh_valid) {
234*059342fcSbrad 		sc->sc_st = iot;
235*059342fcSbrad 		sc->sc_sh = ioh;
236*059342fcSbrad 	} else {
237*059342fcSbrad 		printf(": unable to map device registers\n",
238*059342fcSbrad 		    sc->sc_dev.dv_xname);
239*059342fcSbrad 		return;
240*059342fcSbrad 	}
241*059342fcSbrad 
242*059342fcSbrad 	sc->sc_dmat = pa->pa_dmat;
243*059342fcSbrad 
244*059342fcSbrad 	/* Make sure bus mastering is enabled. */
245*059342fcSbrad 	pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
246*059342fcSbrad 	    pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) |
247*059342fcSbrad 	    PCI_COMMAND_MASTER_ENABLE);
248*059342fcSbrad 
249*059342fcSbrad 	/*
250*059342fcSbrad 	 * Map and establish our interrupt.
251*059342fcSbrad 	 */
252*059342fcSbrad 	if (pci_intr_map(pa, &ih)) {
253*059342fcSbrad 		printf(": unable to map interrupt\n",
254*059342fcSbrad 		    sc->sc_dev.dv_xname);
255*059342fcSbrad 		return;
256*059342fcSbrad 	}
257*059342fcSbrad 	intrstr = pci_intr_string(pc, ih);
258*059342fcSbrad 	psc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, epic_intr, sc,
259*059342fcSbrad 	    self->dv_xname);
260*059342fcSbrad 	if (psc->sc_ih == NULL) {
261*059342fcSbrad 		printf("%s: unable to establish interrupt",
262*059342fcSbrad 		    sc->sc_dev.dv_xname);
263*059342fcSbrad 		if (intrstr != NULL)
264*059342fcSbrad 			printf(" at %s", intrstr);
265*059342fcSbrad 		printf("\n");
266*059342fcSbrad 		return;
267*059342fcSbrad 	}
268*059342fcSbrad 
269*059342fcSbrad 	esp = epic_pci_subsys_lookup(pa);
270*059342fcSbrad 	if (esp)
271*059342fcSbrad 		sc->sc_hwflags = esp->flags;
272*059342fcSbrad 
273*059342fcSbrad 	/*
274*059342fcSbrad 	 * Finish off the attach.
275*059342fcSbrad 	 */
276*059342fcSbrad 	epic_attach(sc, intrstr);
277*059342fcSbrad }
278