xref: /netbsd-src/sys/dev/pci/if_ex_pci.c (revision 27578b9aac214cc7796ead81dcc5427e79d5f2a0)
1 /*	$NetBSD: if_ex_pci.c,v 1.18 2001/08/18 05:49:28 kanaoka Exp $	*/
2 
3 /*-
4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Frank van der Linden; 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  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the NetBSD
22  *	Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/mbuf.h>
43 #include <sys/socket.h>
44 #include <sys/ioctl.h>
45 #include <sys/errno.h>
46 #include <sys/syslog.h>
47 #include <sys/select.h>
48 #include <sys/device.h>
49 
50 #include <net/if.h>
51 #include <net/if_dl.h>
52 #include <net/if_ether.h>
53 #include <net/if_media.h>
54 
55 #include <machine/cpu.h>
56 #include <machine/bus.h>
57 #include <machine/intr.h>
58 
59 #include <dev/mii/miivar.h>
60 #include <dev/mii/mii.h>
61 
62 #include <dev/ic/elink3var.h>
63 #include <dev/ic/elink3reg.h>
64 #include <dev/ic/elinkxlreg.h>
65 #include <dev/ic/elinkxlvar.h>
66 
67 #include <dev/pci/pcivar.h>
68 #include <dev/pci/pcireg.h>
69 #include <dev/pci/pcidevs.h>
70 
71 struct ex_pci_softc {
72 	struct ex_softc sc_ex;
73 
74 	/* PCI function status space. 556,556B requests it. */
75 	bus_space_tag_t sc_funct;
76 	bus_space_handle_t sc_funch;
77 
78 };
79 
80 /*
81  * PCI constants.
82  * XXX These should be in a common file!
83  */
84 #define PCI_CONN		0x48    /* Connector type */
85 #define PCI_CBIO		0x10    /* Configuration Base IO Address */
86 #define PCI_POWERCTL		0xe0
87 #define PCI_FUNCMEM		0x18
88 
89 #define PCI_INTR		4
90 #define PCI_INTRACK		0x00008000
91 
92 int ex_pci_match __P((struct device *, struct cfdata *, void *));
93 void ex_pci_attach __P((struct device *, struct device *, void *));
94 void ex_pci_intr_ack __P((struct ex_softc *));
95 
96 struct cfattach ex_pci_ca = {
97 	sizeof(struct ex_pci_softc), ex_pci_match, ex_pci_attach
98 };
99 
100 const struct ex_pci_product {
101 	u_int32_t	epp_prodid;	/* PCI product ID */
102 	int		epp_flags;	/* initial softc flags */
103 	const char	*epp_name;	/* device name */
104 } ex_pci_products[] = {
105 	{ PCI_PRODUCT_3COM_3C900TPO,	0,
106 	  "3c900-TPO Ethernet" },
107 	{ PCI_PRODUCT_3COM_3C900COMBO,	0,
108 	  "3c900-COMBO Ethernet" },
109 
110 	{ PCI_PRODUCT_3COM_3C905TX,	EX_CONF_MII,
111 	  "3c905-TX 10/100 Ethernet" },
112 	{ PCI_PRODUCT_3COM_3C905T4,	EX_CONF_MII,
113 	  "3c905-T4 10/100 Ethernet" },
114 
115 	{ PCI_PRODUCT_3COM_3C900BTPO,	EX_CONF_90XB,
116 	  "3c900B-TPO Ethernet" },
117 	{ PCI_PRODUCT_3COM_3C900BCOMBO,	EX_CONF_90XB,
118 	  "3c900B-COMBO Ethernet" },
119 	{ PCI_PRODUCT_3COM_3C900BTPC,   EX_CONF_90XB,
120 	  "3c900B-TPC Ethernet" },
121 
122 	{ PCI_PRODUCT_3COM_3C905BTX,	EX_CONF_90XB|EX_CONF_MII|EX_CONF_INTPHY,
123 	  "3c905B-TX 10/100 Ethernet" },
124 	{ PCI_PRODUCT_3COM_3C905BT4,	EX_CONF_90XB|EX_CONF_MII,
125 	  "3c905B-T4 10/100 Ethernet" },
126 	{ PCI_PRODUCT_3COM_3C905BCOMBO,	EX_CONF_90XB/*|EX_CONF_MII|EX_CONF_INTPHY*/,
127 	  "3c905B-COMBO 10/100 Ethernet" },
128 	{ PCI_PRODUCT_3COM_3C905BFX,	EX_CONF_90XB,
129 	  "3c905B-FX 10/100 Ethernet" },
130 
131 	/* XXX Internal PHY? */
132 	{ PCI_PRODUCT_3COM_3C980SRV,	EX_CONF_90XB,
133 	  "3c980 Server Adapter 10/100 Ethernet" },
134 	{ PCI_PRODUCT_3COM_3C980CTXM,	EX_CONF_90XB,
135 	  "3c980C-TXM 10/100 Ethernet" },
136 
137 	{ PCI_PRODUCT_3COM_3C905CTX,	EX_CONF_90XB|EX_CONF_MII,
138 	  "3c905C-TX 10/100 Ethernet with mngmt" },
139 
140 	{ PCI_PRODUCT_3COM_3C450TX,		EX_CONF_90XB,
141 	  "3c450-TX 10/100 Ethernet" },
142 
143 	{ PCI_PRODUCT_3COM_3CSOHO100TX,	EX_CONF_90XB,
144 	  "3cSOHO100-TX 10/100 Ethernet" },
145 
146 	{ PCI_PRODUCT_3COM_3C555,
147 	   EX_CONF_90XB | EX_CONF_MII | EX_CONF_EEPROM_OFF |
148 	   EX_CONF_EEPROM_8BIT,
149 	  "3c555 MiniPCI 10/100 Ethernet" },
150 
151 	{ PCI_PRODUCT_3COM_3C556,
152 	   EX_CONF_90XB | EX_CONF_MII | EX_CONF_EEPROM_OFF |
153 	   EX_CONF_PCI_FUNCREG | EX_CONF_RESETHACK | EX_CONF_INV_LED_POLARITY |
154 	   EX_CONF_PHY_POWER | EX_CONF_EEPROM_8BIT,
155 	  "3c556 MiniPCI 10/100 Ethernet" },
156 
157 	{ PCI_PRODUCT_3COM_3C556B,
158 	   EX_CONF_90XB | EX_CONF_MII | EX_CONF_EEPROM_OFF |
159 	   EX_CONF_PCI_FUNCREG | EX_CONF_RESETHACK | EX_CONF_INV_LED_POLARITY |
160 	   EX_CONF_PHY_POWER,
161 	  "3c556B MiniPCI 10/100 Ethernet" },
162 
163 	{ 0,				0,
164 	  NULL },
165 };
166 
167 const struct ex_pci_product *ex_pci_lookup
168     __P((const struct pci_attach_args *));
169 
170 const struct ex_pci_product *
171 ex_pci_lookup(pa)
172 	const struct pci_attach_args *pa;
173 {
174 	const struct ex_pci_product *epp;
175 
176 	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_3COM)
177 		return (NULL);
178 
179 	for (epp = ex_pci_products; epp->epp_name != NULL; epp++)
180 		if (PCI_PRODUCT(pa->pa_id) == epp->epp_prodid)
181 			return (epp);
182 	return (NULL);
183 }
184 
185 int
186 ex_pci_match(parent, match, aux)
187 	struct device *parent;
188 	struct cfdata *match;
189 	void *aux;
190 {
191 	struct pci_attach_args *pa = (struct pci_attach_args *) aux;
192 
193 	if (ex_pci_lookup(pa) != NULL)
194 		return (2);	/* beat ep_pci */
195 
196 	return (0);
197 }
198 
199 void
200 ex_pci_attach(parent, self, aux)
201 	struct device *parent, *self;
202 	void *aux;
203 {
204 	struct ex_softc *sc = (void *)self;
205 	struct ex_pci_softc *psc = (void *)self;
206 	struct pci_attach_args *pa = aux;
207 	pci_chipset_tag_t pc = pa->pa_pc;
208 	pci_intr_handle_t ih;
209 	const struct ex_pci_product *epp;
210 	const char *intrstr = NULL;
211 	int rev, pmreg;
212 	pcireg_t reg;
213 
214 	if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0,
215 	    &sc->sc_iot, &sc->sc_ioh, NULL, NULL)) {
216 		printf(": can't map i/o space\n");
217 		return;
218 	}
219 
220 	epp = ex_pci_lookup(pa);
221 	if (epp == NULL) {
222 		printf("\n");
223 		panic("ex_pci_attach: impossible");
224 	}
225 
226 	rev = PCI_REVISION(pci_conf_read(pc, pa->pa_tag, PCI_CLASS_REG));
227 	printf(": 3Com %s (rev. 0x%x)\n", epp->epp_name, rev);
228 
229 	sc->enable = NULL;
230 	sc->disable = NULL;
231 	sc->enabled = 1;
232 
233 	sc->sc_dmat = pa->pa_dmat;
234 
235 	sc->ex_bustype = EX_BUS_PCI;
236 	sc->ex_conf = epp->epp_flags;
237 
238 	/* Enable the card. */
239 	pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
240 	    pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) |
241 	    PCI_COMMAND_MASTER_ENABLE);
242 
243 	if (sc->ex_conf & EX_CONF_PCI_FUNCREG) {
244 		/* Map PCI function status window. */
245 		if (pci_mapreg_map(pa, PCI_FUNCMEM, PCI_MAPREG_TYPE_MEM, 0,
246 		    &psc->sc_funct, &psc->sc_funch, NULL, NULL)) {
247 			printf("%s: unable to map function status window\n",
248 			    sc->sc_dev.dv_xname);
249 			return;
250 		}
251 		sc->intr_ack = ex_pci_intr_ack;
252 	}
253 
254 	/* Get it out of power save mode if needed (BIOS bugs) */
255 	if (pci_get_capability(pc, pa->pa_tag, PCI_CAP_PWRMGMT, &pmreg, 0)) {
256 		reg = pci_conf_read(pc, pa->pa_tag, pmreg + 4) & 0x3;
257 		if (reg == 3) {
258 			/*
259 			 * The card has lost all configuration data in
260 			 * this state, so punt.
261 			 */
262 			printf("%s: unable to wake up from power state D3\n",
263 			    sc->sc_dev.dv_xname);
264 			return;
265 		}
266 		if (reg != 0) {
267 			printf("%s: waking up from power state D%d\n",
268 			    sc->sc_dev.dv_xname, reg);
269 			pci_conf_write(pc, pa->pa_tag, pmreg + 4, 0);
270 		}
271 	}
272 
273 	/* Map and establish the interrupt. */
274 	if (pci_intr_map(pa, &ih)) {
275 		printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
276 		return;
277 	}
278 
279 	intrstr = pci_intr_string(pc, ih);
280 	sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, ex_intr, sc);
281 	if (sc->sc_ih == NULL) {
282 		printf("%s: couldn't establish interrupt",
283 		    sc->sc_dev.dv_xname);
284 		if (intrstr != NULL)
285 			printf(" at %s", intrstr);
286 		printf("\n");
287 		return;
288 	}
289 	printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
290 
291 	ex_config(sc);
292 
293 	if (sc->ex_conf & EX_CONF_PCI_FUNCREG)
294 		bus_space_write_4(psc->sc_funct, psc->sc_funch, PCI_INTR,
295 		    PCI_INTRACK);
296 }
297 
298 void
299 ex_pci_intr_ack(sc)
300 	struct ex_softc *sc;
301 {
302 	struct ex_pci_softc *psc = (struct ex_pci_softc *)sc;
303 
304 	bus_space_write_4(psc->sc_funct, psc->sc_funch, PCI_INTR,
305 	    PCI_INTRACK);
306 }
307