Commit | Line | Data |
---|---|---|
984263bc MD |
1 | /*- |
2 | * Copyright (c) 1995, David Greenman | |
3 | * Copyright (c) 2001 Jonathan Lemon <jlemon@freebsd.org> | |
4 | * All rights reserved. | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice unmodified, this list of conditions, and the following | |
11 | * disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | |
15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
26 | * SUCH DAMAGE. | |
27 | * | |
28 | * $FreeBSD: src/sys/dev/fxp/if_fxp.c,v 1.110.2.30 2003/06/12 16:47:05 mux Exp $ | |
29 | */ | |
30 | ||
31 | /* | |
32 | * Intel EtherExpress Pro/100B PCI Fast Ethernet driver | |
33 | */ | |
34 | ||
ee332442 | 35 | #include "opt_ifpoll.h" |
2b71c8f1 | 36 | |
984263bc MD |
37 | #include <sys/param.h> |
38 | #include <sys/systm.h> | |
39 | #include <sys/mbuf.h> | |
40 | #include <sys/malloc.h> | |
984263bc | 41 | #include <sys/kernel.h> |
9db4b353 | 42 | #include <sys/interrupt.h> |
984263bc MD |
43 | #include <sys/socket.h> |
44 | #include <sys/sysctl.h> | |
37103068 | 45 | #include <sys/thread2.h> |
984263bc MD |
46 | |
47 | #include <net/if.h> | |
cb96d2fc | 48 | #include <net/ifq_var.h> |
984263bc MD |
49 | #include <net/if_dl.h> |
50 | #include <net/if_media.h> | |
51 | ||
984263bc MD |
52 | #include <net/bpf.h> |
53 | #include <sys/sockio.h> | |
54 | #include <sys/bus.h> | |
984263bc | 55 | #include <sys/rman.h> |
984263bc MD |
56 | |
57 | #include <net/ethernet.h> | |
58 | #include <net/if_arp.h> | |
ee332442 | 59 | #include <net/if_poll.h> |
984263bc MD |
60 | |
61 | #include <vm/vm.h> /* for vtophys */ | |
62 | #include <vm/pmap.h> /* for vtophys */ | |
984263bc MD |
63 | |
64 | #include <net/if_types.h> | |
1f2de5d4 | 65 | #include <net/vlan/if_vlan_var.h> |
984263bc | 66 | |
1f2de5d4 MD |
67 | #include <bus/pci/pcivar.h> |
68 | #include <bus/pci/pcireg.h> /* for PCIM_CMD_xxx */ | |
984263bc | 69 | |
1f2de5d4 MD |
70 | #include "../mii_layer/mii.h" |
71 | #include "../mii_layer/miivar.h" | |
984263bc | 72 | |
1f2de5d4 MD |
73 | #include "if_fxpreg.h" |
74 | #include "if_fxpvar.h" | |
75 | #include "rcvbundl.h" | |
984263bc | 76 | |
984263bc MD |
77 | #include "miibus_if.h" |
78 | ||
79 | /* | |
80 | * NOTE! On the Alpha, we have an alignment constraint. The | |
81 | * card DMAs the packet immediately following the RFA. However, | |
82 | * the first thing in the packet is a 14-byte Ethernet header. | |
83 | * This means that the packet is misaligned. To compensate, | |
84 | * we actually offset the RFA 2 bytes into the cluster. This | |
85 | * alignes the packet after the Ethernet header at a 32-bit | |
86 | * boundary. HOWEVER! This means that the RFA is misaligned! | |
87 | */ | |
88 | #define RFA_ALIGNMENT_FUDGE 2 | |
89 | ||
90 | /* | |
91 | * Set initial transmit threshold at 64 (512 bytes). This is | |
92 | * increased by 64 (512 bytes) at a time, to maximum of 192 | |
93 | * (1536 bytes), if an underrun occurs. | |
94 | */ | |
95 | static int tx_threshold = 64; | |
96 | ||
97 | /* | |
98 | * The configuration byte map has several undefined fields which | |
99 | * must be one or must be zero. Set up a template for these bits | |
100 | * only, (assuming a 82557 chip) leaving the actual configuration | |
101 | * to fxp_init. | |
102 | * | |
103 | * See struct fxp_cb_config for the bit definitions. | |
104 | */ | |
105 | static u_char fxp_cb_config_template[] = { | |
106 | 0x0, 0x0, /* cb_status */ | |
107 | 0x0, 0x0, /* cb_command */ | |
108 | 0x0, 0x0, 0x0, 0x0, /* link_addr */ | |
109 | 0x0, /* 0 */ | |
110 | 0x0, /* 1 */ | |
111 | 0x0, /* 2 */ | |
112 | 0x0, /* 3 */ | |
113 | 0x0, /* 4 */ | |
114 | 0x0, /* 5 */ | |
115 | 0x32, /* 6 */ | |
116 | 0x0, /* 7 */ | |
117 | 0x0, /* 8 */ | |
118 | 0x0, /* 9 */ | |
119 | 0x6, /* 10 */ | |
120 | 0x0, /* 11 */ | |
121 | 0x0, /* 12 */ | |
122 | 0x0, /* 13 */ | |
123 | 0xf2, /* 14 */ | |
124 | 0x48, /* 15 */ | |
125 | 0x0, /* 16 */ | |
126 | 0x40, /* 17 */ | |
127 | 0xf0, /* 18 */ | |
128 | 0x0, /* 19 */ | |
129 | 0x3f, /* 20 */ | |
130 | 0x5 /* 21 */ | |
131 | }; | |
132 | ||
133 | struct fxp_ident { | |
134 | u_int16_t devid; | |
77bf5450 | 135 | int16_t revid; /* -1 matches anything */ |
984263bc MD |
136 | char *name; |
137 | }; | |
138 | ||
139 | /* | |
140 | * Claim various Intel PCI device identifiers for this driver. The | |
141 | * sub-vendor and sub-device field are extensively used to identify | |
142 | * particular variants, but we don't currently differentiate between | |
143 | * them. | |
144 | */ | |
145 | static struct fxp_ident fxp_ident_table[] = { | |
77bf5450 HP |
146 | { 0x1029, -1, "Intel 82559 PCI/CardBus Pro/100" }, |
147 | { 0x1030, -1, "Intel 82559 Pro/100 Ethernet" }, | |
148 | { 0x1031, -1, "Intel 82801CAM (ICH3) Pro/100 VE Ethernet" }, | |
149 | { 0x1032, -1, "Intel 82801CAM (ICH3) Pro/100 VE Ethernet" }, | |
150 | { 0x1033, -1, "Intel 82801CAM (ICH3) Pro/100 VM Ethernet" }, | |
151 | { 0x1034, -1, "Intel 82801CAM (ICH3) Pro/100 VM Ethernet" }, | |
152 | { 0x1035, -1, "Intel 82801CAM (ICH3) Pro/100 Ethernet" }, | |
153 | { 0x1036, -1, "Intel 82801CAM (ICH3) Pro/100 Ethernet" }, | |
154 | { 0x1037, -1, "Intel 82801CAM (ICH3) Pro/100 Ethernet" }, | |
155 | { 0x1038, -1, "Intel 82801CAM (ICH3) Pro/100 VM Ethernet" }, | |
156 | { 0x1039, -1, "Intel 82801DB (ICH4) Pro/100 VE Ethernet" }, | |
157 | { 0x103A, -1, "Intel 82801DB (ICH4) Pro/100 Ethernet" }, | |
158 | { 0x103B, -1, "Intel 82801DB (ICH4) Pro/100 VM Ethernet" }, | |
159 | { 0x103C, -1, "Intel 82801DB (ICH4) Pro/100 Ethernet" }, | |
160 | { 0x103D, -1, "Intel 82801DB (ICH4) Pro/100 VE Ethernet" }, | |
161 | { 0x103E, -1, "Intel 82801DB (ICH4) Pro/100 VM Ethernet" }, | |
162 | { 0x1050, -1, "Intel 82801BA (D865) Pro/100 VE Ethernet" }, | |
f3f9ebbd | 163 | { 0x1051, -1, "Intel 82562ET (ICH5/ICH5R) Pro/100 VE Ethernet" }, |
77bf5450 | 164 | { 0x1059, -1, "Intel 82551QM Pro/100 M Mobile Connection" }, |
8cae915b | 165 | { 0x1064, -1, "Intel 82562ET/EZ/GT/GZ (ICH6/ICH6R) Pro/100 VE Ethernet" }, |
6378a54d | 166 | { 0x1065, -1, "Intel 82562ET/EZ/GT/GZ PRO/100 VE Ethernet" }, |
654dbb2a SZ |
167 | { 0x1068, -1, "Intel 82801FBM (ICH6-M) Pro/100 VE Ethernet" }, |
168 | { 0x1069, -1, "Intel 82562EM/EX/GX Pro/100 Ethernet" }, | |
149fe16d | 169 | { 0x1091, -1, "Intel 82562GX Pro/100 Ethernet" }, |
8cae915b | 170 | { 0x1092, -1, "Intel Pro/100 VE Network Connection" }, |
6378a54d SZ |
171 | { 0x1093, -1, "Intel Pro/100 VM Network Connection" }, |
172 | { 0x1094, -1, "Intel Pro/100 946GZ (ICH7) Network Connection" }, | |
77bf5450 HP |
173 | { 0x1209, -1, "Intel 82559ER Embedded 10/100 Ethernet" }, |
174 | { 0x1229, 0x01, "Intel 82557 Pro/100 Ethernet" }, | |
175 | { 0x1229, 0x02, "Intel 82557 Pro/100 Ethernet" }, | |
176 | { 0x1229, 0x03, "Intel 82557 Pro/100 Ethernet" }, | |
177 | { 0x1229, 0x04, "Intel 82558 Pro/100 Ethernet" }, | |
178 | { 0x1229, 0x05, "Intel 82558 Pro/100 Ethernet" }, | |
179 | { 0x1229, 0x06, "Intel 82559 Pro/100 Ethernet" }, | |
180 | { 0x1229, 0x07, "Intel 82559 Pro/100 Ethernet" }, | |
181 | { 0x1229, 0x08, "Intel 82559 Pro/100 Ethernet" }, | |
182 | { 0x1229, 0x09, "Intel 82559ER Pro/100 Ethernet" }, | |
183 | { 0x1229, 0x0c, "Intel 82550 Pro/100 Ethernet" }, | |
184 | { 0x1229, 0x0d, "Intel 82550 Pro/100 Ethernet" }, | |
185 | { 0x1229, 0x0e, "Intel 82550 Pro/100 Ethernet" }, | |
186 | { 0x1229, 0x0f, "Intel 82551 Pro/100 Ethernet" }, | |
187 | { 0x1229, 0x10, "Intel 82551 Pro/100 Ethernet" }, | |
188 | { 0x1229, -1, "Intel 82557/8/9 Pro/100 Ethernet" }, | |
189 | { 0x2449, -1, "Intel 82801BA/CAM (ICH2/3) Pro/100 Ethernet" }, | |
8cae915b | 190 | { 0x27dc, -1, "Intel 82801GB (ICH7) 10/100 Ethernet" }, |
77bf5450 | 191 | { 0, -1, NULL }, |
984263bc MD |
192 | }; |
193 | ||
194 | static int fxp_probe(device_t dev); | |
195 | static int fxp_attach(device_t dev); | |
196 | static int fxp_detach(device_t dev); | |
197 | static int fxp_shutdown(device_t dev); | |
198 | static int fxp_suspend(device_t dev); | |
199 | static int fxp_resume(device_t dev); | |
200 | ||
201 | static void fxp_intr(void *xsc); | |
202 | static void fxp_intr_body(struct fxp_softc *sc, | |
203 | u_int8_t statack, int count); | |
204 | ||
205 | static void fxp_init(void *xsc); | |
206 | static void fxp_tick(void *xsc); | |
207 | static void fxp_powerstate_d0(device_t dev); | |
f0a26983 | 208 | static void fxp_start(struct ifnet *ifp, struct ifaltq_subque *); |
984263bc | 209 | static void fxp_stop(struct fxp_softc *sc); |
c81df1a6 | 210 | static void fxp_release(device_t dev); |
984263bc | 211 | static int fxp_ioctl(struct ifnet *ifp, u_long command, |
bd4539cc | 212 | caddr_t data, struct ucred *); |
984263bc MD |
213 | static void fxp_watchdog(struct ifnet *ifp); |
214 | static int fxp_add_rfabuf(struct fxp_softc *sc, struct mbuf *oldm); | |
215 | static int fxp_mc_addrs(struct fxp_softc *sc); | |
216 | static void fxp_mc_setup(struct fxp_softc *sc); | |
217 | static u_int16_t fxp_eeprom_getword(struct fxp_softc *sc, int offset, | |
218 | int autosize); | |
219 | static void fxp_eeprom_putword(struct fxp_softc *sc, int offset, | |
220 | u_int16_t data); | |
221 | static void fxp_autosize_eeprom(struct fxp_softc *sc); | |
222 | static void fxp_read_eeprom(struct fxp_softc *sc, u_short *data, | |
223 | int offset, int words); | |
224 | static void fxp_write_eeprom(struct fxp_softc *sc, u_short *data, | |
225 | int offset, int words); | |
226 | static int fxp_ifmedia_upd(struct ifnet *ifp); | |
227 | static void fxp_ifmedia_sts(struct ifnet *ifp, | |
228 | struct ifmediareq *ifmr); | |
229 | static int fxp_serial_ifmedia_upd(struct ifnet *ifp); | |
230 | static void fxp_serial_ifmedia_sts(struct ifnet *ifp, | |
231 | struct ifmediareq *ifmr); | |
10d1b534 | 232 | static int fxp_miibus_readreg(device_t dev, int phy, int reg); |
984263bc MD |
233 | static void fxp_miibus_writereg(device_t dev, int phy, int reg, |
234 | int value); | |
235 | static void fxp_load_ucode(struct fxp_softc *sc); | |
984263bc MD |
236 | static int sysctl_hw_fxp_bundle_max(SYSCTL_HANDLER_ARGS); |
237 | static int sysctl_hw_fxp_int_delay(SYSCTL_HANDLER_ARGS); | |
ee332442 SZ |
238 | #ifdef IFPOLL_ENABLE |
239 | static void fxp_npoll(struct ifnet *, struct ifpoll_info *); | |
240 | static void fxp_npoll_compat(struct ifnet *, void *, int); | |
9c095379 MD |
241 | #endif |
242 | ||
de1795b2 | 243 | static void fxp_lwcopy(volatile u_int32_t *src, |
984263bc | 244 | volatile u_int32_t *dst); |
de1795b2 JS |
245 | static void fxp_scb_wait(struct fxp_softc *sc); |
246 | static void fxp_scb_cmd(struct fxp_softc *sc, int cmd); | |
247 | static void fxp_dma_wait(volatile u_int16_t *status, | |
984263bc MD |
248 | struct fxp_softc *sc); |
249 | ||
250 | static device_method_t fxp_methods[] = { | |
251 | /* Device interface */ | |
252 | DEVMETHOD(device_probe, fxp_probe), | |
253 | DEVMETHOD(device_attach, fxp_attach), | |
254 | DEVMETHOD(device_detach, fxp_detach), | |
255 | DEVMETHOD(device_shutdown, fxp_shutdown), | |
256 | DEVMETHOD(device_suspend, fxp_suspend), | |
257 | DEVMETHOD(device_resume, fxp_resume), | |
258 | ||
259 | /* MII interface */ | |
260 | DEVMETHOD(miibus_readreg, fxp_miibus_readreg), | |
261 | DEVMETHOD(miibus_writereg, fxp_miibus_writereg), | |
262 | ||
d3c9c58e | 263 | DEVMETHOD_END |
984263bc MD |
264 | }; |
265 | ||
266 | static driver_t fxp_driver = { | |
267 | "fxp", | |
268 | fxp_methods, | |
269 | sizeof(struct fxp_softc), | |
270 | }; | |
271 | ||
272 | static devclass_t fxp_devclass; | |
273 | ||
32832096 MD |
274 | DECLARE_DUMMY_MODULE(if_fxp); |
275 | MODULE_DEPEND(if_fxp, miibus, 1, 1, 1); | |
aa2b9d05 SW |
276 | DRIVER_MODULE(if_fxp, pci, fxp_driver, fxp_devclass, NULL, NULL); |
277 | DRIVER_MODULE(if_fxp, cardbus, fxp_driver, fxp_devclass, NULL, NULL); | |
278 | DRIVER_MODULE(miibus, fxp, miibus_driver, miibus_devclass, NULL, NULL); | |
984263bc MD |
279 | |
280 | static int fxp_rnr; | |
281 | SYSCTL_INT(_hw, OID_AUTO, fxp_rnr, CTLFLAG_RW, &fxp_rnr, 0, "fxp rnr events"); | |
282 | ||
283 | /* | |
de1795b2 | 284 | * Copy a 16-bit aligned 32-bit quantity. |
984263bc | 285 | */ |
de1795b2 | 286 | static void |
984263bc MD |
287 | fxp_lwcopy(volatile u_int32_t *src, volatile u_int32_t *dst) |
288 | { | |
984263bc MD |
289 | volatile u_int16_t *a = (volatile u_int16_t *)src; |
290 | volatile u_int16_t *b = (volatile u_int16_t *)dst; | |
291 | ||
292 | b[0] = a[0]; | |
293 | b[1] = a[1]; | |
984263bc MD |
294 | } |
295 | ||
296 | /* | |
297 | * Wait for the previous command to be accepted (but not necessarily | |
298 | * completed). | |
299 | */ | |
de1795b2 | 300 | static void |
984263bc MD |
301 | fxp_scb_wait(struct fxp_softc *sc) |
302 | { | |
303 | int i = 10000; | |
304 | ||
305 | while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i) | |
306 | DELAY(2); | |
c81df1a6 JS |
307 | if (i == 0) { |
308 | if_printf(&sc->arpcom.ac_if, | |
309 | "SCB timeout: 0x%x 0x%x 0x%x 0x%x\n", | |
984263bc MD |
310 | CSR_READ_1(sc, FXP_CSR_SCB_COMMAND), |
311 | CSR_READ_1(sc, FXP_CSR_SCB_STATACK), | |
312 | CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS), | |
313 | CSR_READ_2(sc, FXP_CSR_FLOWCONTROL)); | |
c81df1a6 | 314 | } |
984263bc MD |
315 | } |
316 | ||
de1795b2 | 317 | static void |
984263bc MD |
318 | fxp_scb_cmd(struct fxp_softc *sc, int cmd) |
319 | { | |
320 | ||
321 | if (cmd == FXP_SCB_COMMAND_CU_RESUME && sc->cu_resume_bug) { | |
322 | CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_CB_COMMAND_NOP); | |
323 | fxp_scb_wait(sc); | |
324 | } | |
325 | CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, cmd); | |
326 | } | |
327 | ||
de1795b2 | 328 | static void |
984263bc MD |
329 | fxp_dma_wait(volatile u_int16_t *status, struct fxp_softc *sc) |
330 | { | |
331 | int i = 10000; | |
332 | ||
333 | while (!(*status & FXP_CB_STATUS_C) && --i) | |
334 | DELAY(2); | |
335 | if (i == 0) | |
c81df1a6 | 336 | if_printf(&sc->arpcom.ac_if, "DMA timeout\n"); |
984263bc MD |
337 | } |
338 | ||
339 | /* | |
340 | * Return identification string if this is device is ours. | |
341 | */ | |
342 | static int | |
343 | fxp_probe(device_t dev) | |
344 | { | |
345 | u_int16_t devid; | |
77bf5450 | 346 | u_int8_t revid; |
984263bc MD |
347 | struct fxp_ident *ident; |
348 | ||
349 | if (pci_get_vendor(dev) == FXP_VENDORID_INTEL) { | |
350 | devid = pci_get_device(dev); | |
77bf5450 | 351 | revid = pci_get_revid(dev); |
984263bc | 352 | for (ident = fxp_ident_table; ident->name != NULL; ident++) { |
77bf5450 HP |
353 | if (ident->devid == devid && |
354 | (ident->revid == revid || ident->revid == -1)) { | |
984263bc MD |
355 | device_set_desc(dev, ident->name); |
356 | return (0); | |
357 | } | |
358 | } | |
359 | } | |
360 | return (ENXIO); | |
361 | } | |
362 | ||
363 | static void | |
364 | fxp_powerstate_d0(device_t dev) | |
365 | { | |
984263bc MD |
366 | u_int32_t iobase, membase, irq; |
367 | ||
368 | if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { | |
369 | /* Save important PCI config data. */ | |
370 | iobase = pci_read_config(dev, FXP_PCI_IOBA, 4); | |
371 | membase = pci_read_config(dev, FXP_PCI_MMBA, 4); | |
372 | irq = pci_read_config(dev, PCIR_INTLINE, 4); | |
373 | ||
374 | /* Reset the power state. */ | |
375 | device_printf(dev, "chip is in D%d power mode " | |
376 | "-- setting to D0\n", pci_get_powerstate(dev)); | |
377 | ||
378 | pci_set_powerstate(dev, PCI_POWERSTATE_D0); | |
379 | ||
380 | /* Restore PCI config data. */ | |
381 | pci_write_config(dev, FXP_PCI_IOBA, iobase, 4); | |
382 | pci_write_config(dev, FXP_PCI_MMBA, membase, 4); | |
383 | pci_write_config(dev, PCIR_INTLINE, irq, 4); | |
384 | } | |
984263bc MD |
385 | } |
386 | ||
387 | static int | |
388 | fxp_attach(device_t dev) | |
389 | { | |
390 | int error = 0; | |
391 | struct fxp_softc *sc = device_get_softc(dev); | |
392 | struct ifnet *ifp; | |
26595b18 SW |
393 | struct sysctl_ctx_list *ctx; |
394 | struct sysctl_oid *tree; | |
984263bc MD |
395 | u_int32_t val; |
396 | u_int16_t data; | |
397 | int i, rid, m1, m2, prefer_iomap; | |
984263bc | 398 | |
a1f4b801 | 399 | callout_init(&sc->fxp_stat_timer); |
984263bc | 400 | |
984263bc MD |
401 | /* |
402 | * Enable bus mastering. Enable memory space too, in case | |
403 | * BIOS/Prom forgot about it. | |
404 | */ | |
af340cf5 JS |
405 | pci_enable_busmaster(dev); |
406 | pci_enable_io(dev, SYS_RES_MEMORY); | |
984263bc MD |
407 | val = pci_read_config(dev, PCIR_COMMAND, 2); |
408 | ||
409 | fxp_powerstate_d0(dev); | |
410 | ||
411 | /* | |
412 | * Figure out which we should try first - memory mapping or i/o mapping? | |
413 | * We default to memory mapping. Then we accept an override from the | |
414 | * command line. Then we check to see which one is enabled. | |
415 | */ | |
416 | m1 = PCIM_CMD_MEMEN; | |
417 | m2 = PCIM_CMD_PORTEN; | |
418 | prefer_iomap = 0; | |
419 | if (resource_int_value(device_get_name(dev), device_get_unit(dev), | |
420 | "prefer_iomap", &prefer_iomap) == 0 && prefer_iomap != 0) { | |
421 | m1 = PCIM_CMD_PORTEN; | |
422 | m2 = PCIM_CMD_MEMEN; | |
423 | } | |
424 | ||
425 | if (val & m1) { | |
426 | sc->rtp = | |
427 | (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; | |
428 | sc->rgd = (m1 == PCIM_CMD_MEMEN)? FXP_PCI_MMBA : FXP_PCI_IOBA; | |
4e6d744d JS |
429 | sc->mem = bus_alloc_resource_any(dev, sc->rtp, &sc->rgd, |
430 | RF_ACTIVE); | |
984263bc MD |
431 | } |
432 | if (sc->mem == NULL && (val & m2)) { | |
433 | sc->rtp = | |
434 | (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; | |
435 | sc->rgd = (m2 == PCIM_CMD_MEMEN)? FXP_PCI_MMBA : FXP_PCI_IOBA; | |
4e6d744d JS |
436 | sc->mem = bus_alloc_resource_any(dev, sc->rtp, &sc->rgd, |
437 | RF_ACTIVE); | |
984263bc MD |
438 | } |
439 | ||
440 | if (!sc->mem) { | |
441 | device_printf(dev, "could not map device registers\n"); | |
442 | error = ENXIO; | |
443 | goto fail; | |
444 | } | |
445 | if (bootverbose) { | |
446 | device_printf(dev, "using %s space register mapping\n", | |
447 | sc->rtp == SYS_RES_MEMORY? "memory" : "I/O"); | |
448 | } | |
449 | ||
450 | sc->sc_st = rman_get_bustag(sc->mem); | |
451 | sc->sc_sh = rman_get_bushandle(sc->mem); | |
452 | ||
453 | /* | |
454 | * Allocate our interrupt. | |
455 | */ | |
456 | rid = 0; | |
4e6d744d JS |
457 | sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, |
458 | RF_SHAREABLE | RF_ACTIVE); | |
984263bc MD |
459 | if (sc->irq == NULL) { |
460 | device_printf(dev, "could not map interrupt\n"); | |
461 | error = ENXIO; | |
462 | goto fail; | |
463 | } | |
464 | ||
984263bc MD |
465 | /* |
466 | * Reset to a stable state. | |
467 | */ | |
468 | CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET); | |
469 | DELAY(10); | |
470 | ||
77652cad | 471 | sc->cbl_base = kmalloc(sizeof(struct fxp_cb_tx) * FXP_NTXCB, |
c5541aee | 472 | M_DEVBUF, M_WAITOK | M_ZERO); |
984263bc | 473 | |
efda3bd0 | 474 | sc->fxp_stats = kmalloc(sizeof(struct fxp_stats), M_DEVBUF, |
c5541aee | 475 | M_WAITOK | M_ZERO); |
984263bc | 476 | |
efda3bd0 | 477 | sc->mcsp = kmalloc(sizeof(struct fxp_cb_mcs), M_DEVBUF, M_WAITOK); |
984263bc MD |
478 | |
479 | /* | |
480 | * Pre-allocate our receive buffers. | |
481 | */ | |
482 | for (i = 0; i < FXP_NRFABUFS; i++) { | |
483 | if (fxp_add_rfabuf(sc, NULL) != 0) { | |
484 | goto failmem; | |
485 | } | |
486 | } | |
487 | ||
488 | /* | |
489 | * Find out how large of an SEEPROM we have. | |
490 | */ | |
491 | fxp_autosize_eeprom(sc); | |
492 | ||
493 | /* | |
494 | * Determine whether we must use the 503 serial interface. | |
495 | */ | |
496 | fxp_read_eeprom(sc, &data, 6, 1); | |
497 | if ((data & FXP_PHY_DEVICE_MASK) != 0 && | |
498 | (data & FXP_PHY_SERIAL_ONLY)) | |
499 | sc->flags |= FXP_FLAG_SERIAL_MEDIA; | |
500 | ||
501 | /* | |
502 | * Create the sysctl tree | |
503 | */ | |
26595b18 SW |
504 | ctx = device_get_sysctl_ctx(dev); |
505 | tree = device_get_sysctl_tree(dev); | |
506 | SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), | |
984263bc MD |
507 | OID_AUTO, "int_delay", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON, |
508 | &sc->tunable_int_delay, 0, &sysctl_hw_fxp_int_delay, "I", | |
509 | "FXP driver receive interrupt microcode bundling delay"); | |
26595b18 | 510 | SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), |
984263bc MD |
511 | OID_AUTO, "bundle_max", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON, |
512 | &sc->tunable_bundle_max, 0, &sysctl_hw_fxp_bundle_max, "I", | |
513 | "FXP driver receive interrupt microcode bundle size limit"); | |
514 | ||
515 | /* | |
516 | * Pull in device tunables. | |
517 | */ | |
518 | sc->tunable_int_delay = TUNABLE_INT_DELAY; | |
519 | sc->tunable_bundle_max = TUNABLE_BUNDLE_MAX; | |
7b9f668c | 520 | resource_int_value(device_get_name(dev), device_get_unit(dev), |
984263bc | 521 | "int_delay", &sc->tunable_int_delay); |
7b9f668c | 522 | resource_int_value(device_get_name(dev), device_get_unit(dev), |
984263bc MD |
523 | "bundle_max", &sc->tunable_bundle_max); |
524 | ||
525 | /* | |
526 | * Find out the chip revision; lump all 82557 revs together. | |
527 | */ | |
528 | fxp_read_eeprom(sc, &data, 5, 1); | |
529 | if ((data >> 8) == 1) | |
530 | sc->revision = FXP_REV_82557; | |
531 | else | |
532 | sc->revision = pci_get_revid(dev); | |
533 | ||
534 | /* | |
535 | * Enable workarounds for certain chip revision deficiencies. | |
536 | * | |
537 | * Systems based on the ICH2/ICH2-M chip from Intel, and possibly | |
538 | * some systems based a normal 82559 design, have a defect where | |
539 | * the chip can cause a PCI protocol violation if it receives | |
540 | * a CU_RESUME command when it is entering the IDLE state. The | |
541 | * workaround is to disable Dynamic Standby Mode, so the chip never | |
542 | * deasserts CLKRUN#, and always remains in an active state. | |
543 | * | |
544 | * See Intel 82801BA/82801BAM Specification Update, Errata #30. | |
545 | */ | |
546 | i = pci_get_device(dev); | |
547 | if (i == 0x2449 || (i > 0x1030 && i < 0x1039) || | |
548 | sc->revision >= FXP_REV_82559_A0) { | |
549 | fxp_read_eeprom(sc, &data, 10, 1); | |
550 | if (data & 0x02) { /* STB enable */ | |
551 | u_int16_t cksum; | |
552 | int i; | |
553 | ||
554 | device_printf(dev, | |
555 | "Disabling dynamic standby mode in EEPROM\n"); | |
556 | data &= ~0x02; | |
557 | fxp_write_eeprom(sc, &data, 10, 1); | |
558 | device_printf(dev, "New EEPROM ID: 0x%x\n", data); | |
559 | cksum = 0; | |
560 | for (i = 0; i < (1 << sc->eeprom_size) - 1; i++) { | |
561 | fxp_read_eeprom(sc, &data, i, 1); | |
562 | cksum += data; | |
563 | } | |
564 | i = (1 << sc->eeprom_size) - 1; | |
565 | cksum = 0xBABA - cksum; | |
566 | fxp_read_eeprom(sc, &data, i, 1); | |
567 | fxp_write_eeprom(sc, &cksum, i, 1); | |
568 | device_printf(dev, | |
569 | "EEPROM checksum @ 0x%x: 0x%x -> 0x%x\n", | |
570 | i, data, cksum); | |
571 | #if 1 | |
572 | /* | |
573 | * If the user elects to continue, try the software | |
574 | * workaround, as it is better than nothing. | |
575 | */ | |
576 | sc->flags |= FXP_FLAG_CU_RESUME_BUG; | |
577 | #endif | |
578 | } | |
579 | } | |
580 | ||
581 | /* | |
582 | * If we are not a 82557 chip, we can enable extended features. | |
583 | */ | |
584 | if (sc->revision != FXP_REV_82557) { | |
585 | /* | |
586 | * If MWI is enabled in the PCI configuration, and there | |
587 | * is a valid cacheline size (8 or 16 dwords), then tell | |
588 | * the board to turn on MWI. | |
589 | */ | |
590 | if (val & PCIM_CMD_MWRICEN && | |
591 | pci_read_config(dev, PCIR_CACHELNSZ, 1) != 0) | |
592 | sc->flags |= FXP_FLAG_MWI_ENABLE; | |
593 | ||
594 | /* turn on the extended TxCB feature */ | |
595 | sc->flags |= FXP_FLAG_EXT_TXCB; | |
596 | ||
597 | /* enable reception of long frames for VLAN */ | |
598 | sc->flags |= FXP_FLAG_LONG_PKT_EN; | |
599 | } | |
600 | ||
601 | /* | |
602 | * Read MAC address. | |
603 | */ | |
604 | fxp_read_eeprom(sc, (u_int16_t *)sc->arpcom.ac_enaddr, 0, 3); | |
267caeeb | 605 | if (sc->flags & FXP_FLAG_SERIAL_MEDIA) |
c81df1a6 | 606 | device_printf(dev, "10Mbps\n"); |
984263bc MD |
607 | if (bootverbose) { |
608 | device_printf(dev, "PCI IDs: %04x %04x %04x %04x %04x\n", | |
609 | pci_get_vendor(dev), pci_get_device(dev), | |
610 | pci_get_subvendor(dev), pci_get_subdevice(dev), | |
611 | pci_get_revid(dev)); | |
612 | fxp_read_eeprom(sc, &data, 10, 1); | |
613 | device_printf(dev, "Dynamic Standby mode is %s\n", | |
614 | data & 0x02 ? "enabled" : "disabled"); | |
615 | } | |
616 | ||
617 | /* | |
618 | * If this is only a 10Mbps device, then there is no MII, and | |
619 | * the PHY will use a serial interface instead. | |
620 | * | |
621 | * The Seeq 80c24 AutoDUPLEX(tm) Ethernet Interface Adapter | |
622 | * doesn't have a programming interface of any sort. The | |
623 | * media is sensed automatically based on how the link partner | |
624 | * is configured. This is, in essence, manual configuration. | |
625 | */ | |
626 | if (sc->flags & FXP_FLAG_SERIAL_MEDIA) { | |
627 | ifmedia_init(&sc->sc_media, 0, fxp_serial_ifmedia_upd, | |
628 | fxp_serial_ifmedia_sts); | |
629 | ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL); | |
630 | ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL); | |
631 | } else { | |
632 | if (mii_phy_probe(dev, &sc->miibus, fxp_ifmedia_upd, | |
633 | fxp_ifmedia_sts)) { | |
634 | device_printf(dev, "MII without any PHY!\n"); | |
635 | error = ENXIO; | |
636 | goto fail; | |
637 | } | |
638 | } | |
639 | ||
640 | ifp = &sc->arpcom.ac_if; | |
af340cf5 | 641 | if_initname(ifp, device_get_name(dev), device_get_unit(dev)); |
984263bc MD |
642 | ifp->if_baudrate = 100000000; |
643 | ifp->if_init = fxp_init; | |
644 | ifp->if_softc = sc; | |
645 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | |
646 | ifp->if_ioctl = fxp_ioctl; | |
647 | ifp->if_start = fxp_start; | |
ee332442 SZ |
648 | #ifdef IFPOLL_ENABLE |
649 | ifp->if_npoll = fxp_npoll; | |
9c095379 | 650 | #endif |
984263bc MD |
651 | ifp->if_watchdog = fxp_watchdog; |
652 | ||
653 | /* | |
654 | * Attach the interface. | |
655 | */ | |
78195a76 | 656 | ether_ifattach(ifp, sc->arpcom.ac_enaddr, NULL); |
984263bc | 657 | |
ee332442 | 658 | #ifdef IFPOLL_ENABLE |
26595b18 SW |
659 | ifpoll_compat_setup(&sc->fxp_npoll, ctx, (struct sysctl_oid *)tree, |
660 | device_get_unit(dev), ifp->if_serializer); | |
ee332442 SZ |
661 | #endif |
662 | ||
984263bc MD |
663 | /* |
664 | * Tell the upper layer(s) we support long frames. | |
665 | */ | |
666 | ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); | |
667 | ||
668 | /* | |
669 | * Let the system queue as many packets as we have available | |
670 | * TX descriptors. | |
671 | */ | |
883c716a | 672 | ifq_set_maxlen(&ifp->if_snd, FXP_USABLE_TXCB); |
4dbb2aca | 673 | ifq_set_ready(&ifp->if_snd); |
984263bc | 674 | |
4c77af2d SZ |
675 | ifq_set_cpuid(&ifp->if_snd, rman_get_cpuid(sc->irq)); |
676 | ||
95893fe4 | 677 | error = bus_setup_intr(dev, sc->irq, INTR_MPSAFE, |
78195a76 MD |
678 | fxp_intr, sc, &sc->ih, |
679 | ifp->if_serializer); | |
37103068 | 680 | if (error) { |
a3e0c8f8 | 681 | ether_ifdetach(ifp); |
37103068 JS |
682 | if (sc->flags & FXP_FLAG_SERIAL_MEDIA) |
683 | ifmedia_removeall(&sc->sc_media); | |
684 | device_printf(dev, "could not setup irq\n"); | |
685 | goto fail; | |
686 | } | |
687 | ||
984263bc MD |
688 | return (0); |
689 | ||
690 | failmem: | |
691 | device_printf(dev, "Failed to malloc memory\n"); | |
692 | error = ENOMEM; | |
693 | fail: | |
c81df1a6 | 694 | fxp_release(dev); |
984263bc MD |
695 | return (error); |
696 | } | |
697 | ||
698 | /* | |
699 | * release all resources | |
700 | */ | |
701 | static void | |
c81df1a6 | 702 | fxp_release(device_t dev) |
984263bc | 703 | { |
37103068 | 704 | struct fxp_softc *sc = device_get_softc(dev); |
984263bc | 705 | |
984263bc | 706 | if (sc->miibus) |
c81df1a6 | 707 | device_delete_child(dev, sc->miibus); |
37103068 | 708 | bus_generic_detach(dev); |
984263bc MD |
709 | |
710 | if (sc->cbl_base) | |
efda3bd0 | 711 | kfree(sc->cbl_base, M_DEVBUF); |
984263bc | 712 | if (sc->fxp_stats) |
efda3bd0 | 713 | kfree(sc->fxp_stats, M_DEVBUF); |
984263bc | 714 | if (sc->mcsp) |
efda3bd0 | 715 | kfree(sc->mcsp, M_DEVBUF); |
984263bc MD |
716 | if (sc->rfa_headm) |
717 | m_freem(sc->rfa_headm); | |
718 | ||
984263bc | 719 | if (sc->irq) |
c81df1a6 | 720 | bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); |
984263bc | 721 | if (sc->mem) |
c81df1a6 | 722 | bus_release_resource(dev, sc->rtp, sc->rgd, sc->mem); |
984263bc MD |
723 | } |
724 | ||
725 | /* | |
726 | * Detach interface. | |
727 | */ | |
728 | static int | |
729 | fxp_detach(device_t dev) | |
730 | { | |
731 | struct fxp_softc *sc = device_get_softc(dev); | |
984263bc | 732 | |
78195a76 | 733 | lwkt_serialize_enter(sc->arpcom.ac_if.if_serializer); |
984263bc MD |
734 | |
735 | /* | |
736 | * Stop DMA and drop transmit queue. | |
737 | */ | |
738 | fxp_stop(sc); | |
739 | ||
71fdcbe1 SZ |
740 | /* |
741 | * Disable interrupts. | |
742 | * | |
743 | * NOTE: This should be done after fxp_stop(), because software | |
744 | * resetting in fxp_stop() may leave interrupts turned on. | |
745 | */ | |
746 | CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, FXP_SCB_INTR_DISABLE); | |
747 | ||
984263bc MD |
748 | /* |
749 | * Free all media structures. | |
750 | */ | |
37103068 JS |
751 | if (sc->flags & FXP_FLAG_SERIAL_MEDIA) |
752 | ifmedia_removeall(&sc->sc_media); | |
984263bc | 753 | |
37103068 JS |
754 | if (sc->ih) |
755 | bus_teardown_intr(dev, sc->irq, sc->ih); | |
756 | ||
cdf89432 SZ |
757 | lwkt_serialize_exit(sc->arpcom.ac_if.if_serializer); |
758 | ||
759 | /* | |
760 | * Close down routes etc. | |
761 | */ | |
762 | ether_ifdetach(&sc->arpcom.ac_if); | |
763 | ||
984263bc | 764 | /* Release our allocated resources. */ |
c81df1a6 | 765 | fxp_release(dev); |
984263bc MD |
766 | |
767 | return (0); | |
768 | } | |
769 | ||
770 | /* | |
771 | * Device shutdown routine. Called at system shutdown after sync. The | |
772 | * main purpose of this routine is to shut off receiver DMA so that | |
773 | * kernel memory doesn't get clobbered during warmboot. | |
774 | */ | |
775 | static int | |
776 | fxp_shutdown(device_t dev) | |
777 | { | |
334b9734 SZ |
778 | struct fxp_softc *sc = device_get_softc(dev); |
779 | struct ifnet *ifp = &sc->arpcom.ac_if; | |
780 | ||
781 | lwkt_serialize_enter(ifp->if_serializer); | |
984263bc MD |
782 | /* |
783 | * Make sure that DMA is disabled prior to reboot. Not doing | |
784 | * do could allow DMA to corrupt kernel memory during the | |
785 | * reboot before the driver initializes. | |
786 | */ | |
334b9734 SZ |
787 | fxp_stop(sc); |
788 | lwkt_serialize_exit(ifp->if_serializer); | |
984263bc MD |
789 | return (0); |
790 | } | |
791 | ||
792 | /* | |
793 | * Device suspend routine. Stop the interface and save some PCI | |
794 | * settings in case the BIOS doesn't restore them properly on | |
795 | * resume. | |
796 | */ | |
797 | static int | |
798 | fxp_suspend(device_t dev) | |
799 | { | |
800 | struct fxp_softc *sc = device_get_softc(dev); | |
37103068 | 801 | int i; |
984263bc | 802 | |
78195a76 | 803 | lwkt_serialize_enter(sc->arpcom.ac_if.if_serializer); |
984263bc MD |
804 | |
805 | fxp_stop(sc); | |
806 | ||
807 | for (i = 0; i < 5; i++) | |
3dc849fa | 808 | sc->saved_maps[i] = pci_read_config(dev, PCIR_BAR(i), 4); |
984263bc MD |
809 | sc->saved_biosaddr = pci_read_config(dev, PCIR_BIOS, 4); |
810 | sc->saved_intline = pci_read_config(dev, PCIR_INTLINE, 1); | |
811 | sc->saved_cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1); | |
812 | sc->saved_lattimer = pci_read_config(dev, PCIR_LATTIMER, 1); | |
813 | ||
814 | sc->suspended = 1; | |
815 | ||
78195a76 | 816 | lwkt_serialize_exit(sc->arpcom.ac_if.if_serializer); |
984263bc MD |
817 | return (0); |
818 | } | |
819 | ||
820 | /* | |
821 | * Device resume routine. Restore some PCI settings in case the BIOS | |
822 | * doesn't, re-enable busmastering, and restart the interface if | |
823 | * appropriate. | |
824 | */ | |
825 | static int | |
826 | fxp_resume(device_t dev) | |
827 | { | |
828 | struct fxp_softc *sc = device_get_softc(dev); | |
3dc849fa | 829 | struct ifnet *ifp = &sc->arpcom.ac_if; |
37103068 | 830 | int i; |
984263bc | 831 | |
78195a76 | 832 | lwkt_serialize_enter(sc->arpcom.ac_if.if_serializer); |
984263bc MD |
833 | |
834 | fxp_powerstate_d0(dev); | |
835 | ||
836 | /* better way to do this? */ | |
837 | for (i = 0; i < 5; i++) | |
3dc849fa | 838 | pci_write_config(dev, PCIR_BAR(i), sc->saved_maps[i], 4); |
984263bc MD |
839 | pci_write_config(dev, PCIR_BIOS, sc->saved_biosaddr, 4); |
840 | pci_write_config(dev, PCIR_INTLINE, sc->saved_intline, 1); | |
841 | pci_write_config(dev, PCIR_CACHELNSZ, sc->saved_cachelnsz, 1); | |
842 | pci_write_config(dev, PCIR_LATTIMER, sc->saved_lattimer, 1); | |
843 | ||
af340cf5 JS |
844 | /* reenable busmastering and memory space */ |
845 | pci_enable_busmaster(dev); | |
846 | pci_enable_io(dev, SYS_RES_MEMORY); | |
984263bc MD |
847 | |
848 | CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET); | |
849 | DELAY(10); | |
850 | ||
851 | /* reinitialize interface if necessary */ | |
852 | if (ifp->if_flags & IFF_UP) | |
853 | fxp_init(sc); | |
854 | ||
855 | sc->suspended = 0; | |
856 | ||
78195a76 | 857 | lwkt_serialize_exit(sc->arpcom.ac_if.if_serializer); |
984263bc MD |
858 | return (0); |
859 | } | |
860 | ||
861 | static void | |
862 | fxp_eeprom_shiftin(struct fxp_softc *sc, int data, int length) | |
863 | { | |
864 | u_int16_t reg; | |
865 | int x; | |
866 | ||
867 | /* | |
868 | * Shift in data. | |
869 | */ | |
870 | for (x = 1 << (length - 1); x; x >>= 1) { | |
871 | if (data & x) | |
872 | reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI; | |
873 | else | |
874 | reg = FXP_EEPROM_EECS; | |
875 | CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); | |
876 | DELAY(1); | |
877 | CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg | FXP_EEPROM_EESK); | |
878 | DELAY(1); | |
879 | CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); | |
880 | DELAY(1); | |
881 | } | |
882 | } | |
883 | ||
884 | /* | |
885 | * Read from the serial EEPROM. Basically, you manually shift in | |
886 | * the read opcode (one bit at a time) and then shift in the address, | |
887 | * and then you shift out the data (all of this one bit at a time). | |
888 | * The word size is 16 bits, so you have to provide the address for | |
889 | * every 16 bits of data. | |
890 | */ | |
891 | static u_int16_t | |
892 | fxp_eeprom_getword(struct fxp_softc *sc, int offset, int autosize) | |
893 | { | |
894 | u_int16_t reg, data; | |
895 | int x; | |
896 | ||
897 | CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS); | |
898 | /* | |
899 | * Shift in read opcode. | |
900 | */ | |
901 | fxp_eeprom_shiftin(sc, FXP_EEPROM_OPC_READ, 3); | |
902 | /* | |
903 | * Shift in address. | |
904 | */ | |
905 | data = 0; | |
906 | for (x = 1 << (sc->eeprom_size - 1); x; x >>= 1) { | |
907 | if (offset & x) | |
908 | reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI; | |
909 | else | |
910 | reg = FXP_EEPROM_EECS; | |
911 | CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); | |
912 | DELAY(1); | |
913 | CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg | FXP_EEPROM_EESK); | |
914 | DELAY(1); | |
915 | CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); | |
916 | DELAY(1); | |
917 | reg = CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) & FXP_EEPROM_EEDO; | |
918 | data++; | |
919 | if (autosize && reg == 0) { | |
920 | sc->eeprom_size = data; | |
921 | break; | |
922 | } | |
923 | } | |
924 | /* | |
925 | * Shift out data. | |
926 | */ | |
927 | data = 0; | |
928 | reg = FXP_EEPROM_EECS; | |
929 | for (x = 1 << 15; x; x >>= 1) { | |
930 | CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg | FXP_EEPROM_EESK); | |
931 | DELAY(1); | |
932 | if (CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) & FXP_EEPROM_EEDO) | |
933 | data |= x; | |
934 | CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); | |
935 | DELAY(1); | |
936 | } | |
937 | CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0); | |
938 | DELAY(1); | |
939 | ||
940 | return (data); | |
941 | } | |
942 | ||
943 | static void | |
944 | fxp_eeprom_putword(struct fxp_softc *sc, int offset, u_int16_t data) | |
945 | { | |
946 | int i; | |
947 | ||
948 | /* | |
949 | * Erase/write enable. | |
950 | */ | |
951 | CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS); | |
952 | fxp_eeprom_shiftin(sc, 0x4, 3); | |
953 | fxp_eeprom_shiftin(sc, 0x03 << (sc->eeprom_size - 2), sc->eeprom_size); | |
954 | CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0); | |
955 | DELAY(1); | |
956 | /* | |
957 | * Shift in write opcode, address, data. | |
958 | */ | |
959 | CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS); | |
960 | fxp_eeprom_shiftin(sc, FXP_EEPROM_OPC_WRITE, 3); | |
961 | fxp_eeprom_shiftin(sc, offset, sc->eeprom_size); | |
962 | fxp_eeprom_shiftin(sc, data, 16); | |
963 | CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0); | |
964 | DELAY(1); | |
965 | /* | |
966 | * Wait for EEPROM to finish up. | |
967 | */ | |
968 | CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS); | |
969 | DELAY(1); | |
970 | for (i = 0; i < 1000; i++) { | |
971 | if (CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) & FXP_EEPROM_EEDO) | |
972 | break; | |
973 | DELAY(50); | |
974 | } | |
975 | CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0); | |
976 | DELAY(1); | |
977 | /* | |
978 | * Erase/write disable. | |
979 | */ | |
980 | CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS); | |
981 | fxp_eeprom_shiftin(sc, 0x4, 3); | |
982 | fxp_eeprom_shiftin(sc, 0, sc->eeprom_size); | |
983 | CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0); | |
984 | DELAY(1); | |
985 | } | |
986 | ||
987 | /* | |
988 | * From NetBSD: | |
989 | * | |
990 | * Figure out EEPROM size. | |
991 | * | |
992 | * 559's can have either 64-word or 256-word EEPROMs, the 558 | |
993 | * datasheet only talks about 64-word EEPROMs, and the 557 datasheet | |
994 | * talks about the existance of 16 to 256 word EEPROMs. | |
995 | * | |
996 | * The only known sizes are 64 and 256, where the 256 version is used | |
997 | * by CardBus cards to store CIS information. | |
998 | * | |
999 | * The address is shifted in msb-to-lsb, and after the last | |
1000 | * address-bit the EEPROM is supposed to output a `dummy zero' bit, | |
1001 | * after which follows the actual data. We try to detect this zero, by | |
1002 | * probing the data-out bit in the EEPROM control register just after | |
1003 | * having shifted in a bit. If the bit is zero, we assume we've | |
1004 | * shifted enough address bits. The data-out should be tri-state, | |
1005 | * before this, which should translate to a logical one. | |
1006 | */ | |
1007 | static void | |
1008 | fxp_autosize_eeprom(struct fxp_softc *sc) | |
1009 | { | |
1010 | ||
1011 | /* guess maximum size of 256 words */ | |
1012 | sc->eeprom_size = 8; | |
1013 | ||
1014 | /* autosize */ | |
7b9f668c | 1015 | fxp_eeprom_getword(sc, 0, 1); |
984263bc MD |
1016 | } |
1017 | ||
1018 | static void | |
1019 | fxp_read_eeprom(struct fxp_softc *sc, u_short *data, int offset, int words) | |
1020 | { | |
1021 | int i; | |
1022 | ||
1023 | for (i = 0; i < words; i++) | |
1024 | data[i] = fxp_eeprom_getword(sc, offset + i, 0); | |
1025 | } | |
1026 | ||
1027 | static void | |
1028 | fxp_write_eeprom(struct fxp_softc *sc, u_short *data, int offset, int words) | |
1029 | { | |
1030 | int i; | |
1031 | ||
1032 | for (i = 0; i < words; i++) | |
1033 | fxp_eeprom_putword(sc, offset + i, data[i]); | |
1034 | } | |
1035 | ||
1036 | /* | |
1037 | * Start packet transmission on the interface. | |
1038 | */ | |
1039 | static void | |
f0a26983 | 1040 | fxp_start(struct ifnet *ifp, struct ifaltq_subque *ifsq) |
984263bc MD |
1041 | { |
1042 | struct fxp_softc *sc = ifp->if_softc; | |
1043 | struct fxp_cb_tx *txp; | |
1044 | ||
f0a26983 | 1045 | ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq); |
ac72fc11 SZ |
1046 | ASSERT_SERIALIZED(ifp->if_serializer); |
1047 | ||
984263bc MD |
1048 | /* |
1049 | * See if we need to suspend xmit until the multicast filter | |
1050 | * has been reprogrammed (which can only be done at the head | |
1051 | * of the command chain). | |
1052 | */ | |
1053 | if (sc->need_mcsetup) { | |
9db4b353 | 1054 | ifq_purge(&ifp->if_snd); |
984263bc MD |
1055 | return; |
1056 | } | |
1057 | ||
9ed293e0 | 1058 | if ((ifp->if_flags & IFF_RUNNING) == 0 || ifq_is_oactive(&ifp->if_snd)) |
9db4b353 SZ |
1059 | return; |
1060 | ||
984263bc MD |
1061 | txp = NULL; |
1062 | ||
1063 | /* | |
1064 | * We're finished if there is nothing more to add to the list or if | |
1065 | * we're all filled up with buffers to transmit. | |
1066 | * NOTE: One TxCB is reserved to guarantee that fxp_mc_setup() can add | |
1067 | * a NOP command when needed. | |
1068 | */ | |
883c716a | 1069 | while (!ifq_is_empty(&ifp->if_snd) && sc->tx_queued < FXP_USABLE_TXCB) { |
984263bc | 1070 | struct mbuf *m, *mb_head; |
50503f0f | 1071 | int segment, ntries = 0; |
984263bc MD |
1072 | |
1073 | /* | |
be2f29ea | 1074 | * Grab a packet to transmit. |
984263bc | 1075 | */ |
ac9843a1 | 1076 | mb_head = ifq_dequeue(&ifp->if_snd); |
cb96d2fc JS |
1077 | if (mb_head == NULL) |
1078 | break; | |
be2f29ea | 1079 | tbdinit: |
984263bc | 1080 | /* |
be2f29ea | 1081 | * Make sure that the packet fits into one TX desc |
984263bc | 1082 | */ |
be2f29ea SZ |
1083 | segment = 0; |
1084 | for (m = mb_head; m != NULL; m = m->m_next) { | |
984263bc | 1085 | if (m->m_len != 0) { |
be2f29ea SZ |
1086 | ++segment; |
1087 | if (segment >= FXP_NTXSEG) | |
984263bc | 1088 | break; |
984263bc MD |
1089 | } |
1090 | } | |
be2f29ea | 1091 | if (segment >= FXP_NTXSEG) { |
984263bc MD |
1092 | struct mbuf *mn; |
1093 | ||
be2f29ea SZ |
1094 | if (ntries) { |
1095 | /* | |
1096 | * Packet is excessively fragmented, | |
1097 | * and will never fit into one TX | |
1098 | * desc. Give it up. | |
1099 | */ | |
1100 | m_freem(mb_head); | |
d40991ef | 1101 | IFNET_STAT_INC(ifp, oerrors, 1); |
be2f29ea | 1102 | continue; |
9db4b353 SZ |
1103 | } |
1104 | ||
b5523eac | 1105 | mn = m_dup(mb_head, M_NOWAIT); |
9db4b353 | 1106 | if (mn == NULL) { |
be2f29ea | 1107 | m_freem(mb_head); |
d40991ef | 1108 | IFNET_STAT_INC(ifp, oerrors, 1); |
be2f29ea | 1109 | continue; |
9db4b353 SZ |
1110 | } |
1111 | ||
984263bc MD |
1112 | m_freem(mb_head); |
1113 | mb_head = mn; | |
50503f0f | 1114 | ntries = 1; |
984263bc MD |
1115 | goto tbdinit; |
1116 | } | |
1117 | ||
be2f29ea SZ |
1118 | /* |
1119 | * Get pointer to next available tx desc. | |
1120 | */ | |
1121 | txp = sc->cbl_last->next; | |
1122 | ||
1123 | /* | |
1124 | * Go through each of the mbufs in the chain and initialize | |
1125 | * the transmit buffer descriptors with the physical address | |
1126 | * and size of the mbuf. | |
1127 | */ | |
1128 | for (m = mb_head, segment = 0; m != NULL; m = m->m_next) { | |
1129 | if (m->m_len != 0) { | |
1130 | KKASSERT(segment < FXP_NTXSEG); | |
1131 | ||
1132 | txp->tbd[segment].tb_addr = | |
1133 | vtophys(mtod(m, vm_offset_t)); | |
1134 | txp->tbd[segment].tb_size = m->m_len; | |
1135 | segment++; | |
1136 | } | |
1137 | } | |
1138 | KKASSERT(m == NULL); | |
1139 | ||
984263bc MD |
1140 | txp->tbd_number = segment; |
1141 | txp->mb_head = mb_head; | |
1142 | txp->cb_status = 0; | |
1143 | if (sc->tx_queued != FXP_CXINT_THRESH - 1) { | |
1144 | txp->cb_command = | |
1145 | FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | | |
1146 | FXP_CB_COMMAND_S; | |
1147 | } else { | |
1148 | txp->cb_command = | |
1149 | FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | | |
1150 | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I; | |
984263bc MD |
1151 | } |
1152 | txp->tx_threshold = tx_threshold; | |
be2f29ea | 1153 | |
984263bc MD |
1154 | /* |
1155 | * Advance the end of list forward. | |
1156 | */ | |
984263bc | 1157 | sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S; |
984263bc MD |
1158 | sc->cbl_last = txp; |
1159 | ||
1160 | /* | |
1161 | * Advance the beginning of the list forward if there are | |
1162 | * no other packets queued (when nothing is queued, cbl_first | |
1163 | * sits on the last TxCB that was sent out). | |
1164 | */ | |
1165 | if (sc->tx_queued == 0) | |
1166 | sc->cbl_first = txp; | |
1167 | ||
1168 | sc->tx_queued++; | |
be2f29ea SZ |
1169 | /* |
1170 | * Set a 5 second timer just in case we don't hear | |
1171 | * from the card again. | |
1172 | */ | |
1173 | ifp->if_timer = 5; | |
984263bc | 1174 | |
7600679e | 1175 | BPF_MTAP(ifp, mb_head); |
984263bc MD |
1176 | } |
1177 | ||
883c716a | 1178 | if (sc->tx_queued >= FXP_USABLE_TXCB) |
9ed293e0 | 1179 | ifq_set_oactive(&ifp->if_snd); |
9db4b353 | 1180 | |
984263bc MD |
1181 | /* |
1182 | * We're finished. If we added to the list, issue a RESUME to get DMA | |
1183 | * going again if suspended. | |
1184 | */ | |
1185 | if (txp != NULL) { | |
1186 | fxp_scb_wait(sc); | |
1187 | fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_RESUME); | |
1188 | } | |
1189 | } | |
1190 | ||
ee332442 | 1191 | #ifdef IFPOLL_ENABLE |
984263bc MD |
1192 | |
1193 | static void | |
ee332442 | 1194 | fxp_npoll_compat(struct ifnet *ifp, void *arg __unused, int count) |
984263bc MD |
1195 | { |
1196 | struct fxp_softc *sc = ifp->if_softc; | |
1197 | u_int8_t statack; | |
1198 | ||
ac72fc11 SZ |
1199 | ASSERT_SERIALIZED(ifp->if_serializer); |
1200 | ||
ee332442 SZ |
1201 | statack = FXP_SCB_STATACK_CXTNO | FXP_SCB_STATACK_CNA | |
1202 | FXP_SCB_STATACK_FR; | |
1203 | if (sc->fxp_npoll.ifpc_stcount-- == 0) { | |
1204 | u_int8_t tmp; | |
1205 | ||
1206 | sc->fxp_npoll.ifpc_stcount = sc->fxp_npoll.ifpc_stfrac; | |
1207 | ||
1208 | tmp = CSR_READ_1(sc, FXP_CSR_SCB_STATACK); | |
1209 | if (tmp == 0xff || tmp == 0) | |
1210 | return; /* nothing to do */ | |
1211 | tmp &= ~statack; | |
1212 | /* ack what we can */ | |
1213 | if (tmp != 0) | |
1214 | CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, tmp); | |
1215 | statack |= tmp; | |
1216 | } | |
1217 | fxp_intr_body(sc, statack, count); | |
1218 | } | |
1219 | ||
1220 | static void | |
1221 | fxp_npoll(struct ifnet *ifp, struct ifpoll_info *info) | |
1222 | { | |
1223 | struct fxp_softc *sc = ifp->if_softc; | |
1224 | ||
1225 | ASSERT_SERIALIZED(ifp->if_serializer); | |
1226 | ||
1227 | if (info != NULL) { | |
1228 | int cpuid = sc->fxp_npoll.ifpc_cpuid; | |
1229 | ||
1230 | info->ifpi_rx[cpuid].poll_func = fxp_npoll_compat; | |
1231 | info->ifpi_rx[cpuid].arg = NULL; | |
1232 | info->ifpi_rx[cpuid].serializer = ifp->if_serializer; | |
1233 | ||
1234 | if (ifp->if_flags & IFF_RUNNING) { | |
1235 | /* disable interrupts */ | |
1236 | CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, | |
1237 | FXP_SCB_INTR_DISABLE); | |
1238 | sc->fxp_npoll.ifpc_stcount = 0; | |
1239 | } | |
dfd3b18b | 1240 | ifq_set_cpuid(&ifp->if_snd, cpuid); |
ee332442 SZ |
1241 | } else { |
1242 | if (ifp->if_flags & IFF_RUNNING) { | |
1243 | /* enable interrupts */ | |
1244 | CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, 0); | |
9c095379 | 1245 | } |
dfd3b18b | 1246 | ifq_set_cpuid(&ifp->if_snd, rman_get_cpuid(sc->irq)); |
984263bc | 1247 | } |
984263bc | 1248 | } |
9c095379 | 1249 | |
ee332442 | 1250 | #endif /* IFPOLL_ENABLE */ |
984263bc MD |
1251 | |
1252 | /* | |
1253 | * Process interface interrupts. | |
1254 | */ | |
1255 | static void | |
1256 | fxp_intr(void *xsc) | |
1257 | { | |
1258 | struct fxp_softc *sc = xsc; | |
1259 | u_int8_t statack; | |
1260 | ||
ac72fc11 SZ |
1261 | ASSERT_SERIALIZED(sc->arpcom.ac_if.if_serializer); |
1262 | ||
984263bc MD |
1263 | if (sc->suspended) { |
1264 | return; | |
1265 | } | |
1266 | ||
1267 | while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) { | |
1268 | /* | |
1269 | * It should not be possible to have all bits set; the | |
1270 | * FXP_SCB_INTR_SWI bit always returns 0 on a read. If | |
1271 | * all bits are set, this may indicate that the card has | |
1272 | * been physically ejected, so ignore it. | |
1273 | */ | |
1274 | if (statack == 0xff) | |
1275 | return; | |
1276 | ||
1277 | /* | |
1278 | * First ACK all the interrupts in this pass. | |
1279 | */ | |
1280 | CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack); | |
1281 | fxp_intr_body(sc, statack, -1); | |
1282 | } | |
1283 | } | |
1284 | ||
1285 | static void | |
1286 | fxp_intr_body(struct fxp_softc *sc, u_int8_t statack, int count) | |
1287 | { | |
3dc849fa | 1288 | struct ifnet *ifp = &sc->arpcom.ac_if; |
984263bc MD |
1289 | struct mbuf *m; |
1290 | struct fxp_rfa *rfa; | |
1291 | int rnr = (statack & FXP_SCB_STATACK_RNR) ? 1 : 0; | |
1292 | ||
1293 | if (rnr) | |
1294 | fxp_rnr++; | |
ee332442 | 1295 | #ifdef IFPOLL_ENABLE |
984263bc MD |
1296 | /* Pick up a deferred RNR condition if `count' ran out last time. */ |
1297 | if (sc->flags & FXP_FLAG_DEFERRED_RNR) { | |
1298 | sc->flags &= ~FXP_FLAG_DEFERRED_RNR; | |
1299 | rnr = 1; | |
1300 | } | |
1301 | #endif | |
1302 | ||
1303 | /* | |
1304 | * Free any finished transmit mbuf chains. | |
1305 | * | |
1306 | * Handle the CNA event likt a CXTNO event. It used to | |
1307 | * be that this event (control unit not ready) was not | |
1308 | * encountered, but it is now with the SMPng modifications. | |
1309 | * The exact sequence of events that occur when the interface | |
1310 | * is brought up are different now, and if this event | |
1311 | * goes unhandled, the configuration/rxfilter setup sequence | |
1312 | * can stall for several seconds. The result is that no | |
1313 | * packets go out onto the wire for about 5 to 10 seconds | |
1314 | * after the interface is ifconfig'ed for the first time. | |
1315 | */ | |
1316 | if (statack & (FXP_SCB_STATACK_CXTNO | FXP_SCB_STATACK_CNA)) { | |
1317 | struct fxp_cb_tx *txp; | |
1318 | ||
1319 | for (txp = sc->cbl_first; sc->tx_queued && | |
1320 | (txp->cb_status & FXP_CB_STATUS_C) != 0; | |
1321 | txp = txp->next) { | |
acaaa437 | 1322 | if ((m = txp->mb_head) != NULL) { |
984263bc | 1323 | txp->mb_head = NULL; |
acaaa437 MD |
1324 | sc->tx_queued--; |
1325 | m_freem(m); | |
1326 | } else { | |
1327 | sc->tx_queued--; | |
984263bc | 1328 | } |
984263bc MD |
1329 | } |
1330 | sc->cbl_first = txp; | |
9db4b353 | 1331 | |
883c716a | 1332 | if (sc->tx_queued < FXP_USABLE_TXCB) |
9ed293e0 | 1333 | ifq_clr_oactive(&ifp->if_snd); |
9db4b353 | 1334 | |
984263bc | 1335 | if (sc->tx_queued == 0) { |
be2f29ea | 1336 | ifp->if_timer = 0; |
984263bc MD |
1337 | if (sc->need_mcsetup) |
1338 | fxp_mc_setup(sc); | |
1339 | } | |
9db4b353 | 1340 | |
984263bc MD |
1341 | /* |
1342 | * Try to start more packets transmitting. | |
1343 | */ | |
cb96d2fc | 1344 | if (!ifq_is_empty(&ifp->if_snd)) |
9db4b353 | 1345 | if_devstart(ifp); |
984263bc MD |
1346 | } |
1347 | ||
1348 | /* | |
1349 | * Just return if nothing happened on the receive side. | |
1350 | */ | |
1351 | if (!rnr && (statack & FXP_SCB_STATACK_FR) == 0) | |
1352 | return; | |
1353 | ||
1354 | /* | |
1355 | * Process receiver interrupts. If a no-resource (RNR) | |
1356 | * condition exists, get whatever packets we can and | |
1357 | * re-start the receiver. | |
1358 | * | |
1359 | * When using polling, we do not process the list to completion, | |
1360 | * so when we get an RNR interrupt we must defer the restart | |
1361 | * until we hit the last buffer with the C bit set. | |
1362 | * If we run out of cycles and rfa_headm has the C bit set, | |
1363 | * record the pending RNR in the FXP_FLAG_DEFERRED_RNR flag so | |
1364 | * that the info will be used in the subsequent polling cycle. | |
1365 | */ | |
1366 | for (;;) { | |
1367 | m = sc->rfa_headm; | |
1368 | rfa = (struct fxp_rfa *)(m->m_ext.ext_buf + | |
5bd08532 | 1369 | RFA_ALIGNMENT_FUDGE); |
984263bc | 1370 | |
ee332442 | 1371 | #ifdef IFPOLL_ENABLE /* loop at most count times if count >=0 */ |
984263bc MD |
1372 | if (count >= 0 && count-- == 0) { |
1373 | if (rnr) { | |
1374 | /* Defer RNR processing until the next time. */ | |
1375 | sc->flags |= FXP_FLAG_DEFERRED_RNR; | |
1376 | rnr = 0; | |
1377 | } | |
1378 | break; | |
1379 | } | |
ee332442 | 1380 | #endif /* IFPOLL_ENABLE */ |
984263bc MD |
1381 | |
1382 | if ( (rfa->rfa_status & FXP_RFA_STATUS_C) == 0) | |
1383 | break; | |
1384 | ||
1385 | /* | |
1386 | * Remove first packet from the chain. | |
1387 | */ | |
1388 | sc->rfa_headm = m->m_next; | |
5bd08532 MD |
1389 | if (sc->rfa_headm == NULL) |
1390 | sc->rfa_tailm = NULL; | |
984263bc MD |
1391 | m->m_next = NULL; |
1392 | ||
1393 | /* | |
1394 | * Add a new buffer to the receive chain. | |
1395 | * If this fails, the old buffer is recycled | |
1396 | * instead. | |
1397 | */ | |
1398 | if (fxp_add_rfabuf(sc, m) == 0) { | |
1399 | int total_len; | |
1400 | ||
1401 | /* | |
1402 | * Fetch packet length (the top 2 bits of | |
1403 | * actual_size are flags set by the controller | |
1404 | * upon completion), and drop the packet in case | |
1405 | * of bogus length or CRC errors. | |
1406 | */ | |
1407 | total_len = rfa->actual_size & 0x3fff; | |
1408 | if (total_len < sizeof(struct ether_header) || | |
1409 | total_len > MCLBYTES - RFA_ALIGNMENT_FUDGE - | |
5bd08532 MD |
1410 | sizeof(struct fxp_rfa) || |
1411 | (rfa->rfa_status & FXP_RFA_STATUS_CRC)) { | |
984263bc MD |
1412 | m_freem(m); |
1413 | continue; | |
1414 | } | |
1415 | m->m_pkthdr.len = m->m_len = total_len; | |
73029d08 | 1416 | ifp->if_input(ifp, m, NULL, -1); |
984263bc MD |
1417 | } |
1418 | } | |
21f7a7d1 | 1419 | |
984263bc MD |
1420 | if (rnr) { |
1421 | fxp_scb_wait(sc); | |
1422 | CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, | |
1423 | vtophys(sc->rfa_headm->m_ext.ext_buf) + | |
1424 | RFA_ALIGNMENT_FUDGE); | |
1425 | fxp_scb_cmd(sc, FXP_SCB_COMMAND_RU_START); | |
1426 | } | |
1427 | } | |
1428 | ||
1429 | /* | |
1430 | * Update packet in/out/collision statistics. The i82557 doesn't | |
1431 | * allow you to access these counters without doing a fairly | |
1432 | * expensive DMA to get _all_ of the statistics it maintains, so | |
1433 | * we do this operation here only once per second. The statistics | |
1434 | * counters in the kernel are updated from the previous dump-stats | |
1435 | * DMA and then a new dump-stats DMA is started. The on-chip | |
1436 | * counters are zeroed when the DMA completes. If we can't start | |
1437 | * the DMA immediately, we don't wait - we just prepare to read | |
1438 | * them again next time. | |
1439 | */ | |
1440 | static void | |
1441 | fxp_tick(void *xsc) | |
1442 | { | |
1443 | struct fxp_softc *sc = xsc; | |
3dc849fa | 1444 | struct ifnet *ifp = &sc->arpcom.ac_if; |
984263bc MD |
1445 | struct fxp_stats *sp = sc->fxp_stats; |
1446 | struct fxp_cb_tx *txp; | |
acaaa437 | 1447 | struct mbuf *m; |
984263bc | 1448 | |
78195a76 MD |
1449 | lwkt_serialize_enter(sc->arpcom.ac_if.if_serializer); |
1450 | ||
d40991ef SZ |
1451 | IFNET_STAT_INC(ifp, opackets, sp->tx_good); |
1452 | IFNET_STAT_INC(ifp, collisions, sp->tx_total_collisions); | |
984263bc | 1453 | if (sp->rx_good) { |
d40991ef | 1454 | IFNET_STAT_INC(ifp, ipackets, sp->rx_good); |
984263bc MD |
1455 | sc->rx_idle_secs = 0; |
1456 | } else { | |
1457 | /* | |
1458 | * Receiver's been idle for another second. | |
1459 | */ | |
1460 | sc->rx_idle_secs++; | |
1461 | } | |
d40991ef | 1462 | IFNET_STAT_INC(ifp, ierrors, |
984263bc MD |
1463 | sp->rx_crc_errors + |
1464 | sp->rx_alignment_errors + | |
1465 | sp->rx_rnr_errors + | |
d40991ef | 1466 | sp->rx_overrun_errors); |
984263bc MD |
1467 | /* |
1468 | * If any transmit underruns occured, bump up the transmit | |
1469 | * threshold by another 512 bytes (64 * 8). | |
1470 | */ | |
1471 | if (sp->tx_underruns) { | |
d40991ef | 1472 | IFNET_STAT_INC(ifp, oerrors, sp->tx_underruns); |
984263bc MD |
1473 | if (tx_threshold < 192) |
1474 | tx_threshold += 64; | |
1475 | } | |
37103068 | 1476 | |
984263bc MD |
1477 | /* |
1478 | * Release any xmit buffers that have completed DMA. This isn't | |
1479 | * strictly necessary to do here, but it's advantagous for mbufs | |
1480 | * with external storage to be released in a timely manner rather | |
1481 | * than being defered for a potentially long time. This limits | |
1482 | * the delay to a maximum of one second. | |
be2f29ea | 1483 | */ |
984263bc MD |
1484 | for (txp = sc->cbl_first; sc->tx_queued && |
1485 | (txp->cb_status & FXP_CB_STATUS_C) != 0; | |
1486 | txp = txp->next) { | |
acaaa437 | 1487 | if ((m = txp->mb_head) != NULL) { |
984263bc | 1488 | txp->mb_head = NULL; |
acaaa437 MD |
1489 | sc->tx_queued--; |
1490 | m_freem(m); | |
1491 | } else { | |
1492 | sc->tx_queued--; | |
984263bc | 1493 | } |
984263bc MD |
1494 | } |
1495 | sc->cbl_first = txp; | |
be2f29ea | 1496 | |
883c716a | 1497 | if (sc->tx_queued < FXP_USABLE_TXCB) |
9ed293e0 | 1498 | ifq_clr_oactive(&ifp->if_snd); |
be2f29ea SZ |
1499 | if (sc->tx_queued == 0) |
1500 | ifp->if_timer = 0; | |
1501 | ||
883c716a SZ |
1502 | /* |
1503 | * Try to start more packets transmitting. | |
1504 | */ | |
1505 | if (!ifq_is_empty(&ifp->if_snd)) | |
1506 | if_devstart(ifp); | |
1507 | ||
984263bc MD |
1508 | /* |
1509 | * If we haven't received any packets in FXP_MAC_RX_IDLE seconds, | |
1510 | * then assume the receiver has locked up and attempt to clear | |
1511 | * the condition by reprogramming the multicast filter. This is | |
1512 | * a work-around for a bug in the 82557 where the receiver locks | |
1513 | * up if it gets certain types of garbage in the syncronization | |
1514 | * bits prior to the packet header. This bug is supposed to only | |
1515 | * occur in 10Mbps mode, but has been seen to occur in 100Mbps | |
1516 | * mode as well (perhaps due to a 10/100 speed transition). | |
1517 | */ | |
1518 | if (sc->rx_idle_secs > FXP_MAX_RX_IDLE) { | |
1519 | sc->rx_idle_secs = 0; | |
1520 | fxp_mc_setup(sc); | |
1521 | } | |
1522 | /* | |
1523 | * If there is no pending command, start another stats | |
1524 | * dump. Otherwise punt for now. | |
1525 | */ | |
1526 | if (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) == 0) { | |
1527 | /* | |
1528 | * Start another stats dump. | |
1529 | */ | |
1530 | fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_DUMPRESET); | |
1531 | } else { | |
1532 | /* | |
1533 | * A previous command is still waiting to be accepted. | |
1534 | * Just zero our copy of the stats and wait for the | |
1535 | * next timer event to update them. | |
1536 | */ | |
1537 | sp->tx_good = 0; | |
1538 | sp->tx_underruns = 0; | |
1539 | sp->tx_total_collisions = 0; | |
1540 | ||
1541 | sp->rx_good = 0; | |
1542 | sp->rx_crc_errors = 0; | |
1543 | sp->rx_alignment_errors = 0; | |
1544 | sp->rx_rnr_errors = 0; | |
1545 | sp->rx_overrun_errors = 0; | |
1546 | } | |
1547 | if (sc->miibus != NULL) | |
1548 | mii_tick(device_get_softc(sc->miibus)); | |
984263bc MD |
1549 | /* |
1550 | * Schedule another timeout one second from now. | |
1551 | */ | |
a1f4b801 | 1552 | callout_reset(&sc->fxp_stat_timer, hz, fxp_tick, sc); |
37103068 | 1553 | |
78195a76 | 1554 | lwkt_serialize_exit(sc->arpcom.ac_if.if_serializer); |
984263bc MD |
1555 | } |
1556 | ||
1557 | /* | |
1558 | * Stop the interface. Cancels the statistics updater and resets | |
1559 | * the interface. | |
1560 | */ | |
1561 | static void | |
1562 | fxp_stop(struct fxp_softc *sc) | |
1563 | { | |
3dc849fa | 1564 | struct ifnet *ifp = &sc->arpcom.ac_if; |
984263bc MD |
1565 | struct fxp_cb_tx *txp; |
1566 | int i; | |
1567 | ||
334b9734 SZ |
1568 | ASSERT_SERIALIZED(ifp->if_serializer); |
1569 | ||
9ed293e0 SZ |
1570 | ifp->if_flags &= ~IFF_RUNNING; |
1571 | ifq_clr_oactive(&ifp->if_snd); | |
984263bc MD |
1572 | ifp->if_timer = 0; |
1573 | ||
984263bc MD |
1574 | /* |
1575 | * Cancel stats updater. | |
1576 | */ | |
a1f4b801 | 1577 | callout_stop(&sc->fxp_stat_timer); |
984263bc MD |
1578 | |
1579 | /* | |
1580 | * Issue software reset, which also unloads the microcode. | |
1581 | */ | |
1582 | sc->flags &= ~FXP_FLAG_UCODE; | |
1583 | CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SOFTWARE_RESET); | |
1584 | DELAY(50); | |
1585 | ||
1586 | /* | |
1587 | * Release any xmit buffers. | |
1588 | */ | |
1589 | txp = sc->cbl_base; | |
1590 | if (txp != NULL) { | |
1591 | for (i = 0; i < FXP_NTXCB; i++) { | |
1592 | if (txp[i].mb_head != NULL) { | |
1593 | m_freem(txp[i].mb_head); | |
1594 | txp[i].mb_head = NULL; | |
1595 | } | |
1596 | } | |
1597 | } | |
1598 | sc->tx_queued = 0; | |
1599 | ||
1600 | /* | |
1601 | * Free all the receive buffers then reallocate/reinitialize | |
1602 | */ | |
1603 | if (sc->rfa_headm != NULL) | |
1604 | m_freem(sc->rfa_headm); | |
1605 | sc->rfa_headm = NULL; | |
1606 | sc->rfa_tailm = NULL; | |
1607 | for (i = 0; i < FXP_NRFABUFS; i++) { | |
1608 | if (fxp_add_rfabuf(sc, NULL) != 0) { | |
1609 | /* | |
1610 | * This "can't happen" - we're at splimp() | |
1611 | * and we just freed all the buffers we need | |
1612 | * above. | |
1613 | */ | |
1614 | panic("fxp_stop: no buffers!"); | |
1615 | } | |
1616 | } | |
1617 | } | |
1618 | ||
1619 | /* | |
1620 | * Watchdog/transmission transmit timeout handler. Called when a | |
1621 | * transmission is started on the interface, but no interrupt is | |
1622 | * received before the timeout. This usually indicates that the | |
1623 | * card has wedged for some reason. | |
1624 | */ | |
1625 | static void | |
1626 | fxp_watchdog(struct ifnet *ifp) | |
1627 | { | |
ac72fc11 SZ |
1628 | ASSERT_SERIALIZED(ifp->if_serializer); |
1629 | ||
af340cf5 | 1630 | if_printf(ifp, "device timeout\n"); |
d40991ef | 1631 | IFNET_STAT_INC(ifp, oerrors, 1); |
af340cf5 | 1632 | fxp_init(ifp->if_softc); |
984263bc MD |
1633 | } |
1634 | ||
1635 | static void | |
1636 | fxp_init(void *xsc) | |
1637 | { | |
1638 | struct fxp_softc *sc = xsc; | |
3dc849fa | 1639 | struct ifnet *ifp = &sc->arpcom.ac_if; |
984263bc MD |
1640 | struct fxp_cb_config *cbp; |
1641 | struct fxp_cb_ias *cb_ias; | |
1642 | struct fxp_cb_tx *txp; | |
1643 | struct fxp_cb_mcs *mcsp; | |
37103068 JS |
1644 | int i, prm; |
1645 | ||
ac72fc11 SZ |
1646 | ASSERT_SERIALIZED(ifp->if_serializer); |
1647 | ||
984263bc MD |
1648 | /* |
1649 | * Cancel any pending I/O | |
1650 | */ | |
1651 | fxp_stop(sc); | |
1652 | ||
1653 | prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0; | |
1654 | ||
1655 | /* | |
1656 | * Initialize base of CBL and RFA memory. Loading with zero | |
1657 | * sets it up for regular linear addressing. | |
1658 | */ | |
1659 | CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, 0); | |
1660 | fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_BASE); | |
1661 | ||
1662 | fxp_scb_wait(sc); | |
1663 | fxp_scb_cmd(sc, FXP_SCB_COMMAND_RU_BASE); | |
1664 | ||
1665 | /* | |
1666 | * Initialize base of dump-stats buffer. | |
1667 | */ | |
1668 | fxp_scb_wait(sc); | |
1669 | CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(sc->fxp_stats)); | |
1670 | fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_DUMP_ADR); | |
1671 | ||
1672 | /* | |
1673 | * Attempt to load microcode if requested. | |
1674 | */ | |
1675 | if (ifp->if_flags & IFF_LINK0 && (sc->flags & FXP_FLAG_UCODE) == 0) | |
1676 | fxp_load_ucode(sc); | |
1677 | ||
1678 | /* | |
1679 | * Initialize the multicast address list. | |
1680 | */ | |
1681 | if (fxp_mc_addrs(sc)) { | |
1682 | mcsp = sc->mcsp; | |
1683 | mcsp->cb_status = 0; | |
1684 | mcsp->cb_command = FXP_CB_COMMAND_MCAS | FXP_CB_COMMAND_EL; | |
1685 | mcsp->link_addr = -1; | |
1686 | /* | |
1687 | * Start the multicast setup command. | |
1688 | */ | |
1689 | fxp_scb_wait(sc); | |
1690 | CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&mcsp->cb_status)); | |
1691 | fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_START); | |
1692 | /* ...and wait for it to complete. */ | |
1693 | fxp_dma_wait(&mcsp->cb_status, sc); | |
1694 | } | |
1695 | ||
1696 | /* | |
1697 | * We temporarily use memory that contains the TxCB list to | |
1698 | * construct the config CB. The TxCB list memory is rebuilt | |
1699 | * later. | |
1700 | */ | |
1701 | cbp = (struct fxp_cb_config *) sc->cbl_base; | |
1702 | ||
1703 | /* | |
1704 | * This bcopy is kind of disgusting, but there are a bunch of must be | |
1705 | * zero and must be one bits in this structure and this is the easiest | |
1706 | * way to initialize them all to proper values. | |
1707 | */ | |
1708 | bcopy(fxp_cb_config_template, | |
1709 | (void *)(uintptr_t)(volatile void *)&cbp->cb_status, | |
1710 | sizeof(fxp_cb_config_template)); | |
1711 | ||
1712 | cbp->cb_status = 0; | |
1713 | cbp->cb_command = FXP_CB_COMMAND_CONFIG | FXP_CB_COMMAND_EL; | |
1714 | cbp->link_addr = -1; /* (no) next command */ | |
1715 | cbp->byte_count = 22; /* (22) bytes to config */ | |
1716 | cbp->rx_fifo_limit = 8; /* rx fifo threshold (32 bytes) */ | |
1717 | cbp->tx_fifo_limit = 0; /* tx fifo threshold (0 bytes) */ | |
1718 | cbp->adaptive_ifs = 0; /* (no) adaptive interframe spacing */ | |
1719 | cbp->mwi_enable = sc->flags & FXP_FLAG_MWI_ENABLE ? 1 : 0; | |
1720 | cbp->type_enable = 0; /* actually reserved */ | |
1721 | cbp->read_align_en = sc->flags & FXP_FLAG_READ_ALIGN ? 1 : 0; | |
1722 | cbp->end_wr_on_cl = sc->flags & FXP_FLAG_WRITE_ALIGN ? 1 : 0; | |
1723 | cbp->rx_dma_bytecount = 0; /* (no) rx DMA max */ | |
1724 | cbp->tx_dma_bytecount = 0; /* (no) tx DMA max */ | |
1725 | cbp->dma_mbce = 0; /* (disable) dma max counters */ | |
1726 | cbp->late_scb = 0; /* (don't) defer SCB update */ | |
1727 | cbp->direct_dma_dis = 1; /* disable direct rcv dma mode */ | |
1728 | cbp->tno_int_or_tco_en =0; /* (disable) tx not okay interrupt */ | |
1729 | cbp->ci_int = 1; /* interrupt on CU idle */ | |
1730 | cbp->ext_txcb_dis = sc->flags & FXP_FLAG_EXT_TXCB ? 0 : 1; | |
1731 | cbp->ext_stats_dis = 1; /* disable extended counters */ | |
1732 | cbp->keep_overrun_rx = 0; /* don't pass overrun frames to host */ | |
1733 | cbp->save_bf = sc->revision == FXP_REV_82557 ? 1 : prm; | |
1734 | cbp->disc_short_rx = !prm; /* discard short packets */ | |
1735 | cbp->underrun_retry = 1; /* retry mode (once) on DMA underrun */ | |
1736 | cbp->two_frames = 0; /* do not limit FIFO to 2 frames */ | |
1737 | cbp->dyn_tbd = 0; /* (no) dynamic TBD mode */ | |
1738 | cbp->mediatype = sc->flags & FXP_FLAG_SERIAL_MEDIA ? 0 : 1; | |
1739 | cbp->csma_dis = 0; /* (don't) disable link */ | |
1740 | cbp->tcp_udp_cksum = 0; /* (don't) enable checksum */ | |
1741 | cbp->vlan_tco = 0; /* (don't) enable vlan wakeup */ | |
1742 | cbp->link_wake_en = 0; /* (don't) assert PME# on link change */ | |
1743 | cbp->arp_wake_en = 0; /* (don't) assert PME# on arp */ | |
1744 | cbp->mc_wake_en = 0; /* (don't) enable PME# on mcmatch */ | |
1745 | cbp->nsai = 1; /* (don't) disable source addr insert */ | |
1746 | cbp->preamble_length = 2; /* (7 byte) preamble */ | |
1747 | cbp->loopback = 0; /* (don't) loopback */ | |
1748 | cbp->linear_priority = 0; /* (normal CSMA/CD operation) */ | |
1749 | cbp->linear_pri_mode = 0; /* (wait after xmit only) */ | |
1750 | cbp->interfrm_spacing = 6; /* (96 bits of) interframe spacing */ | |
1751 | cbp->promiscuous = prm; /* promiscuous mode */ | |
1752 | cbp->bcast_disable = 0; /* (don't) disable broadcasts */ | |
1753 | cbp->wait_after_win = 0; /* (don't) enable modified backoff alg*/ | |
1754 | cbp->ignore_ul = 0; /* consider U/L bit in IA matching */ | |
1755 | cbp->crc16_en = 0; /* (don't) enable crc-16 algorithm */ | |
1756 | cbp->crscdt = sc->flags & FXP_FLAG_SERIAL_MEDIA ? 1 : 0; | |
1757 | ||
1758 | cbp->stripping = !prm; /* truncate rx packet to byte count */ | |
1759 | cbp->padding = 1; /* (do) pad short tx packets */ | |
1760 | cbp->rcv_crc_xfer = 0; /* (don't) xfer CRC to host */ | |
1761 | cbp->long_rx_en = sc->flags & FXP_FLAG_LONG_PKT_EN ? 1 : 0; | |
1762 | cbp->ia_wake_en = 0; /* (don't) wake up on address match */ | |
1763 | cbp->magic_pkt_dis = 0; /* (don't) disable magic packet */ | |
1764 | /* must set wake_en in PMCSR also */ | |
1765 | cbp->force_fdx = 0; /* (don't) force full duplex */ | |
1766 | cbp->fdx_pin_en = 1; /* (enable) FDX# pin */ | |
1767 | cbp->multi_ia = 0; /* (don't) accept multiple IAs */ | |
1768 | cbp->mc_all = sc->flags & FXP_FLAG_ALL_MCAST ? 1 : 0; | |
1769 | ||
1770 | if (sc->revision == FXP_REV_82557) { | |
1771 | /* | |
1772 | * The 82557 has no hardware flow control, the values | |
1773 | * below are the defaults for the chip. | |
1774 | */ | |
1775 | cbp->fc_delay_lsb = 0; | |
1776 | cbp->fc_delay_msb = 0x40; | |
1777 | cbp->pri_fc_thresh = 3; | |
1778 | cbp->tx_fc_dis = 0; | |
1779 | cbp->rx_fc_restop = 0; | |
1780 | cbp->rx_fc_restart = 0; | |
1781 | cbp->fc_filter = 0; | |
1782 | cbp->pri_fc_loc = 1; | |
1783 | } else { | |
1784 | cbp->fc_delay_lsb = 0x1f; | |
1785 | cbp->fc_delay_msb = 0x01; | |
1786 | cbp->pri_fc_thresh = 3; | |
1787 | cbp->tx_fc_dis = 0; /* enable transmit FC */ | |
1788 | cbp->rx_fc_restop = 1; /* enable FC restop frames */ | |
1789 | cbp->rx_fc_restart = 1; /* enable FC restart frames */ | |
1790 | cbp->fc_filter = !prm; /* drop FC frames to host */ | |
1791 | cbp->pri_fc_loc = 1; /* FC pri location (byte31) */ | |
1792 | } | |
1793 | ||
1794 | /* | |
1795 | * Start the config command/DMA. | |
1796 | */ | |
1797 | fxp_scb_wait(sc); | |
1798 | CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&cbp->cb_status)); | |
1799 | fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_START); | |
1800 | /* ...and wait for it to complete. */ | |
1801 | fxp_dma_wait(&cbp->cb_status, sc); | |
1802 | ||
1803 | /* | |
1804 | * Now initialize the station address. Temporarily use the TxCB | |
1805 | * memory area like we did above for the config CB. | |
1806 | */ | |
1807 | cb_ias = (struct fxp_cb_ias *) sc->cbl_base; | |
1808 | cb_ias->cb_status = 0; | |
1809 | cb_ias->cb_command = FXP_CB_COMMAND_IAS | FXP_CB_COMMAND_EL; | |
1810 | cb_ias->link_addr = -1; | |
1811 | bcopy(sc->arpcom.ac_enaddr, | |
1812 | (void *)(uintptr_t)(volatile void *)cb_ias->macaddr, | |
1813 | sizeof(sc->arpcom.ac_enaddr)); | |
1814 | ||
1815 | /* | |
1816 | * Start the IAS (Individual Address Setup) command/DMA. | |
1817 | */ | |
1818 | fxp_scb_wait(sc); | |
1819 | fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_START); | |
1820 | /* ...and wait for it to complete. */ | |
1821 | fxp_dma_wait(&cb_ias->cb_status, sc); | |
1822 | ||
1823 | /* | |
1824 | * Initialize transmit control block (TxCB) list. | |
1825 | */ | |
1826 | ||
1827 | txp = sc->cbl_base; | |
1828 | bzero(txp, sizeof(struct fxp_cb_tx) * FXP_NTXCB); | |
1829 | for (i = 0; i < FXP_NTXCB; i++) { | |
1830 | txp[i].cb_status = FXP_CB_STATUS_C | FXP_CB_STATUS_OK; | |
1831 | txp[i].cb_command = FXP_CB_COMMAND_NOP; | |
1832 | txp[i].link_addr = | |
1833 | vtophys(&txp[(i + 1) & FXP_TXCB_MASK].cb_status); | |
1834 | if (sc->flags & FXP_FLAG_EXT_TXCB) | |
1835 | txp[i].tbd_array_addr = vtophys(&txp[i].tbd[2]); | |
1836 | else | |
1837 | txp[i].tbd_array_addr = vtophys(&txp[i].tbd[0]); | |
1838 | txp[i].next = &txp[(i + 1) & FXP_TXCB_MASK]; | |
1839 | } | |
1840 | /* | |
1841 | * Set the suspend flag on the first TxCB and start the control | |
1842 | * unit. It will execute the NOP and then suspend. | |
1843 | */ | |
1844 | txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S; | |
1845 | sc->cbl_first = sc->cbl_last = txp; | |
1846 | sc->tx_queued = 1; | |
1847 | ||
1848 | fxp_scb_wait(sc); | |
1849 | fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_START); | |
1850 | ||
1851 | /* | |
1852 | * Initialize receiver buffer area - RFA. | |
1853 | */ | |
1854 | fxp_scb_wait(sc); | |
1855 | CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, | |
1856 | vtophys(sc->rfa_headm->m_ext.ext_buf) + RFA_ALIGNMENT_FUDGE); | |
1857 | fxp_scb_cmd(sc, FXP_SCB_COMMAND_RU_START); | |
1858 | ||
1859 | /* | |
1860 | * Set current media. | |
1861 | */ | |
1862 | if (sc->miibus != NULL) | |
1863 | mii_mediachg(device_get_softc(sc->miibus)); | |
1864 | ||
1865 | ifp->if_flags |= IFF_RUNNING; | |
9ed293e0 | 1866 | ifq_clr_oactive(&ifp->if_snd); |
984263bc MD |
1867 | |
1868 | /* | |
1869 | * Enable interrupts. | |
1870 | */ | |
ee332442 | 1871 | #ifdef IFPOLL_ENABLE |
984263bc MD |
1872 | /* |
1873 | * ... but only do that if we are not polling. And because (presumably) | |
1874 | * the default is interrupts on, we need to disable them explicitly! | |
1875 | */ | |
ee332442 | 1876 | if (ifp->if_flags & IFF_NPOLLING) { |
984263bc | 1877 | CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, FXP_SCB_INTR_DISABLE); |
ee332442 SZ |
1878 | sc->fxp_npoll.ifpc_stcount = 0; |
1879 | } else | |
1880 | #endif /* IFPOLL_ENABLE */ | |
984263bc | 1881 | CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, 0); |
984263bc MD |
1882 | |
1883 | /* | |
1884 | * Start stats updater. | |
1885 | */ | |
a1f4b801 | 1886 | callout_reset(&sc->fxp_stat_timer, hz, fxp_tick, sc); |
984263bc MD |
1887 | } |
1888 | ||
1889 | static int | |
1890 | fxp_serial_ifmedia_upd(struct ifnet *ifp) | |
1891 | { | |
ac72fc11 | 1892 | ASSERT_SERIALIZED(ifp->if_serializer); |
984263bc MD |
1893 | return (0); |
1894 | } | |
1895 | ||
1896 | static void | |
1897 | fxp_serial_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) | |
1898 | { | |
ac72fc11 | 1899 | ASSERT_SERIALIZED(ifp->if_serializer); |
984263bc MD |
1900 | ifmr->ifm_active = IFM_ETHER|IFM_MANUAL; |
1901 | } | |
1902 | ||
1903 | /* | |
1904 | * Change media according to request. | |
1905 | */ | |
1906 | static int | |
1907 | fxp_ifmedia_upd(struct ifnet *ifp) | |
1908 | { | |
1909 | struct fxp_softc *sc = ifp->if_softc; | |
1910 | struct mii_data *mii; | |
1911 | ||
ac72fc11 SZ |
1912 | ASSERT_SERIALIZED(ifp->if_serializer); |
1913 | ||
984263bc MD |
1914 | mii = device_get_softc(sc->miibus); |
1915 | mii_mediachg(mii); | |
1916 | return (0); | |
1917 | } | |
1918 | ||
1919 | /* | |
1920 | * Notify the world which media we're using. | |
1921 | */ | |
1922 | static void | |
1923 | fxp_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) | |
1924 | { | |
1925 | struct fxp_softc *sc = ifp->if_softc; | |
1926 | struct mii_data *mii; | |
1927 | ||
ac72fc11 SZ |
1928 | ASSERT_SERIALIZED(ifp->if_serializer); |
1929 | ||
984263bc MD |
1930 | mii = device_get_softc(sc->miibus); |
1931 | mii_pollstat(mii); | |
1932 | ifmr->ifm_active = mii->mii_media_active; | |
1933 | ifmr->ifm_status = mii->mii_media_status; | |
1934 | ||
1935 | if (ifmr->ifm_status & IFM_10_T && sc->flags & FXP_FLAG_CU_RESUME_BUG) | |
1936 | sc->cu_resume_bug = 1; | |
1937 | else | |
1938 | sc->cu_resume_bug = 0; | |
1939 | } | |
1940 | ||
1941 | /* | |
1942 | * Add a buffer to the end of the RFA buffer list. | |
1943 | * Return 0 if successful, 1 for failure. A failure results in | |
1944 | * adding the 'oldm' (if non-NULL) on to the end of the list - | |
1945 | * tossing out its old contents and recycling it. | |
1946 | * The RFA struct is stuck at the beginning of mbuf cluster and the | |
1947 | * data pointer is fixed up to point just past it. | |
1948 | */ | |
1949 | static int | |
1950 | fxp_add_rfabuf(struct fxp_softc *sc, struct mbuf *oldm) | |
1951 | { | |
1952 | u_int32_t v; | |
1953 | struct mbuf *m; | |
1954 | struct fxp_rfa *rfa, *p_rfa; | |
1955 | ||
b5523eac | 1956 | m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); |
984263bc MD |
1957 | if (m == NULL) { /* try to recycle the old mbuf instead */ |
1958 | if (oldm == NULL) | |
1959 | return 1; | |
1960 | m = oldm; | |
1961 | m->m_data = m->m_ext.ext_buf; | |
1962 | } | |
1963 | ||
1964 | /* | |
1965 | * Move the data pointer up so that the incoming data packet | |
1966 | * will be 32-bit aligned. | |
1967 | */ | |
1968 | m->m_data += RFA_ALIGNMENT_FUDGE; | |
1969 | ||
1970 | /* | |
1971 | * Get a pointer to the base of the mbuf cluster and move | |
1972 | * data start past it. | |
1973 | */ | |
1974 | rfa = mtod(m, struct fxp_rfa *); | |
1975 | m->m_data += sizeof(struct fxp_rfa); | |
b8a16790 MD |
1976 | rfa->size = (u_int16_t)(MCLBYTES - sizeof(struct fxp_rfa) - |
1977 | RFA_ALIGNMENT_FUDGE); | |
984263bc MD |
1978 | |
1979 | /* | |
1980 | * Initialize the rest of the RFA. Note that since the RFA | |
1981 | * is misaligned, we cannot store values directly. Instead, | |
1982 | * we use an optimized, inline copy. | |
1983 | */ | |
1984 | ||
1985 | rfa->rfa_status = 0; | |
1986 | rfa->rfa_control = FXP_RFA_CONTROL_EL; | |
1987 | rfa->actual_size = 0; | |
1988 | ||
1989 | v = -1; | |
1990 | fxp_lwcopy(&v, (volatile u_int32_t *) rfa->link_addr); | |
1991 | fxp_lwcopy(&v, (volatile u_int32_t *) rfa->rbd_addr); | |
1992 | ||
1993 | /* | |
1994 | * If there are other buffers already on the list, attach this | |
1995 | * one to the end by fixing up the tail to point to this one. | |
1996 | */ | |
1997 | if (sc->rfa_headm != NULL) { | |
b8a16790 MD |
1998 | p_rfa = (struct fxp_rfa *)(sc->rfa_tailm->m_ext.ext_buf + |
1999 | RFA_ALIGNMENT_FUDGE); | |
984263bc MD |
2000 | sc->rfa_tailm->m_next = m; |
2001 | v = vtophys(rfa); | |
2002 | fxp_lwcopy(&v, (volatile u_int32_t *) p_rfa->link_addr); | |
2003 | p_rfa->rfa_control = 0; | |
2004 | } else { | |
2005 | sc->rfa_headm = m; | |
2006 | } | |
2007 | sc->rfa_tailm = m; | |
2008 | ||
2009 | return (m == oldm); | |
2010 | } | |
2011 | ||
10d1b534 | 2012 | static int |
984263bc MD |
2013 | fxp_miibus_readreg(device_t dev, int phy, int reg) |
2014 | { | |
2015 | struct fxp_softc *sc = device_get_softc(dev); | |
2016 | int count = 10000; | |
2017 | int value; | |
2018 | ||
2019 | CSR_WRITE_4(sc, FXP_CSR_MDICONTROL, | |
2020 | (FXP_MDI_READ << 26) | (reg << 16) | (phy << 21)); | |
2021 | ||
2022 | while (((value = CSR_READ_4(sc, FXP_CSR_MDICONTROL)) & 0x10000000) == 0 | |
2023 | && count--) | |
2024 | DELAY(10); | |
2025 | ||
2026 | if (count <= 0) | |
2027 | device_printf(dev, "fxp_miibus_readreg: timed out\n"); | |
2028 | ||
2029 | return (value & 0xffff); | |
2030 | } | |
2031 | ||
2032 | static void | |
2033 | fxp_miibus_writereg(device_t dev, int phy, int reg, int value) | |
2034 | { | |
2035 | struct fxp_softc *sc = device_get_softc(dev); | |
2036 | int count = 10000; | |
2037 | ||
2038 | CSR_WRITE_4(sc, FXP_CSR_MDICONTROL, | |
2039 | (FXP_MDI_WRITE << 26) | (reg << 16) | (phy << 21) | | |
2040 | (value & 0xffff)); | |
2041 | ||
2042 | while ((CSR_READ_4(sc, FXP_CSR_MDICONTROL) & 0x10000000) == 0 && | |
2043 | count--) | |
2044 | DELAY(10); | |
2045 | ||
2046 | if (count <= 0) | |
2047 | device_printf(dev, "fxp_miibus_writereg: timed out\n"); | |
2048 | } | |
2049 | ||
2050 | static int | |
bd4539cc | 2051 | fxp_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr) |
984263bc MD |
2052 | { |
2053 | struct fxp_softc *sc = ifp->if_softc; | |
2054 | struct ifreq *ifr = (struct ifreq *)data; | |
2055 | struct mii_data *mii; | |
37103068 | 2056 | int error = 0; |
984263bc | 2057 | |
ac72fc11 SZ |
2058 | ASSERT_SERIALIZED(ifp->if_serializer); |
2059 | ||
984263bc | 2060 | switch (command) { |
984263bc MD |
2061 | |
2062 | case SIOCSIFFLAGS: | |
2063 | if (ifp->if_flags & IFF_ALLMULTI) | |
2064 | sc->flags |= FXP_FLAG_ALL_MCAST; | |
2065 | else | |
2066 | sc->flags &= ~FXP_FLAG_ALL_MCAST; | |
2067 | ||
2068 | /* | |
2069 | * If interface is marked up and not running, then start it. | |
2070 | * If it is marked down and running, stop it. | |
2071 | * XXX If it's up then re-initialize it. This is so flags | |
2072 | * such as IFF_PROMISC are handled. | |
2073 | */ | |
2074 | if (ifp->if_flags & IFF_UP) { | |
2075 | fxp_init(sc); | |
2076 | } else { | |
2077 | if (ifp->if_flags & IFF_RUNNING) | |
2078 | fxp_stop(sc); | |
2079 | } | |
2080 | break; | |
2081 | ||
2082 | case SIOCADDMULTI: | |
2083 | case SIOCDELMULTI: | |
2084 | if (ifp->if_flags & IFF_ALLMULTI) | |
2085 | sc->flags |= FXP_FLAG_ALL_MCAST; | |
2086 | else | |
2087 | sc->flags &= ~FXP_FLAG_ALL_MCAST; | |
2088 | /* | |
2089 | * Multicast list has changed; set the hardware filter | |
2090 | * accordingly. | |
2091 | */ | |
2092 | if ((sc->flags & FXP_FLAG_ALL_MCAST) == 0) | |
2093 | fxp_mc_setup(sc); | |
2094 | /* | |
2095 | * fxp_mc_setup() can set FXP_FLAG_ALL_MCAST, so check it | |
2096 | * again rather than else {}. | |
2097 | */ | |
2098 | if (sc->flags & FXP_FLAG_ALL_MCAST) | |
2099 | fxp_init(sc); | |
2100 | error = 0; | |
2101 | break; | |
2102 | ||
2103 | case SIOCSIFMEDIA: | |
2104 | case SIOCGIFMEDIA: | |
2105 | if (sc->miibus != NULL) { | |
2106 | mii = device_get_softc(sc->miibus); | |
2107 | error = ifmedia_ioctl(ifp, ifr, | |
2108 | &mii->mii_media, command); | |
2109 | } else { | |
2110 | error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command); | |
2111 | } | |
2112 | break; | |
2113 | ||
2114 | default: | |
20de928f JS |
2115 | error = ether_ioctl(ifp, command, data); |
2116 | break; | |
984263bc | 2117 | } |
984263bc MD |
2118 | return (error); |
2119 | } | |
2120 | ||
2121 | /* | |
2122 | * Fill in the multicast address list and return number of entries. | |
2123 | */ | |
2124 | static int | |
2125 | fxp_mc_addrs(struct fxp_softc *sc) | |
2126 | { | |
2127 | struct fxp_cb_mcs *mcsp = sc->mcsp; | |
3dc849fa | 2128 | struct ifnet *ifp = &sc->arpcom.ac_if; |
984263bc MD |
2129 | struct ifmultiaddr *ifma; |
2130 | int nmcasts; | |
2131 | ||
2132 | nmcasts = 0; | |
2133 | if ((sc->flags & FXP_FLAG_ALL_MCAST) == 0) { | |
441d34b2 | 2134 | TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { |
984263bc MD |
2135 | if (ifma->ifma_addr->sa_family != AF_LINK) |
2136 | continue; | |
2137 | if (nmcasts >= MAXMCADDR) { | |
2138 | sc->flags |= FXP_FLAG_ALL_MCAST; | |
2139 | nmcasts = 0; | |
2140 | break; | |
2141 | } | |
2142 | bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), | |
2143 | (void *)(uintptr_t)(volatile void *) | |
2144 | &sc->mcsp->mc_addr[nmcasts][0], 6); | |
2145 | nmcasts++; | |
2146 | } | |
2147 | } | |
2148 | mcsp->mc_cnt = nmcasts * 6; | |
2149 | return (nmcasts); | |
2150 | } | |
2151 | ||
2152 | /* | |
2153 | * Program the multicast filter. | |
2154 | * | |
2155 | * We have an artificial restriction that the multicast setup command | |
2156 | * must be the first command in the chain, so we take steps to ensure | |
2157 | * this. By requiring this, it allows us to keep up the performance of | |
2158 | * the pre-initialized command ring (esp. link pointers) by not actually | |
2159 | * inserting the mcsetup command in the ring - i.e. its link pointer | |
2160 | * points to the TxCB ring, but the mcsetup descriptor itself is not part | |
2161 | * of it. We then can do 'CU_START' on the mcsetup descriptor and have it | |
2162 | * lead into the regular TxCB ring when it completes. | |
2163 | * | |
2164 | * This function must be called at splimp. | |
2165 | */ | |
2166 | static void | |
2167 | fxp_mc_setup(struct fxp_softc *sc) | |
2168 | { | |
2169 | struct fxp_cb_mcs *mcsp = sc->mcsp; | |
3dc849fa | 2170 | struct ifnet *ifp = &sc->arpcom.ac_if; |
984263bc MD |
2171 | int count; |
2172 | ||
2173 | /* | |
2174 | * If there are queued commands, we must wait until they are all | |
2175 | * completed. If we are already waiting, then add a NOP command | |
2176 | * with interrupt option so that we're notified when all commands | |
2177 | * have been completed - fxp_start() ensures that no additional | |
2178 | * TX commands will be added when need_mcsetup is true. | |
2179 | */ | |
2180 | if (sc->tx_queued) { | |
2181 | struct fxp_cb_tx *txp; | |
2182 | ||
2183 | /* | |
2184 | * need_mcsetup will be true if we are already waiting for the | |
2185 | * NOP command to be completed (see below). In this case, bail. | |
2186 | */ | |
2187 | if (sc->need_mcsetup) | |
2188 | return; | |
2189 | sc->need_mcsetup = 1; | |
2190 | ||
2191 | /* | |
2192 | * Add a NOP command with interrupt so that we are notified | |
2193 | * when all TX commands have been processed. | |
2194 | */ | |
2195 | txp = sc->cbl_last->next; | |
2196 | txp->mb_head = NULL; | |
2197 | txp->cb_status = 0; | |
2198 | txp->cb_command = FXP_CB_COMMAND_NOP | | |
2199 | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I; | |
2200 | /* | |
2201 | * Advance the end of list forward. | |
2202 | */ | |
2203 | sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S; | |
2204 | sc->cbl_last = txp; | |
2205 | sc->tx_queued++; | |
2206 | /* | |
2207 | * Issue a resume in case the CU has just suspended. | |
2208 | */ | |
2209 | fxp_scb_wait(sc); | |
2210 | fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_RESUME); | |
2211 | /* | |
2212 | * Set a 5 second timer just in case we don't hear from the | |
2213 | * card again. | |
2214 | */ | |
2215 | ifp->if_timer = 5; | |
2216 | ||
2217 | return; | |
2218 | } | |
2219 | sc->need_mcsetup = 0; | |
2220 | ||
2221 | /* | |
2222 | * Initialize multicast setup descriptor. | |
2223 | */ | |
2224 | mcsp->next = sc->cbl_base; | |
2225 | mcsp->mb_head = NULL; | |
2226 | mcsp->cb_status = 0; | |
2227 | mcsp->cb_command = FXP_CB_COMMAND_MCAS | | |
2228 | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I; | |
2229 | mcsp->link_addr = vtophys(&sc->cbl_base->cb_status); | |
7b9f668c | 2230 | fxp_mc_addrs(sc); |
984263bc MD |
2231 | sc->cbl_first = sc->cbl_last = (struct fxp_cb_tx *) mcsp; |
2232 | sc->tx_queued = 1; | |
2233 | ||
2234 | /* | |
2235 | * Wait until command unit is not active. This should never | |
2236 | * be the case when nothing is queued, but make sure anyway. | |
2237 | */ | |
2238 | count = 100; | |
2239 | while ((CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS) >> 6) == | |
2240 | FXP_SCB_CUS_ACTIVE && --count) | |
2241 | DELAY(10); | |
2242 | if (count == 0) { | |
c81df1a6 | 2243 | if_printf(&sc->arpcom.ac_if, "command queue timeout\n"); |
984263bc MD |
2244 | return; |
2245 | } | |
2246 | ||
2247 | /* | |
2248 | * Start the multicast setup command. | |
2249 | */ | |
2250 | fxp_scb_wait(sc); | |
2251 | CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&mcsp->cb_status)); | |
2252 | fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_START); | |
2253 | ||
2254 | ifp->if_timer = 2; | |
2255 | return; | |
2256 | } | |
2257 | ||
2258 | static u_int32_t fxp_ucode_d101a[] = D101_A_RCVBUNDLE_UCODE; | |
2259 | static u_int32_t fxp_ucode_d101b0[] = D101_B0_RCVBUNDLE_UCODE; | |
2260 | static u_int32_t fxp_ucode_d101ma[] = D101M_B_RCVBUNDLE_UCODE; | |
2261 | static u_int32_t fxp_ucode_d101s[] = D101S_RCVBUNDLE_UCODE; | |
2262 | static u_int32_t fxp_ucode_d102[] = D102_B_RCVBUNDLE_UCODE; | |
2263 | static u_int32_t fxp_ucode_d102c[] = D102_C_RCVBUNDLE_UCODE; | |
2264 | ||
2265 | #define UCODE(x) x, sizeof(x) | |
2266 | ||
2267 | struct ucode { | |
2268 | u_int32_t revision; | |
2269 | u_int32_t *ucode; | |
2270 | int length; | |
2271 | u_short int_delay_offset; | |
2272 | u_short bundle_max_offset; | |
2273 | } ucode_table[] = { | |
2274 | { FXP_REV_82558_A4, UCODE(fxp_ucode_d101a), D101_CPUSAVER_DWORD, 0 }, | |
2275 | { FXP_REV_82558_B0, UCODE(fxp_ucode_d101b0), D101_CPUSAVER_DWORD, 0 }, | |
2276 | { FXP_REV_82559_A0, UCODE(fxp_ucode_d101ma), | |
2277 | D101M_CPUSAVER_DWORD, D101M_CPUSAVER_BUNDLE_MAX_DWORD }, | |
2278 | { FXP_REV_82559S_A, UCODE(fxp_ucode_d101s), | |
2279 | D101S_CPUSAVER_DWORD, D101S_CPUSAVER_BUNDLE_MAX_DWORD }, | |
2280 | { FXP_REV_82550, UCODE(fxp_ucode_d102), | |
2281 | D102_B_CPUSAVER_DWORD, D102_B_CPUSAVER_BUNDLE_MAX_DWORD }, | |
2282 | { FXP_REV_82550_C, UCODE(fxp_ucode_d102c), | |
2283 | D102_C_CPUSAVER_DWORD, D102_C_CPUSAVER_BUNDLE_MAX_DWORD }, | |
2284 | { 0, NULL, 0, 0, 0 } | |
2285 | }; | |
2286 | ||
2287 | static void | |
2288 | fxp_load_ucode(struct fxp_softc *sc) | |
2289 | { | |
2290 | struct ucode *uc; | |
2291 | struct fxp_cb_ucode *cbp; | |
2292 | ||
2293 | for (uc = ucode_table; uc->ucode != NULL; uc++) | |
2294 | if (sc->revision == uc->revision) | |
2295 | break; | |
2296 | if (uc->ucode == NULL) | |
2297 | return; | |
2298 | cbp = (struct fxp_cb_ucode *)sc->cbl_base; | |
2299 | cbp->cb_status = 0; | |
2300 | cbp->cb_command = FXP_CB_COMMAND_UCODE | FXP_CB_COMMAND_EL; | |
2301 | cbp->link_addr = -1; /* (no) next command */ | |
2302 | memcpy(cbp->ucode, uc->ucode, uc->length); | |
2303 | if (uc->int_delay_offset) | |
2304 | *(u_short *)&cbp->ucode[uc->int_delay_offset] = | |
2305 | sc->tunable_int_delay + sc->tunable_int_delay / 2; | |
2306 | if (uc->bundle_max_offset) | |
2307 | *(u_short *)&cbp->ucode[uc->bundle_max_offset] = | |
2308 | sc->tunable_bundle_max; | |
2309 | /* | |
2310 | * Download the ucode to the chip. | |
2311 | */ | |
2312 | fxp_scb_wait(sc); | |
2313 | CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&cbp->cb_status)); | |
2314 | fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_START); | |
2315 | /* ...and wait for it to complete. */ | |
2316 | fxp_dma_wait(&cbp->cb_status, sc); | |
c81df1a6 | 2317 | if_printf(&sc->arpcom.ac_if, |
984263bc MD |
2318 | "Microcode loaded, int_delay: %d usec bundle_max: %d\n", |
2319 | sc->tunable_int_delay, | |
2320 | uc->bundle_max_offset == 0 ? 0 : sc->tunable_bundle_max); | |
2321 | sc->flags |= FXP_FLAG_UCODE; | |
2322 | } | |
2323 | ||
984263bc MD |
2324 | /* |
2325 | * Interrupt delay is expressed in microseconds, a multiplier is used | |
2326 | * to convert this to the appropriate clock ticks before using. | |
2327 | */ | |
2328 | static int | |
2329 | sysctl_hw_fxp_int_delay(SYSCTL_HANDLER_ARGS) | |
2330 | { | |
2331 | return (sysctl_int_range(oidp, arg1, arg2, req, 300, 3000)); | |
2332 | } | |
2333 | ||
2334 | static int | |
2335 | sysctl_hw_fxp_bundle_max(SYSCTL_HANDLER_ARGS) | |
2336 | { | |
2337 | return (sysctl_int_range(oidp, arg1, arg2, req, 1, 0xffff)); | |
2338 | } |