1 | /* $NetBSD: if_fxp_pci.c,v 1.82 2015/04/13 16:33:25 riastradh Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1997, 1998, 1999, 2000, 2001 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 Intel i82557 fast Ethernet controller |
35 | * driver. Works with Intel Etherexpress Pro 10+, 100B, 100+ cards. |
36 | */ |
37 | |
38 | #include <sys/cdefs.h> |
39 | __KERNEL_RCSID(0, "$NetBSD: if_fxp_pci.c,v 1.82 2015/04/13 16:33:25 riastradh 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 <machine/endian.h> |
52 | |
53 | #include <net/if.h> |
54 | #include <net/if_dl.h> |
55 | #include <net/if_media.h> |
56 | #include <net/if_ether.h> |
57 | |
58 | #include <sys/bus.h> |
59 | #include <sys/intr.h> |
60 | |
61 | #include <dev/mii/miivar.h> |
62 | |
63 | #include <dev/ic/i82557reg.h> |
64 | #include <dev/ic/i82557var.h> |
65 | |
66 | #include <dev/pci/pcivar.h> |
67 | #include <dev/pci/pcireg.h> |
68 | #include <dev/pci/pcidevs.h> |
69 | |
70 | struct fxp_pci_softc { |
71 | struct fxp_softc psc_fxp; |
72 | |
73 | pci_chipset_tag_t psc_pc; /* pci chipset tag */ |
74 | pcireg_t psc_regs[0x20>>2]; /* saved PCI config regs (sparse) */ |
75 | pcitag_t psc_tag; /* pci register tag */ |
76 | |
77 | struct pci_conf_state psc_pciconf; /* standard PCI configuration regs */ |
78 | }; |
79 | |
80 | static int fxp_pci_match(device_t, cfdata_t, void *); |
81 | static void fxp_pci_attach(device_t, device_t, void *); |
82 | static int fxp_pci_detach(device_t, int); |
83 | |
84 | static int fxp_pci_enable(struct fxp_softc *); |
85 | |
86 | static void fxp_pci_confreg_restore(struct fxp_pci_softc *psc); |
87 | static bool fxp_pci_resume(device_t dv, const pmf_qual_t *); |
88 | |
89 | CFATTACH_DECL3_NEW(fxp_pci, sizeof(struct fxp_pci_softc), |
90 | fxp_pci_match, fxp_pci_attach, fxp_pci_detach, NULL, NULL, |
91 | null_childdetached, DVF_DETACH_SHUTDOWN); |
92 | |
93 | static const struct fxp_pci_product { |
94 | uint32_t fpp_prodid; /* PCI product ID */ |
95 | const char *fpp_name; /* device name */ |
96 | } fxp_pci_products[] = { |
97 | { PCI_PRODUCT_INTEL_82552, |
98 | "Intel i82552 10/100 Network Connection" }, |
99 | { PCI_PRODUCT_INTEL_8255X, |
100 | "Intel i8255x Ethernet" }, |
101 | { PCI_PRODUCT_INTEL_82559ER, |
102 | "Intel i82559ER Ethernet" }, |
103 | { PCI_PRODUCT_INTEL_IN_BUSINESS, |
104 | "Intel InBusiness Ethernet" }, |
105 | { PCI_PRODUCT_INTEL_PRO_100, |
106 | "Intel PRO/100 Ethernet" }, |
107 | { PCI_PRODUCT_INTEL_PRO_100_VE_0, |
108 | "Intel PRO/100 VE Network Controller" }, |
109 | { PCI_PRODUCT_INTEL_PRO_100_VE_1, |
110 | "Intel PRO/100 VE Network Controller" }, |
111 | { PCI_PRODUCT_INTEL_PRO_100_VE_2, |
112 | "Intel PRO/100 VE Network Controller with 82562ET/EZ PHY" }, |
113 | { PCI_PRODUCT_INTEL_PRO_100_VE_3, |
114 | "Intel PRO/100 VE Network Controller with 82562ET/EZ (CNR) PHY" }, |
115 | { PCI_PRODUCT_INTEL_PRO_100_VE_4, |
116 | "Intel PRO/100 VE (MOB) Network Controller" }, |
117 | { PCI_PRODUCT_INTEL_PRO_100_VE_5, |
118 | "Intel PRO/100 VE (LOM) Network Controller" }, |
119 | { PCI_PRODUCT_INTEL_PRO_100_VE_6, |
120 | "Intel PRO/100 VE Network Controller" }, |
121 | { PCI_PRODUCT_INTEL_PRO_100_VE_7, |
122 | "Intel PRO/100 VE Network Controller" }, |
123 | { PCI_PRODUCT_INTEL_PRO_100_VE_8, |
124 | "Intel PRO/100 VE Network Controller" }, |
125 | { PCI_PRODUCT_INTEL_PRO_100_VE_9, |
126 | "Intel PRO/100 VE Network Controller" }, |
127 | { PCI_PRODUCT_INTEL_PRO_100_VE_10, |
128 | "Intel PRO/100 VE Network Controller" }, |
129 | { PCI_PRODUCT_INTEL_PRO_100_VE_11, |
130 | "Intel PRO/100 VE Network Controller" }, |
131 | { PCI_PRODUCT_INTEL_PRO_100_VM_0, |
132 | "Intel PRO/100 VM Network Controller" }, |
133 | { PCI_PRODUCT_INTEL_PRO_100_VM_1, |
134 | "Intel PRO/100 VM Network Controller" }, |
135 | { PCI_PRODUCT_INTEL_PRO_100_VM_2, |
136 | "Intel PRO/100 VM Network Controller" }, |
137 | { PCI_PRODUCT_INTEL_PRO_100_VM_3, |
138 | "Intel PRO/100 VM Network Controller with 82562EM/EX PHY" }, |
139 | { PCI_PRODUCT_INTEL_PRO_100_VM_4, |
140 | "Intel PRO/100 VM Network Controller with 82562EM/EX (CNR) PHY" }, |
141 | { PCI_PRODUCT_INTEL_PRO_100_VM_5, |
142 | "Intel PRO/100 VM (MOB) Network Controller" }, |
143 | { PCI_PRODUCT_INTEL_PRO_100_VM_6, |
144 | "Intel PRO/100 VM Network Controller with 82562ET/EZ PHY" }, |
145 | { PCI_PRODUCT_INTEL_PRO_100_VM_7, |
146 | "Intel PRO/100 VM Network Connection" }, |
147 | { PCI_PRODUCT_INTEL_PRO_100_VM_8, |
148 | "Intel PRO/100 VM Network Connection" }, |
149 | { PCI_PRODUCT_INTEL_PRO_100_VM_9, |
150 | "Intel PRO/100 VM Network Connection" }, |
151 | { PCI_PRODUCT_INTEL_PRO_100_VM_10, |
152 | "Intel PRO/100 VM Network Connection" }, |
153 | { PCI_PRODUCT_INTEL_PRO_100_VM_11, |
154 | "Intel PRO/100 VM Network Connection" }, |
155 | { PCI_PRODUCT_INTEL_PRO_100_VM_12, |
156 | "Intel PRO/100 VM Network Connection" }, |
157 | { PCI_PRODUCT_INTEL_PRO_100_VM_13, |
158 | "Intel PRO/100 VM Network Connection" }, |
159 | { PCI_PRODUCT_INTEL_PRO_100_VM_14, |
160 | "Intel PRO/100 VM Network Connection" }, |
161 | { PCI_PRODUCT_INTEL_PRO_100_VM_15, |
162 | "Intel PRO/100 VM Network Connection" }, |
163 | { PCI_PRODUCT_INTEL_PRO_100_VM_16, |
164 | "Intel PRO/100 VM Network Connection" }, |
165 | { PCI_PRODUCT_INTEL_PRO_100_M, |
166 | "Intel PRO/100 M Network Controller" }, |
167 | { PCI_PRODUCT_INTEL_82801BA_LAN, |
168 | "Intel i82562 Ethernet" }, |
169 | { PCI_PRODUCT_INTEL_82801E_LAN_1, |
170 | "Intel i82801E Ethernet" }, |
171 | { PCI_PRODUCT_INTEL_82801E_LAN_2, |
172 | "Intel i82801E Ethernet" }, |
173 | { PCI_PRODUCT_INTEL_82801EB_LAN, |
174 | "Intel 82801EB/ER (ICH5) Network Controller" }, |
175 | { PCI_PRODUCT_INTEL_82801FB_LAN, |
176 | "Intel i82801FB LAN Controller" }, |
177 | { PCI_PRODUCT_INTEL_82801FB_LAN_2, |
178 | "Intel i82801FB LAN Controller" }, |
179 | { PCI_PRODUCT_INTEL_82801G_LAN, |
180 | "Intel 82801GB/GR (ICH7) Network Controller" }, |
181 | { PCI_PRODUCT_INTEL_82801GB_LAN, |
182 | "Intel 82801GB 10/100 Network Controller" }, |
183 | { 0, |
184 | NULL }, |
185 | }; |
186 | |
187 | static const struct fxp_pci_product * |
188 | fxp_pci_lookup(const struct pci_attach_args *pa) |
189 | { |
190 | const struct fxp_pci_product *fpp; |
191 | |
192 | if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL) |
193 | return (NULL); |
194 | |
195 | for (fpp = fxp_pci_products; fpp->fpp_name != NULL; fpp++) |
196 | if (PCI_PRODUCT(pa->pa_id) == fpp->fpp_prodid) |
197 | return (fpp); |
198 | |
199 | return (NULL); |
200 | } |
201 | |
202 | static int |
203 | fxp_pci_match(device_t parent, cfdata_t match, void *aux) |
204 | { |
205 | struct pci_attach_args *pa = aux; |
206 | |
207 | if (fxp_pci_lookup(pa) != NULL) |
208 | return (1); |
209 | |
210 | return (0); |
211 | } |
212 | |
213 | /* |
214 | * On resume : (XXX it is necessary with new pmf framework ?) |
215 | * Restore PCI configuration registers that may have been clobbered. |
216 | * This is necessary due to bugs on the Sony VAIO Z505-series on-board |
217 | * ethernet, after an APM suspend/resume, as well as after an ACPI |
218 | * D3->D0 transition. We call this function from a power hook after |
219 | * APM resume events, as well as after the ACPI D3->D0 transition. |
220 | */ |
221 | static void |
222 | fxp_pci_confreg_restore(struct fxp_pci_softc *psc) |
223 | { |
224 | pcireg_t reg; |
225 | |
226 | #if 0 |
227 | /* |
228 | * Check to see if the command register is blank -- if so, then |
229 | * we'll assume that all the clobberable-registers have been |
230 | * clobbered. |
231 | */ |
232 | |
233 | /* |
234 | * In general, the above metric is accurate. Unfortunately, |
235 | * it is inaccurate across a hibernation. Ideally APM/ACPI |
236 | * code should take note of hibernation events and execute |
237 | * a hibernation wakeup hook, but at present a hibernation wake |
238 | * is indistinguishable from a suspend wake. |
239 | */ |
240 | |
241 | if (((reg = pci_conf_read(psc->psc_pc, psc->psc_tag, |
242 | PCI_COMMAND_STATUS_REG)) & 0xffff) != 0) |
243 | return; |
244 | #else |
245 | reg = pci_conf_read(psc->psc_pc, psc->psc_tag, PCI_COMMAND_STATUS_REG); |
246 | #endif |
247 | |
248 | pci_conf_write(psc->psc_pc, psc->psc_tag, |
249 | PCI_COMMAND_STATUS_REG, |
250 | (reg & 0xffff0000) | |
251 | (psc->psc_regs[PCI_COMMAND_STATUS_REG>>2] & 0xffff)); |
252 | pci_conf_write(psc->psc_pc, psc->psc_tag, PCI_BHLC_REG, |
253 | psc->psc_regs[PCI_BHLC_REG>>2]); |
254 | pci_conf_write(psc->psc_pc, psc->psc_tag, PCI_MAPREG_START+0x0, |
255 | psc->psc_regs[(PCI_MAPREG_START+0x0)>>2]); |
256 | pci_conf_write(psc->psc_pc, psc->psc_tag, PCI_MAPREG_START+0x4, |
257 | psc->psc_regs[(PCI_MAPREG_START+0x4)>>2]); |
258 | pci_conf_write(psc->psc_pc, psc->psc_tag, PCI_MAPREG_START+0x8, |
259 | psc->psc_regs[(PCI_MAPREG_START+0x8)>>2]); |
260 | } |
261 | |
262 | static bool |
263 | fxp_pci_resume(device_t dv, const pmf_qual_t *qual) |
264 | { |
265 | struct fxp_pci_softc *psc = device_private(dv); |
266 | fxp_pci_confreg_restore(psc); |
267 | |
268 | return true; |
269 | } |
270 | |
271 | static int |
272 | fxp_pci_detach(device_t self, int flags) |
273 | { |
274 | struct fxp_pci_softc *psc = device_private(self); |
275 | struct fxp_softc *sc = &psc->psc_fxp; |
276 | int error; |
277 | |
278 | /* Finish off the attach. */ |
279 | if ((error = fxp_detach(sc, flags)) != 0) |
280 | return error; |
281 | |
282 | pmf_device_deregister(self); |
283 | |
284 | pci_intr_disestablish(psc->psc_pc, sc->sc_ih); |
285 | |
286 | bus_space_unmap(sc->sc_st, sc->sc_sh, sc->sc_size); |
287 | |
288 | return 0; |
289 | } |
290 | |
291 | static void |
292 | fxp_pci_attach(device_t parent, device_t self, void *aux) |
293 | { |
294 | struct fxp_pci_softc *psc = device_private(self); |
295 | struct fxp_softc *sc = &psc->psc_fxp; |
296 | const struct pci_attach_args *pa = aux; |
297 | pci_chipset_tag_t pc = pa->pa_pc; |
298 | pci_intr_handle_t ih; |
299 | const struct fxp_pci_product *fpp; |
300 | const char *chipname = NULL; |
301 | const char *intrstr = NULL; |
302 | bus_space_tag_t iot, memt; |
303 | bus_space_handle_t ioh, memh; |
304 | int ioh_valid, memh_valid; |
305 | bus_addr_t addr; |
306 | int flags; |
307 | int error; |
308 | char intrbuf[PCI_INTRSTR_LEN]; |
309 | |
310 | sc->sc_dev = self; |
311 | |
312 | /* |
313 | * Map control/status registers. |
314 | */ |
315 | ioh_valid = (pci_mapreg_map(pa, FXP_PCI_IOBA, |
316 | PCI_MAPREG_TYPE_IO, 0, |
317 | &iot, &ioh, NULL, NULL) == 0); |
318 | |
319 | /* |
320 | * Version 2.1 of the PCI spec, page 196, "Address Maps": |
321 | * |
322 | * Prefetchable |
323 | * |
324 | * Set to one if there are no side effects on reads, the |
325 | * device returns all bytes regardless of the byte enables, |
326 | * and host bridges can merge processor writes into this |
327 | * range without causing errors. Bit must be set to zero |
328 | * otherwise. |
329 | * |
330 | * The 82557 incorrectly sets the "prefetchable" bit, resulting |
331 | * in errors on systems which will do merged reads and writes. |
332 | * These errors manifest themselves as all-bits-set when reading |
333 | * from the EEPROM or other < 4 byte registers. |
334 | * |
335 | * We must work around this problem by always forcing the mapping |
336 | * for memory space to be uncacheable. On systems which cannot |
337 | * create an uncacheable mapping (because the firmware mapped it |
338 | * into only cacheable/prefetchable space due to the "prefetchable" |
339 | * bit), we can fall back onto i/o mapped access. |
340 | */ |
341 | memh_valid = 0; |
342 | memt = pa->pa_memt; |
343 | if (((pa->pa_flags & PCI_FLAGS_MEM_OKAY) != 0) && |
344 | pci_mapreg_info(pa->pa_pc, pa->pa_tag, FXP_PCI_MMBA, |
345 | PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, |
346 | &addr, &sc->sc_size, &flags) == 0) { |
347 | flags &= ~BUS_SPACE_MAP_PREFETCHABLE; |
348 | if (bus_space_map(memt, addr, sc->sc_size, flags, &memh) == 0) |
349 | memh_valid = 1; |
350 | } |
351 | |
352 | if (memh_valid) { |
353 | sc->sc_st = memt; |
354 | sc->sc_sh = memh; |
355 | } else if (ioh_valid) { |
356 | sc->sc_st = iot; |
357 | sc->sc_sh = ioh; |
358 | } else { |
359 | aprint_error(": unable to map device registers\n" ); |
360 | return; |
361 | } |
362 | |
363 | sc->sc_dmat = pa->pa_dmat; |
364 | |
365 | fpp = fxp_pci_lookup(pa); |
366 | if (fpp == NULL) { |
367 | printf("\n" ); |
368 | panic("fxp_pci_attach: impossible" ); |
369 | } |
370 | |
371 | sc->sc_rev = PCI_REVISION(pa->pa_class); |
372 | |
373 | switch (fpp->fpp_prodid) { |
374 | case PCI_PRODUCT_INTEL_8255X: |
375 | case PCI_PRODUCT_INTEL_IN_BUSINESS: |
376 | |
377 | if (sc->sc_rev >= FXP_REV_82558_A4) { |
378 | chipname = "i82558 Ethernet" ; |
379 | sc->sc_flags |= FXPF_FC|FXPF_EXT_TXCB; |
380 | /* |
381 | * Enable the MWI command for memory writes. |
382 | */ |
383 | if (pa->pa_flags & PCI_FLAGS_MWI_OKAY) |
384 | sc->sc_flags |= FXPF_MWI; |
385 | } |
386 | if (sc->sc_rev >= FXP_REV_82559_A0) { |
387 | chipname = "i82559 Ethernet" ; |
388 | sc->sc_flags |= FXPF_82559_RXCSUM; |
389 | } |
390 | if (sc->sc_rev >= FXP_REV_82559S_A) |
391 | chipname = "i82559S Ethernet" ; |
392 | if (sc->sc_rev >= FXP_REV_82550) { |
393 | chipname = "i82550 Ethernet" ; |
394 | sc->sc_flags &= ~FXPF_82559_RXCSUM; |
395 | sc->sc_flags |= FXPF_EXT_RFA; |
396 | } |
397 | if (sc->sc_rev >= FXP_REV_82551_E) |
398 | chipname = "i82551 Ethernet" ; |
399 | |
400 | /* |
401 | * Mark all i82559 and i82550 revisions as having |
402 | * the "resume bug". See i82557.c for details. |
403 | */ |
404 | if (sc->sc_rev >= FXP_REV_82559_A0) |
405 | sc->sc_flags |= FXPF_HAS_RESUME_BUG; |
406 | |
407 | break; |
408 | |
409 | case PCI_PRODUCT_INTEL_82559ER: |
410 | sc->sc_flags |= FXPF_FC|FXPF_EXT_TXCB; |
411 | |
412 | /* |
413 | * i82559ER/82551ER don't support RX hardware checksumming |
414 | * even though it has a newer revision number than 82559_A0. |
415 | */ |
416 | |
417 | /* All i82559 have the "resume bug". */ |
418 | sc->sc_flags |= FXPF_HAS_RESUME_BUG; |
419 | |
420 | /* Enable the MWI command for memory writes. */ |
421 | if (pa->pa_flags & PCI_FLAGS_MWI_OKAY) |
422 | sc->sc_flags |= FXPF_MWI; |
423 | |
424 | if (sc->sc_rev >= FXP_REV_82551_E) |
425 | chipname = "Intel i82551ER Ethernet" ; |
426 | |
427 | break; |
428 | |
429 | case PCI_PRODUCT_INTEL_82801BA_LAN: |
430 | case PCI_PRODUCT_INTEL_PRO_100_VE_0: |
431 | case PCI_PRODUCT_INTEL_PRO_100_VE_1: |
432 | case PCI_PRODUCT_INTEL_PRO_100_VM_0: |
433 | case PCI_PRODUCT_INTEL_PRO_100_VM_1: |
434 | case PCI_PRODUCT_INTEL_82562EH_HPNA_0: |
435 | case PCI_PRODUCT_INTEL_82562EH_HPNA_1: |
436 | case PCI_PRODUCT_INTEL_82562EH_HPNA_2: |
437 | case PCI_PRODUCT_INTEL_PRO_100_VM_2: |
438 | /* |
439 | * The ICH-2 and ICH-3 have the "resume bug". |
440 | */ |
441 | sc->sc_flags |= FXPF_HAS_RESUME_BUG; |
442 | /* FALLTHROUGH */ |
443 | |
444 | default: |
445 | if (sc->sc_rev >= FXP_REV_82558_A4) |
446 | sc->sc_flags |= FXPF_FC|FXPF_EXT_TXCB; |
447 | if (sc->sc_rev >= FXP_REV_82559_A0) |
448 | sc->sc_flags |= FXPF_82559_RXCSUM; |
449 | |
450 | break; |
451 | } |
452 | |
453 | pci_aprint_devinfo_fancy(pa, "Ethernet controller" , |
454 | (chipname ? chipname : fpp->fpp_name), 1); |
455 | |
456 | /* Make sure bus-mastering is enabled. */ |
457 | pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, |
458 | pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) | |
459 | PCI_COMMAND_MASTER_ENABLE); |
460 | |
461 | /* |
462 | * Under some circumstances (such as APM suspend/resume |
463 | * cycles, and across ACPI power state changes), the |
464 | * i82257-family can lose the contents of critical PCI |
465 | * configuration registers, causing the card to be |
466 | * non-responsive and useless. This occurs on the Sony VAIO |
467 | * Z505-series, among others. Preserve them here so they can |
468 | * be later restored (by fxp_pci_confreg_restore()). |
469 | */ |
470 | psc->psc_pc = pc; |
471 | psc->psc_tag = pa->pa_tag; |
472 | psc->psc_regs[PCI_COMMAND_STATUS_REG>>2] = |
473 | pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); |
474 | psc->psc_regs[PCI_BHLC_REG>>2] = |
475 | pci_conf_read(pc, pa->pa_tag, PCI_BHLC_REG); |
476 | psc->psc_regs[(PCI_MAPREG_START+0x0)>>2] = |
477 | pci_conf_read(pc, pa->pa_tag, PCI_MAPREG_START+0x0); |
478 | psc->psc_regs[(PCI_MAPREG_START+0x4)>>2] = |
479 | pci_conf_read(pc, pa->pa_tag, PCI_MAPREG_START+0x4); |
480 | psc->psc_regs[(PCI_MAPREG_START+0x8)>>2] = |
481 | pci_conf_read(pc, pa->pa_tag, PCI_MAPREG_START+0x8); |
482 | |
483 | /* power up chip */ |
484 | switch ((error = pci_activate(pa->pa_pc, pa->pa_tag, self, |
485 | pci_activate_null))) { |
486 | case EOPNOTSUPP: |
487 | break; |
488 | case 0: |
489 | sc->sc_enable = fxp_pci_enable; |
490 | sc->sc_disable = NULL; |
491 | break; |
492 | default: |
493 | aprint_error_dev(self, "cannot activate %d\n" , error); |
494 | return; |
495 | } |
496 | |
497 | /* Restore PCI configuration registers. */ |
498 | fxp_pci_confreg_restore(psc); |
499 | |
500 | sc->sc_enabled = 1; |
501 | |
502 | /* |
503 | * Map and establish our interrupt. |
504 | */ |
505 | if (pci_intr_map(pa, &ih)) { |
506 | aprint_error_dev(self, "couldn't map interrupt\n" ); |
507 | return; |
508 | } |
509 | intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf)); |
510 | sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, fxp_intr, sc); |
511 | if (sc->sc_ih == NULL) { |
512 | aprint_error_dev(self, "couldn't establish interrupt" ); |
513 | if (intrstr != NULL) |
514 | aprint_error(" at %s" , intrstr); |
515 | aprint_error("\n" ); |
516 | return; |
517 | } |
518 | aprint_normal_dev(self, "interrupting at %s\n" , intrstr); |
519 | |
520 | /* Finish off the attach. */ |
521 | fxp_attach(sc); |
522 | if (sc->sc_disable != NULL) |
523 | fxp_disable(sc); |
524 | |
525 | /* Add a suspend hook to restore PCI config state */ |
526 | if (pmf_device_register(self, NULL, fxp_pci_resume)) |
527 | pmf_class_network_register(self, &sc->sc_ethercom.ec_if); |
528 | else |
529 | aprint_error_dev(self, "couldn't establish power handler\n" ); |
530 | } |
531 | |
532 | static int |
533 | fxp_pci_enable(struct fxp_softc *sc) |
534 | { |
535 | struct fxp_pci_softc *psc = (void *) sc; |
536 | |
537 | #if 0 |
538 | printf("%s: going to power state D0\n" , device_xname(self)); |
539 | #endif |
540 | |
541 | /* Now restore the configuration registers. */ |
542 | fxp_pci_confreg_restore(psc); |
543 | |
544 | return (0); |
545 | } |
546 | |