1 | /* $NetBSD: if_fxp_cardbus.c,v 1.52 2016/07/07 06:55:41 msaitoh Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1999 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Johan Danielsson. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * CardBus front-end for the Intel i82557 family of Ethernet chips. |
34 | */ |
35 | |
36 | #include <sys/cdefs.h> |
37 | __KERNEL_RCSID(0, "$NetBSD: if_fxp_cardbus.c,v 1.52 2016/07/07 06:55:41 msaitoh Exp $" ); |
38 | |
39 | #include "opt_inet.h" |
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 <machine/endian.h> |
57 | |
58 | #ifdef INET |
59 | #include <netinet/in.h> |
60 | #include <netinet/if_inarp.h> |
61 | #endif |
62 | |
63 | |
64 | #include <sys/bus.h> |
65 | #include <sys/intr.h> |
66 | |
67 | #include <dev/mii/miivar.h> |
68 | |
69 | #include <dev/ic/i82557reg.h> |
70 | #include <dev/ic/i82557var.h> |
71 | |
72 | #include <dev/pci/pcivar.h> |
73 | #include <dev/pci/pcireg.h> |
74 | #include <dev/pci/pcidevs.h> |
75 | |
76 | #include <dev/cardbus/cardbusvar.h> |
77 | #include <dev/pci/pcidevs.h> |
78 | |
79 | static int fxp_cardbus_match(device_t, cfdata_t, void *); |
80 | static void fxp_cardbus_attach(device_t, device_t, void *); |
81 | static int fxp_cardbus_detach(device_t, int); |
82 | static void fxp_cardbus_setup(struct fxp_softc *); |
83 | static int fxp_cardbus_enable(struct fxp_softc *); |
84 | static void fxp_cardbus_disable(struct fxp_softc *); |
85 | |
86 | struct fxp_cardbus_softc { |
87 | struct fxp_softc sc; |
88 | cardbus_devfunc_t ct; |
89 | pcitag_t tag; |
90 | pcireg_t base0_reg; |
91 | pcireg_t base1_reg; |
92 | }; |
93 | |
94 | CFATTACH_DECL3_NEW(fxp_cardbus, sizeof(struct fxp_cardbus_softc), |
95 | fxp_cardbus_match, fxp_cardbus_attach, fxp_cardbus_detach, fxp_activate, |
96 | NULL, null_childdetached, DVF_DETACH_SHUTDOWN); |
97 | |
98 | #ifdef CBB_DEBUG |
99 | #define DPRINTF(X) printf X |
100 | #else |
101 | #define DPRINTF(X) |
102 | #endif |
103 | |
104 | static int |
105 | fxp_cardbus_match(device_t parent, cfdata_t match, void *aux) |
106 | { |
107 | struct cardbus_attach_args *ca = aux; |
108 | |
109 | if (PCI_VENDOR(ca->ca_id) == PCI_VENDOR_INTEL && |
110 | PCI_PRODUCT(ca->ca_id) == PCI_PRODUCT_INTEL_8255X) |
111 | return (1); |
112 | |
113 | return (0); |
114 | } |
115 | |
116 | static void |
117 | fxp_cardbus_attach(device_t parent, device_t self, void *aux) |
118 | { |
119 | struct fxp_cardbus_softc *csc = device_private(self); |
120 | struct fxp_softc *sc = &csc->sc; |
121 | struct cardbus_attach_args *ca = aux; |
122 | bus_space_tag_t iot, memt; |
123 | bus_space_handle_t ioh, memh; |
124 | |
125 | bus_addr_t adr; |
126 | |
127 | sc->sc_dev = self; |
128 | csc->ct = ca->ca_ct; |
129 | csc->tag = ca->ca_tag; |
130 | |
131 | /* |
132 | * Map control/status registers. |
133 | */ |
134 | if (Cardbus_mapreg_map(csc->ct, PCI_BAR1, |
135 | PCI_MAPREG_TYPE_IO, 0, &iot, &ioh, &adr, &sc->sc_size) == 0) { |
136 | csc->base1_reg = adr | 1; |
137 | sc->sc_st = iot; |
138 | sc->sc_sh = ioh; |
139 | } else if (Cardbus_mapreg_map(csc->ct, PCI_BAR0, |
140 | PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, |
141 | 0, &memt, &memh, &adr, &sc->sc_size) == 0) { |
142 | csc->base0_reg = adr; |
143 | sc->sc_st = memt; |
144 | sc->sc_sh = memh; |
145 | } else |
146 | panic("%s: failed to allocate mem and io space" , __func__); |
147 | |
148 | if (ca->ca_cis.cis1_info[0] && ca->ca_cis.cis1_info[1]) |
149 | printf(": %s %s\n" , ca->ca_cis.cis1_info[0], |
150 | ca->ca_cis.cis1_info[1]); |
151 | else |
152 | printf("\n" ); |
153 | |
154 | sc->sc_rev = PCI_REVISION(ca->ca_class); |
155 | if (sc->sc_rev >= FXP_REV_82558_A4) |
156 | sc->sc_flags |= FXPF_FC|FXPF_EXT_TXCB; |
157 | if (sc->sc_rev >= FXP_REV_82559_A0) |
158 | sc->sc_flags |= FXPF_82559_RXCSUM; |
159 | if (sc->sc_rev >= FXP_REV_82550) { |
160 | sc->sc_flags &= ~FXPF_82559_RXCSUM; |
161 | sc->sc_flags |= FXPF_EXT_RFA; |
162 | } |
163 | |
164 | sc->sc_dmat = ca->ca_dmat; |
165 | sc->sc_enable = fxp_cardbus_enable; |
166 | sc->sc_disable = fxp_cardbus_disable; |
167 | sc->sc_enabled = 0; |
168 | |
169 | fxp_enable(sc); |
170 | fxp_attach(sc); |
171 | fxp_disable(sc); |
172 | |
173 | if (pmf_device_register(self, NULL, NULL)) |
174 | pmf_class_network_register(self, &sc->sc_ethercom.ec_if); |
175 | else |
176 | aprint_error_dev(self, "couldn't establish power handler\n" ); |
177 | } |
178 | |
179 | static void |
180 | fxp_cardbus_setup(struct fxp_softc * sc) |
181 | { |
182 | struct fxp_cardbus_softc *csc = (struct fxp_cardbus_softc *)sc; |
183 | pcireg_t command; |
184 | |
185 | pcitag_t tag = csc->tag; |
186 | |
187 | command = Cardbus_conf_read(csc->ct, tag, PCI_COMMAND_STATUS_REG); |
188 | if (csc->base0_reg) { |
189 | Cardbus_conf_write(csc->ct, tag, |
190 | PCI_BAR0, csc->base0_reg); |
191 | command |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE; |
192 | } else if (csc->base1_reg) { |
193 | Cardbus_conf_write(csc->ct, tag, |
194 | PCI_BAR1, csc->base1_reg); |
195 | command |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE; |
196 | } |
197 | |
198 | /* enable the card */ |
199 | Cardbus_conf_write(csc->ct, tag, PCI_COMMAND_STATUS_REG, command); |
200 | } |
201 | |
202 | static int |
203 | fxp_cardbus_enable(struct fxp_softc * sc) |
204 | { |
205 | struct fxp_cardbus_softc *csc = (struct fxp_cardbus_softc *)sc; |
206 | cardbus_devfunc_t ct = csc->ct; |
207 | |
208 | Cardbus_function_enable(csc->ct); |
209 | |
210 | fxp_cardbus_setup(sc); |
211 | |
212 | /* Map and establish the interrupt. */ |
213 | |
214 | sc->sc_ih = Cardbus_intr_establish(ct, IPL_NET, fxp_intr, sc); |
215 | if (NULL == sc->sc_ih) { |
216 | aprint_error_dev(sc->sc_dev, "couldn't establish interrupt\n" ); |
217 | return 1; |
218 | } |
219 | |
220 | return 0; |
221 | } |
222 | |
223 | static void |
224 | fxp_cardbus_disable(struct fxp_softc * sc) |
225 | { |
226 | struct fxp_cardbus_softc *csc = (struct fxp_cardbus_softc *)sc; |
227 | cardbus_devfunc_t ct = csc->ct; |
228 | |
229 | /* Remove interrupt handler. */ |
230 | Cardbus_intr_disestablish(ct, sc->sc_ih); |
231 | |
232 | Cardbus_function_disable(csc->ct); |
233 | } |
234 | |
235 | static int |
236 | fxp_cardbus_detach(device_t self, int flags) |
237 | { |
238 | struct fxp_cardbus_softc *csc = device_private(self); |
239 | struct fxp_softc *sc = &csc->sc; |
240 | struct cardbus_devfunc *ct = csc->ct; |
241 | int rv, reg; |
242 | |
243 | #ifdef DIAGNOSTIC |
244 | if (ct == NULL) |
245 | panic("%s: data structure lacks" , device_xname(self)); |
246 | #endif |
247 | |
248 | if ((rv = fxp_detach(sc, flags)) != 0) |
249 | return rv; |
250 | /* |
251 | * Unhook the interrupt handler. |
252 | */ |
253 | Cardbus_intr_disestablish(ct, sc->sc_ih); |
254 | |
255 | /* |
256 | * release bus space and close window |
257 | */ |
258 | if (csc->base0_reg) |
259 | reg = PCI_BAR0; |
260 | else |
261 | reg = PCI_BAR1; |
262 | Cardbus_mapreg_unmap(ct, reg, sc->sc_st, sc->sc_sh, sc->sc_size); |
263 | return 0; |
264 | } |
265 | |