File: | dev/pci/if_cas.c |
Warning: | line 865, column 2 Value stored to 'rxs' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: if_cas.c,v 1.55 2023/11/10 15:51:20 bluhm Exp $ */ |
2 | |
3 | /* |
4 | * |
5 | * Copyright (C) 2007 Mark Kettenis. |
6 | * Copyright (C) 2001 Eduardo Horvath. |
7 | * All rights reserved. |
8 | * |
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 AUTHOR ``AS IS'' AND |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 | * SUCH DAMAGE. |
30 | * |
31 | */ |
32 | |
33 | /* |
34 | * Driver for Sun Cassini ethernet controllers. |
35 | * |
36 | * There are basically two variants of this chip: Cassini and |
37 | * Cassini+. We can distinguish between the two by revision: 0x10 and |
38 | * up are Cassini+. The most important difference is that Cassini+ |
39 | * has a second RX descriptor ring. Cassini+ will not work without |
40 | * configuring that second ring. However, since we don't use it we |
41 | * don't actually fill the descriptors, and only hand off the first |
42 | * four to the chip. |
43 | */ |
44 | |
45 | #include "bpfilter.h" |
46 | |
47 | #include <sys/param.h> |
48 | #include <sys/systm.h> |
49 | #include <sys/timeout.h> |
50 | #include <sys/mbuf.h> |
51 | #include <sys/syslog.h> |
52 | #include <sys/malloc.h> |
53 | #include <sys/kernel.h> |
54 | #include <sys/socket.h> |
55 | #include <sys/ioctl.h> |
56 | #include <sys/errno.h> |
57 | #include <sys/device.h> |
58 | #include <sys/endian.h> |
59 | #include <sys/atomic.h> |
60 | |
61 | #include <net/if.h> |
62 | #include <net/if_media.h> |
63 | |
64 | #include <netinet/in.h> |
65 | #include <netinet/if_ether.h> |
66 | |
67 | #if NBPFILTER1 > 0 |
68 | #include <net/bpf.h> |
69 | #endif |
70 | |
71 | #include <machine/bus.h> |
72 | #include <machine/intr.h> |
73 | |
74 | #include <dev/mii/mii.h> |
75 | #include <dev/mii/miivar.h> |
76 | |
77 | #include <dev/pci/if_casreg.h> |
78 | #include <dev/pci/if_casvar.h> |
79 | |
80 | #include <dev/pci/pcivar.h> |
81 | #include <dev/pci/pcireg.h> |
82 | #include <dev/pci/pcidevs.h> |
83 | |
84 | #ifdef __sparc64__ |
85 | #include <dev/ofw/openfirm.h> |
86 | #endif |
87 | |
88 | #define TRIES10000 10000 |
89 | |
90 | struct cfdriver cas_cd = { |
91 | NULL((void *)0), "cas", DV_IFNET |
92 | }; |
93 | |
94 | int cas_match(struct device *, void *, void *); |
95 | void cas_attach(struct device *, struct device *, void *); |
96 | int cas_pci_enaddr(struct cas_softc *, struct pci_attach_args *); |
97 | |
98 | const struct cfattach cas_ca = { |
99 | sizeof(struct cas_softc), cas_match, cas_attach |
100 | }; |
101 | |
102 | void cas_config(struct cas_softc *); |
103 | void cas_start(struct ifnet *); |
104 | void cas_stop(struct ifnet *, int); |
105 | int cas_ioctl(struct ifnet *, u_long, caddr_t); |
106 | void cas_tick(void *); |
107 | void cas_watchdog(struct ifnet *); |
108 | int cas_init(struct ifnet *); |
109 | void cas_init_regs(struct cas_softc *); |
110 | int cas_ringsize(int); |
111 | int cas_cringsize(int); |
112 | int cas_meminit(struct cas_softc *); |
113 | void cas_mifinit(struct cas_softc *); |
114 | int cas_bitwait(struct cas_softc *, bus_space_handle_t, int, |
115 | u_int32_t, u_int32_t); |
116 | void cas_reset(struct cas_softc *); |
117 | int cas_reset_rx(struct cas_softc *); |
118 | int cas_reset_tx(struct cas_softc *); |
119 | int cas_disable_rx(struct cas_softc *); |
120 | int cas_disable_tx(struct cas_softc *); |
121 | void cas_rxdrain(struct cas_softc *); |
122 | int cas_add_rxbuf(struct cas_softc *, int idx); |
123 | void cas_iff(struct cas_softc *); |
124 | int cas_encap(struct cas_softc *, struct mbuf *, int *); |
125 | |
126 | /* MII methods & callbacks */ |
127 | int cas_mii_readreg(struct device *, int, int); |
128 | void cas_mii_writereg(struct device *, int, int, int); |
129 | void cas_mii_statchg(struct device *); |
130 | int cas_pcs_readreg(struct device *, int, int); |
131 | void cas_pcs_writereg(struct device *, int, int, int); |
132 | |
133 | int cas_mediachange(struct ifnet *); |
134 | void cas_mediastatus(struct ifnet *, struct ifmediareq *); |
135 | |
136 | int cas_eint(struct cas_softc *, u_int); |
137 | int cas_rint(struct cas_softc *); |
138 | int cas_tint(struct cas_softc *, u_int32_t); |
139 | int cas_pint(struct cas_softc *); |
140 | int cas_intr(void *); |
141 | |
142 | #ifdef CAS_DEBUG |
143 | #define DPRINTF(sc, x) if ((sc)->sc_arpcom.ac_if.if_flags & IFF_DEBUG0x4) \ |
144 | printf x |
145 | #else |
146 | #define DPRINTF(sc, x) /* nothing */ |
147 | #endif |
148 | |
149 | const struct pci_matchid cas_pci_devices[] = { |
150 | { PCI_VENDOR_SUN0x108e, PCI_PRODUCT_SUN_CASSINI0xabba }, |
151 | { PCI_VENDOR_NS0x100b, PCI_PRODUCT_NS_SATURN0x0035 } |
152 | }; |
153 | |
154 | int |
155 | cas_match(struct device *parent, void *cf, void *aux) |
156 | { |
157 | return (pci_matchbyid((struct pci_attach_args *)aux, cas_pci_devices, |
158 | nitems(cas_pci_devices)(sizeof((cas_pci_devices)) / sizeof((cas_pci_devices)[0])))); |
159 | } |
160 | |
161 | #define PROMHDR_PTR_DATA0x18 0x18 |
162 | #define PROMDATA_PTR_VPD0x08 0x08 |
163 | #define PROMDATA_DATA20x0a 0x0a |
164 | |
165 | static const u_int8_t cas_promhdr[] = { 0x55, 0xaa }; |
166 | static const u_int8_t cas_promdat_sun[] = { |
167 | 'P', 'C', 'I', 'R', |
168 | PCI_VENDOR_SUN0x108e & 0xff, PCI_VENDOR_SUN0x108e >> 8, |
169 | PCI_PRODUCT_SUN_CASSINI0xabba & 0xff, PCI_PRODUCT_SUN_CASSINI0xabba >> 8 |
170 | }; |
171 | static const u_int8_t cas_promdat_ns[] = { |
172 | 'P', 'C', 'I', 'R', |
173 | PCI_VENDOR_NS0x100b & 0xff, PCI_VENDOR_NS0x100b >> 8, |
174 | PCI_PRODUCT_NS_SATURN0x0035 & 0xff, PCI_PRODUCT_NS_SATURN0x0035 >> 8 |
175 | }; |
176 | |
177 | static const u_int8_t cas_promdat2[] = { |
178 | 0x18, 0x00, /* structure length */ |
179 | 0x00, /* structure revision */ |
180 | 0x00, /* interface revision */ |
181 | PCI_SUBCLASS_NETWORK_ETHERNET0x00, /* subclass code */ |
182 | PCI_CLASS_NETWORK0x02 /* class code */ |
183 | }; |
184 | |
185 | int |
186 | cas_pci_enaddr(struct cas_softc *sc, struct pci_attach_args *pa) |
187 | { |
188 | struct pci_vpd_largeres *res; |
189 | struct pci_vpd *vpd; |
190 | bus_space_handle_t romh; |
191 | bus_space_tag_t romt; |
192 | bus_size_t romsize = 0; |
193 | u_int8_t buf[32], *desc; |
194 | pcireg_t address; |
195 | int dataoff, vpdoff, len; |
196 | int rv = -1; |
197 | |
198 | if (pci_mapreg_map(pa, PCI_ROM_REG0x30, PCI_MAPREG_TYPE_MEM0x00000000, 0, |
199 | &romt, &romh, 0, &romsize, 0)) |
200 | return (-1); |
201 | |
202 | address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG0x30); |
203 | address |= PCI_ROM_ENABLE0x00000001; |
204 | pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG0x30, address); |
205 | |
206 | bus_space_read_region_1(romt, romh, 0, buf, sizeof(buf))((romt)->read_region_1((romh), (0), (buf), (sizeof(buf)))); |
207 | if (bcmp(buf, cas_promhdr, sizeof(cas_promhdr))) |
208 | goto fail; |
209 | |
210 | dataoff = buf[PROMHDR_PTR_DATA0x18] | (buf[PROMHDR_PTR_DATA0x18 + 1] << 8); |
211 | if (dataoff < 0x1c) |
212 | goto fail; |
213 | |
214 | bus_space_read_region_1(romt, romh, dataoff, buf, sizeof(buf))((romt)->read_region_1((romh), (dataoff), (buf), (sizeof(buf )))); |
215 | if ((bcmp(buf, cas_promdat_sun, sizeof(cas_promdat_sun)) && |
216 | bcmp(buf, cas_promdat_ns, sizeof(cas_promdat_ns))) || |
217 | bcmp(buf + PROMDATA_DATA20x0a, cas_promdat2, sizeof(cas_promdat2))) |
218 | goto fail; |
219 | |
220 | vpdoff = buf[PROMDATA_PTR_VPD0x08] | (buf[PROMDATA_PTR_VPD0x08 + 1] << 8); |
221 | if (vpdoff < 0x1c) |
222 | goto fail; |
223 | |
224 | next: |
225 | bus_space_read_region_1(romt, romh, vpdoff, buf, sizeof(buf))((romt)->read_region_1((romh), (vpdoff), (buf), (sizeof(buf )))); |
226 | if (!PCI_VPDRES_ISLARGE(buf[0])((buf[0]) & 0x80)) |
227 | goto fail; |
228 | |
229 | res = (struct pci_vpd_largeres *)buf; |
230 | vpdoff += sizeof(*res); |
231 | |
232 | len = ((res->vpdres_len_msb << 8) + res->vpdres_len_lsb); |
233 | switch(PCI_VPDRES_LARGE_NAME(res->vpdres_byte0)((res->vpdres_byte0) & 0x7f)) { |
234 | case PCI_VPDRES_TYPE_IDENTIFIER_STRING0x02: |
235 | /* Skip identifier string. */ |
236 | vpdoff += len; |
237 | goto next; |
238 | |
239 | case PCI_VPDRES_TYPE_VPD0x10: |
240 | while (len > 0) { |
241 | bus_space_read_region_1(romt, romh, vpdoff,((romt)->read_region_1((romh), (vpdoff), (buf), (sizeof(buf )))) |
242 | buf, sizeof(buf))((romt)->read_region_1((romh), (vpdoff), (buf), (sizeof(buf )))); |
243 | |
244 | vpd = (struct pci_vpd *)buf; |
245 | vpdoff += sizeof(*vpd) + vpd->vpd_len; |
246 | len -= sizeof(*vpd) + vpd->vpd_len; |
247 | |
248 | /* |
249 | * We're looking for an "Enhanced" VPD... |
250 | */ |
251 | if (vpd->vpd_key0 != 'Z') |
252 | continue; |
253 | |
254 | desc = buf + sizeof(*vpd); |
255 | |
256 | /* |
257 | * ...which is an instance property... |
258 | */ |
259 | if (desc[0] != 'I') |
260 | continue; |
261 | desc += 3; |
262 | |
263 | /* |
264 | * ...that's a byte array with the proper |
265 | * length for a MAC address... |
266 | */ |
267 | if (desc[0] != 'B' || desc[1] != ETHER_ADDR_LEN6) |
268 | continue; |
269 | desc += 2; |
270 | |
271 | /* |
272 | * ...named "local-mac-address". |
273 | */ |
274 | if (strcmp(desc, "local-mac-address") != 0) |
275 | continue; |
276 | desc += strlen("local-mac-address") + 1; |
277 | |
278 | bcopy(desc, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN6); |
279 | sc->sc_arpcom.ac_enaddr[5] += pa->pa_device; |
280 | rv = 0; |
281 | } |
282 | break; |
283 | |
284 | default: |
285 | goto fail; |
286 | } |
287 | |
288 | fail: |
289 | if (romsize != 0) |
290 | bus_space_unmap(romt, romh, romsize); |
291 | |
292 | address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG0x30); |
293 | address &= ~PCI_ROM_ENABLE0x00000001; |
294 | pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG0x30, address); |
295 | |
296 | return (rv); |
297 | } |
298 | |
299 | void |
300 | cas_attach(struct device *parent, struct device *self, void *aux) |
301 | { |
302 | struct pci_attach_args *pa = aux; |
303 | struct cas_softc *sc = (void *)self; |
304 | pci_intr_handle_t ih; |
305 | #ifdef __sparc64__ |
306 | /* XXX the following declarations should be elsewhere */ |
307 | extern void myetheraddr(u_char *); |
308 | #endif |
309 | const char *intrstr = NULL((void *)0); |
310 | bus_size_t size; |
311 | int gotenaddr = 0; |
312 | |
313 | sc->sc_rev = PCI_REVISION(pa->pa_class)(((pa->pa_class) >> 0) & 0xff); |
314 | sc->sc_dmatag = pa->pa_dmat; |
315 | |
316 | #define PCI_CAS_BASEADDR0x10 0x10 |
317 | if (pci_mapreg_map(pa, PCI_CAS_BASEADDR0x10, PCI_MAPREG_TYPE_MEM0x00000000, 0, |
318 | &sc->sc_memt, &sc->sc_memh, NULL((void *)0), &size, 0) != 0) { |
319 | printf(": can't map registers\n"); |
320 | return; |
321 | } |
322 | |
323 | if (cas_pci_enaddr(sc, pa) == 0) |
324 | gotenaddr = 1; |
325 | |
326 | #ifdef __sparc64__ |
327 | if (!gotenaddr) { |
328 | if (OF_getprop(PCITAG_NODE(pa->pa_tag), "local-mac-address", |
329 | sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN6) <= 0) |
330 | myetheraddr(sc->sc_arpcom.ac_enaddr); |
331 | gotenaddr = 1; |
332 | } |
333 | #endif |
334 | #ifdef __powerpc__ |
335 | if (!gotenaddr) { |
336 | pci_ether_hw_addr(pa->pa_pc, sc->sc_arpcom.ac_enaddr); |
337 | gotenaddr = 1; |
338 | } |
339 | #endif |
340 | |
341 | sc->sc_burst = 16; /* XXX */ |
342 | |
343 | if (pci_intr_map(pa, &ih) != 0) { |
344 | printf(": couldn't map interrupt\n"); |
345 | bus_space_unmap(sc->sc_memt, sc->sc_memh, size); |
346 | return; |
347 | } |
348 | intrstr = pci_intr_string(pa->pa_pc, ih); |
349 | sc->sc_ih = pci_intr_establish(pa->pa_pc, |
350 | ih, IPL_NET0x4 | IPL_MPSAFE0x100, cas_intr, sc, self->dv_xname); |
351 | if (sc->sc_ih == NULL((void *)0)) { |
352 | printf(": couldn't establish interrupt"); |
353 | if (intrstr != NULL((void *)0)) |
354 | printf(" at %s", intrstr); |
355 | printf("\n"); |
356 | bus_space_unmap(sc->sc_memt, sc->sc_memh, size); |
357 | return; |
358 | } |
359 | |
360 | printf(": %s", intrstr); |
361 | |
362 | /* |
363 | * call the main configure |
364 | */ |
365 | cas_config(sc); |
366 | } |
367 | |
368 | /* |
369 | * cas_config: |
370 | * |
371 | * Attach a Cassini interface to the system. |
372 | */ |
373 | void |
374 | cas_config(struct cas_softc *sc) |
375 | { |
376 | struct ifnet *ifp = &sc->sc_arpcom.ac_if; |
377 | struct mii_data *mii = &sc->sc_mii; |
378 | struct mii_softc *child; |
379 | int i, error; |
380 | |
381 | /* Make sure the chip is stopped. */ |
382 | ifp->if_softc = sc; |
383 | cas_reset(sc); |
384 | |
385 | /* |
386 | * Allocate the control data structures, and create and load the |
387 | * DMA map for it. |
388 | */ |
389 | if ((error = bus_dmamem_alloc(sc->sc_dmatag,(*(sc->sc_dmatag)->_dmamem_alloc)((sc->sc_dmatag), ( sizeof(struct cas_control_data)), (8192), (0), (&sc->sc_cdseg ), (1), (&sc->sc_cdnseg), (0x1000)) |
390 | sizeof(struct cas_control_data), CAS_PAGE_SIZE, 0, &sc->sc_cdseg,(*(sc->sc_dmatag)->_dmamem_alloc)((sc->sc_dmatag), ( sizeof(struct cas_control_data)), (8192), (0), (&sc->sc_cdseg ), (1), (&sc->sc_cdnseg), (0x1000)) |
391 | 1, &sc->sc_cdnseg, BUS_DMA_ZERO)(*(sc->sc_dmatag)->_dmamem_alloc)((sc->sc_dmatag), ( sizeof(struct cas_control_data)), (8192), (0), (&sc->sc_cdseg ), (1), (&sc->sc_cdnseg), (0x1000))) != 0) { |
392 | printf("\n%s: unable to allocate control data, error = %d\n", |
393 | sc->sc_dev.dv_xname, error); |
394 | goto fail_0; |
395 | } |
396 | |
397 | /* XXX should map this in with correct endianness */ |
398 | if ((error = bus_dmamem_map(sc->sc_dmatag, &sc->sc_cdseg, sc->sc_cdnseg,(*(sc->sc_dmatag)->_dmamem_map)((sc->sc_dmatag), (& sc->sc_cdseg), (sc->sc_cdnseg), (sizeof(struct cas_control_data )), ((caddr_t *)&sc->sc_control_data), (0x0004)) |
399 | sizeof(struct cas_control_data), (caddr_t *)&sc->sc_control_data,(*(sc->sc_dmatag)->_dmamem_map)((sc->sc_dmatag), (& sc->sc_cdseg), (sc->sc_cdnseg), (sizeof(struct cas_control_data )), ((caddr_t *)&sc->sc_control_data), (0x0004)) |
400 | BUS_DMA_COHERENT)(*(sc->sc_dmatag)->_dmamem_map)((sc->sc_dmatag), (& sc->sc_cdseg), (sc->sc_cdnseg), (sizeof(struct cas_control_data )), ((caddr_t *)&sc->sc_control_data), (0x0004))) != 0) { |
401 | printf("\n%s: unable to map control data, error = %d\n", |
402 | sc->sc_dev.dv_xname, error); |
403 | goto fail_1; |
404 | } |
405 | |
406 | if ((error = bus_dmamap_create(sc->sc_dmatag,(*(sc->sc_dmatag)->_dmamap_create)((sc->sc_dmatag), ( sizeof(struct cas_control_data)), (1), (sizeof(struct cas_control_data )), (0), (0), (&sc->sc_cddmamap)) |
407 | sizeof(struct cas_control_data), 1,(*(sc->sc_dmatag)->_dmamap_create)((sc->sc_dmatag), ( sizeof(struct cas_control_data)), (1), (sizeof(struct cas_control_data )), (0), (0), (&sc->sc_cddmamap)) |
408 | sizeof(struct cas_control_data), 0, 0, &sc->sc_cddmamap)(*(sc->sc_dmatag)->_dmamap_create)((sc->sc_dmatag), ( sizeof(struct cas_control_data)), (1), (sizeof(struct cas_control_data )), (0), (0), (&sc->sc_cddmamap))) != 0) { |
409 | printf("\n%s: unable to create control data DMA map, " |
410 | "error = %d\n", sc->sc_dev.dv_xname, error); |
411 | goto fail_2; |
412 | } |
413 | |
414 | if ((error = bus_dmamap_load(sc->sc_dmatag, sc->sc_cddmamap,(*(sc->sc_dmatag)->_dmamap_load)((sc->sc_dmatag), (sc ->sc_cddmamap), (sc->sc_control_data), (sizeof(struct cas_control_data )), (((void *)0)), (0)) |
415 | sc->sc_control_data, sizeof(struct cas_control_data), NULL,(*(sc->sc_dmatag)->_dmamap_load)((sc->sc_dmatag), (sc ->sc_cddmamap), (sc->sc_control_data), (sizeof(struct cas_control_data )), (((void *)0)), (0)) |
416 | 0)(*(sc->sc_dmatag)->_dmamap_load)((sc->sc_dmatag), (sc ->sc_cddmamap), (sc->sc_control_data), (sizeof(struct cas_control_data )), (((void *)0)), (0))) != 0) { |
417 | printf("\n%s: unable to load control data DMA map, error = %d\n", |
418 | sc->sc_dev.dv_xname, error); |
419 | goto fail_3; |
420 | } |
421 | |
422 | /* |
423 | * Create the receive buffer DMA maps. |
424 | */ |
425 | for (i = 0; i < CAS_NRXDESC128; i++) { |
426 | bus_dma_segment_t seg; |
427 | caddr_t kva; |
428 | int rseg; |
429 | |
430 | if ((error = bus_dmamem_alloc(sc->sc_dmatag, CAS_PAGE_SIZE,(*(sc->sc_dmatag)->_dmamem_alloc)((sc->sc_dmatag), ( 8192), (8192), (0), (&seg), (1), (&rseg), (0x0001)) |
431 | CAS_PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)(*(sc->sc_dmatag)->_dmamem_alloc)((sc->sc_dmatag), ( 8192), (8192), (0), (&seg), (1), (&rseg), (0x0001))) != 0) { |
432 | printf("\n%s: unable to alloc rx DMA mem %d, " |
433 | "error = %d\n", sc->sc_dev.dv_xname, i, error); |
434 | goto fail_5; |
435 | } |
436 | sc->sc_rxsoft[i].rxs_dmaseg = seg; |
437 | |
438 | if ((error = bus_dmamem_map(sc->sc_dmatag, &seg, rseg,(*(sc->sc_dmatag)->_dmamem_map)((sc->sc_dmatag), (& seg), (rseg), (8192), (&kva), (0x0001)) |
439 | CAS_PAGE_SIZE, &kva, BUS_DMA_NOWAIT)(*(sc->sc_dmatag)->_dmamem_map)((sc->sc_dmatag), (& seg), (rseg), (8192), (&kva), (0x0001))) != 0) { |
440 | printf("\n%s: unable to alloc rx DMA mem %d, " |
441 | "error = %d\n", sc->sc_dev.dv_xname, i, error); |
442 | goto fail_5; |
443 | } |
444 | sc->sc_rxsoft[i].rxs_kva = kva; |
445 | |
446 | if ((error = bus_dmamap_create(sc->sc_dmatag, CAS_PAGE_SIZE, 1,(*(sc->sc_dmatag)->_dmamap_create)((sc->sc_dmatag), ( 8192), (1), (8192), (0), (0), (&sc->sc_rxsoft[i].rxs_dmamap )) |
447 | CAS_PAGE_SIZE, 0, 0, &sc->sc_rxsoft[i].rxs_dmamap)(*(sc->sc_dmatag)->_dmamap_create)((sc->sc_dmatag), ( 8192), (1), (8192), (0), (0), (&sc->sc_rxsoft[i].rxs_dmamap ))) != 0) { |
448 | printf("\n%s: unable to create rx DMA map %d, " |
449 | "error = %d\n", sc->sc_dev.dv_xname, i, error); |
450 | goto fail_5; |
451 | } |
452 | |
453 | if ((error = bus_dmamap_load(sc->sc_dmatag,(*(sc->sc_dmatag)->_dmamap_load)((sc->sc_dmatag), (sc ->sc_rxsoft[i].rxs_dmamap), (kva), (8192), (((void *)0)), ( 0x0001)) |
454 | sc->sc_rxsoft[i].rxs_dmamap, kva, CAS_PAGE_SIZE, NULL,(*(sc->sc_dmatag)->_dmamap_load)((sc->sc_dmatag), (sc ->sc_rxsoft[i].rxs_dmamap), (kva), (8192), (((void *)0)), ( 0x0001)) |
455 | BUS_DMA_NOWAIT)(*(sc->sc_dmatag)->_dmamap_load)((sc->sc_dmatag), (sc ->sc_rxsoft[i].rxs_dmamap), (kva), (8192), (((void *)0)), ( 0x0001))) != 0) { |
456 | printf("\n%s: unable to load rx DMA map %d, " |
457 | "error = %d\n", sc->sc_dev.dv_xname, i, error); |
458 | goto fail_5; |
459 | } |
460 | } |
461 | |
462 | /* |
463 | * Create the transmit buffer DMA maps. |
464 | */ |
465 | for (i = 0; i < CAS_NTXDESC(64 * 16); i++) { |
466 | if ((error = bus_dmamap_create(sc->sc_dmatag, MCLBYTES,(*(sc->sc_dmatag)->_dmamap_create)((sc->sc_dmatag), ( (1 << 11)), (16), ((1 << 11)), (0), (0x0001), (& sc->sc_txd[i].sd_map)) |
467 | CAS_NTXSEGS, MCLBYTES, 0, BUS_DMA_NOWAIT,(*(sc->sc_dmatag)->_dmamap_create)((sc->sc_dmatag), ( (1 << 11)), (16), ((1 << 11)), (0), (0x0001), (& sc->sc_txd[i].sd_map)) |
468 | &sc->sc_txd[i].sd_map)(*(sc->sc_dmatag)->_dmamap_create)((sc->sc_dmatag), ( (1 << 11)), (16), ((1 << 11)), (0), (0x0001), (& sc->sc_txd[i].sd_map))) != 0) { |
469 | printf("\n%s: unable to create tx DMA map %d, " |
470 | "error = %d\n", sc->sc_dev.dv_xname, i, error); |
471 | goto fail_6; |
472 | } |
473 | sc->sc_txd[i].sd_mbuf = NULL((void *)0); |
474 | } |
475 | |
476 | /* |
477 | * From this point forward, the attachment cannot fail. A failure |
478 | * before this point releases all resources that may have been |
479 | * allocated. |
480 | */ |
481 | |
482 | /* Announce ourselves. */ |
483 | printf(", address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr)); |
484 | |
485 | /* Get RX FIFO size */ |
486 | sc->sc_rxfifosize = 16 * 1024; |
487 | |
488 | /* Initialize ifnet structure. */ |
489 | strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, sizeof ifp->if_xname); |
490 | ifp->if_softc = sc; |
491 | ifp->if_flags = |
492 | IFF_BROADCAST0x2 | IFF_SIMPLEX0x800 | IFF_MULTICAST0x8000; |
493 | ifp->if_start = cas_start; |
494 | ifp->if_ioctl = cas_ioctl; |
495 | ifp->if_watchdog = cas_watchdog; |
496 | ifq_init_maxlen(&ifp->if_snd, CAS_NTXDESC(64 * 16) - 1); |
497 | |
498 | ifp->if_capabilitiesif_data.ifi_capabilities = IFCAP_VLAN_MTU0x00000010; |
499 | |
500 | /* Initialize ifmedia structures and MII info */ |
501 | mii->mii_ifp = ifp; |
502 | mii->mii_readreg = cas_mii_readreg; |
503 | mii->mii_writereg = cas_mii_writereg; |
504 | mii->mii_statchg = cas_mii_statchg; |
505 | |
506 | ifmedia_init(&mii->mii_media, 0, cas_mediachange, cas_mediastatus); |
507 | |
508 | bus_space_write_4(sc->sc_memt, sc->sc_memh, CAS_MII_DATAPATH_MODE, 0)((sc->sc_memt)->write_4((sc->sc_memh), (0x9050), (0) )); |
509 | |
510 | cas_mifinit(sc); |
511 | |
512 | if (sc->sc_mif_config & CAS_MIF_CONFIG_MDI10x00000200) { |
513 | sc->sc_mif_config |= CAS_MIF_CONFIG_PHY_SEL0x00000001; |
514 | bus_space_write_4(sc->sc_memt, sc->sc_memh,((sc->sc_memt)->write_4((sc->sc_memh), (0x6210), (sc ->sc_mif_config))) |
515 | CAS_MIF_CONFIG, sc->sc_mif_config)((sc->sc_memt)->write_4((sc->sc_memh), (0x6210), (sc ->sc_mif_config))); |
516 | } |
517 | |
518 | mii_attach(&sc->sc_dev, mii, 0xffffffff, MII_PHY_ANY-1, |
519 | MII_OFFSET_ANY-1, 0); |
520 | |
521 | child = LIST_FIRST(&mii->mii_phys)((&mii->mii_phys)->lh_first); |
522 | if (child == NULL((void *)0) && |
523 | sc->sc_mif_config & (CAS_MIF_CONFIG_MDI00x00000100|CAS_MIF_CONFIG_MDI10x00000200)) { |
524 | /* |
525 | * Try the external PCS SERDES if we didn't find any |
526 | * MII devices. |
527 | */ |
528 | bus_space_write_4(sc->sc_memt, sc->sc_memh,((sc->sc_memt)->write_4((sc->sc_memh), (0x9050), (0x00000002 ))) |
529 | CAS_MII_DATAPATH_MODE, CAS_MII_DATAPATH_SERDES)((sc->sc_memt)->write_4((sc->sc_memh), (0x9050), (0x00000002 ))); |
530 | |
531 | bus_space_write_4(sc->sc_memt, sc->sc_memh,((sc->sc_memt)->write_4((sc->sc_memh), (0x9010), (0x00000001 ))) |
532 | CAS_MII_CONFIG, CAS_MII_CONFIG_ENABLE)((sc->sc_memt)->write_4((sc->sc_memh), (0x9010), (0x00000001 ))); |
533 | |
534 | mii->mii_readreg = cas_pcs_readreg; |
535 | mii->mii_writereg = cas_pcs_writereg; |
536 | |
537 | mii_attach(&sc->sc_dev, mii, 0xffffffff, MII_PHY_ANY-1, |
538 | MII_OFFSET_ANY-1, MIIF_NOISOLATE0x0002); |
539 | } |
540 | |
541 | child = LIST_FIRST(&mii->mii_phys)((&mii->mii_phys)->lh_first); |
542 | if (child == NULL((void *)0)) { |
543 | /* No PHY attached */ |
544 | ifmedia_add(&sc->sc_mediasc_mii.mii_media, IFM_ETHER0x0000000000000100ULL|IFM_MANUAL1ULL, 0, NULL((void *)0)); |
545 | ifmedia_set(&sc->sc_mediasc_mii.mii_media, IFM_ETHER0x0000000000000100ULL|IFM_MANUAL1ULL); |
546 | } else { |
547 | /* |
548 | * Walk along the list of attached MII devices and |
549 | * establish an `MII instance' to `phy number' |
550 | * mapping. We'll use this mapping in media change |
551 | * requests to determine which phy to use to program |
552 | * the MIF configuration register. |
553 | */ |
554 | for (; child != NULL((void *)0); child = LIST_NEXT(child, mii_list)((child)->mii_list.le_next)) { |
555 | /* |
556 | * Note: we support just two PHYs: the built-in |
557 | * internal device and an external on the MII |
558 | * connector. |
559 | */ |
560 | if (child->mii_phy > 1 || child->mii_inst > 1) { |
561 | printf("%s: cannot accommodate MII device %s" |
562 | " at phy %d, instance %lld\n", |
563 | sc->sc_dev.dv_xname, |
564 | child->mii_dev.dv_xname, |
565 | child->mii_phy, child->mii_inst); |
566 | continue; |
567 | } |
568 | |
569 | sc->sc_phys[child->mii_inst] = child->mii_phy; |
570 | } |
571 | |
572 | /* |
573 | * XXX - we can really do the following ONLY if the |
574 | * phy indeed has the auto negotiation capability!! |
575 | */ |
576 | ifmedia_set(&sc->sc_mediasc_mii.mii_media, IFM_ETHER0x0000000000000100ULL|IFM_AUTO0ULL); |
577 | } |
578 | |
579 | /* Attach the interface. */ |
580 | if_attach(ifp); |
581 | ether_ifattach(ifp); |
582 | |
583 | timeout_set(&sc->sc_tick_ch, cas_tick, sc); |
584 | return; |
585 | |
586 | /* |
587 | * Free any resources we've allocated during the failed attach |
588 | * attempt. Do this in reverse order and fall through. |
589 | */ |
590 | fail_6: |
591 | for (i = 0; i < CAS_NTXDESC(64 * 16); i++) { |
592 | if (sc->sc_txd[i].sd_map != NULL((void *)0)) |
593 | bus_dmamap_destroy(sc->sc_dmatag,(*(sc->sc_dmatag)->_dmamap_destroy)((sc->sc_dmatag), (sc->sc_txd[i].sd_map)) |
594 | sc->sc_txd[i].sd_map)(*(sc->sc_dmatag)->_dmamap_destroy)((sc->sc_dmatag), (sc->sc_txd[i].sd_map)); |
595 | } |
596 | fail_5: |
597 | for (i = 0; i < CAS_NRXDESC128; i++) { |
598 | if (sc->sc_rxsoft[i].rxs_dmamap != NULL((void *)0)) |
599 | bus_dmamap_destroy(sc->sc_dmatag,(*(sc->sc_dmatag)->_dmamap_destroy)((sc->sc_dmatag), (sc->sc_rxsoft[i].rxs_dmamap)) |
600 | sc->sc_rxsoft[i].rxs_dmamap)(*(sc->sc_dmatag)->_dmamap_destroy)((sc->sc_dmatag), (sc->sc_rxsoft[i].rxs_dmamap)); |
601 | } |
602 | bus_dmamap_unload(sc->sc_dmatag, sc->sc_cddmamap)(*(sc->sc_dmatag)->_dmamap_unload)((sc->sc_dmatag), ( sc->sc_cddmamap)); |
603 | fail_3: |
604 | bus_dmamap_destroy(sc->sc_dmatag, sc->sc_cddmamap)(*(sc->sc_dmatag)->_dmamap_destroy)((sc->sc_dmatag), (sc->sc_cddmamap)); |
605 | fail_2: |
606 | bus_dmamem_unmap(sc->sc_dmatag, (caddr_t)sc->sc_control_data,(*(sc->sc_dmatag)->_dmamem_unmap)((sc->sc_dmatag), ( (caddr_t)sc->sc_control_data), (sizeof(struct cas_control_data ))) |
607 | sizeof(struct cas_control_data))(*(sc->sc_dmatag)->_dmamem_unmap)((sc->sc_dmatag), ( (caddr_t)sc->sc_control_data), (sizeof(struct cas_control_data ))); |
608 | fail_1: |
609 | bus_dmamem_free(sc->sc_dmatag, &sc->sc_cdseg, sc->sc_cdnseg)(*(sc->sc_dmatag)->_dmamem_free)((sc->sc_dmatag), (& sc->sc_cdseg), (sc->sc_cdnseg)); |
610 | fail_0: |
611 | return; |
612 | } |
613 | |
614 | |
615 | void |
616 | cas_tick(void *arg) |
617 | { |
618 | struct cas_softc *sc = arg; |
619 | struct ifnet *ifp = &sc->sc_arpcom.ac_if; |
620 | bus_space_tag_t t = sc->sc_memt; |
621 | bus_space_handle_t mac = sc->sc_memh; |
622 | int s; |
623 | u_int32_t v; |
624 | |
625 | /* unload collisions counters */ |
626 | v = bus_space_read_4(t, mac, CAS_MAC_EXCESS_COLL_CNT)((t)->read_4((mac), (0x61a8))) + |
627 | bus_space_read_4(t, mac, CAS_MAC_LATE_COLL_CNT)((t)->read_4((mac), (0x61ac))); |
628 | ifp->if_collisionsif_data.ifi_collisions += v + |
629 | bus_space_read_4(t, mac, CAS_MAC_NORM_COLL_CNT)((t)->read_4((mac), (0x61a0))) + |
630 | bus_space_read_4(t, mac, CAS_MAC_FIRST_COLL_CNT)((t)->read_4((mac), (0x61a4))); |
631 | ifp->if_oerrorsif_data.ifi_oerrors += v; |
632 | |
633 | /* read error counters */ |
634 | ifp->if_ierrorsif_data.ifi_ierrors += |
635 | bus_space_read_4(t, mac, CAS_MAC_RX_LEN_ERR_CNT)((t)->read_4((mac), (0x61bc))) + |
636 | bus_space_read_4(t, mac, CAS_MAC_RX_ALIGN_ERR)((t)->read_4((mac), (0x61c0))) + |
637 | bus_space_read_4(t, mac, CAS_MAC_RX_CRC_ERR_CNT)((t)->read_4((mac), (0x61c4))) + |
638 | bus_space_read_4(t, mac, CAS_MAC_RX_CODE_VIOL)((t)->read_4((mac), (0x61c8))); |
639 | |
640 | /* clear the hardware counters */ |
641 | bus_space_write_4(t, mac, CAS_MAC_NORM_COLL_CNT, 0)((t)->write_4((mac), (0x61a0), (0))); |
642 | bus_space_write_4(t, mac, CAS_MAC_FIRST_COLL_CNT, 0)((t)->write_4((mac), (0x61a4), (0))); |
643 | bus_space_write_4(t, mac, CAS_MAC_EXCESS_COLL_CNT, 0)((t)->write_4((mac), (0x61a8), (0))); |
644 | bus_space_write_4(t, mac, CAS_MAC_LATE_COLL_CNT, 0)((t)->write_4((mac), (0x61ac), (0))); |
645 | bus_space_write_4(t, mac, CAS_MAC_RX_LEN_ERR_CNT, 0)((t)->write_4((mac), (0x61bc), (0))); |
646 | bus_space_write_4(t, mac, CAS_MAC_RX_ALIGN_ERR, 0)((t)->write_4((mac), (0x61c0), (0))); |
647 | bus_space_write_4(t, mac, CAS_MAC_RX_CRC_ERR_CNT, 0)((t)->write_4((mac), (0x61c4), (0))); |
648 | bus_space_write_4(t, mac, CAS_MAC_RX_CODE_VIOL, 0)((t)->write_4((mac), (0x61c8), (0))); |
649 | |
650 | s = splnet()splraise(0x4); |
651 | mii_tick(&sc->sc_mii); |
652 | splx(s)spllower(s); |
653 | |
654 | timeout_add_sec(&sc->sc_tick_ch, 1); |
655 | } |
656 | |
657 | int |
658 | cas_bitwait(struct cas_softc *sc, bus_space_handle_t h, int r, |
659 | u_int32_t clr, u_int32_t set) |
660 | { |
661 | int i; |
662 | u_int32_t reg; |
663 | |
664 | for (i = TRIES10000; i--; DELAY(100)(*delay_func)(100)) { |
665 | reg = bus_space_read_4(sc->sc_memt, h, r)((sc->sc_memt)->read_4((h), (r))); |
666 | if ((reg & clr) == 0 && (reg & set) == set) |
667 | return (1); |
668 | } |
669 | |
670 | return (0); |
671 | } |
672 | |
673 | void |
674 | cas_reset(struct cas_softc *sc) |
675 | { |
676 | bus_space_tag_t t = sc->sc_memt; |
677 | bus_space_handle_t h = sc->sc_memh; |
678 | int s; |
679 | |
680 | s = splnet()splraise(0x4); |
681 | DPRINTF(sc, ("%s: cas_reset\n", sc->sc_dev.dv_xname)); |
682 | cas_reset_rx(sc); |
683 | cas_reset_tx(sc); |
684 | |
685 | /* Do a full reset */ |
686 | bus_space_write_4(t, h, CAS_RESET,((t)->write_4((h), (0x1010), (0x000000002 | 0x000000001 | 0x00000008 ))) |
687 | CAS_RESET_RX | CAS_RESET_TX | CAS_RESET_BLOCK_PCS)((t)->write_4((h), (0x1010), (0x000000002 | 0x000000001 | 0x00000008 ))); |
688 | if (!cas_bitwait(sc, h, CAS_RESET0x1010, CAS_RESET_RX0x000000002 | CAS_RESET_TX0x000000001, 0)) |
689 | printf("%s: cannot reset device\n", sc->sc_dev.dv_xname); |
690 | splx(s)spllower(s); |
691 | } |
692 | |
693 | |
694 | /* |
695 | * cas_rxdrain: |
696 | * |
697 | * Drain the receive queue. |
698 | */ |
699 | void |
700 | cas_rxdrain(struct cas_softc *sc) |
701 | { |
702 | /* Nothing to do yet. */ |
703 | } |
704 | |
705 | /* |
706 | * Reset the whole thing. |
707 | */ |
708 | void |
709 | cas_stop(struct ifnet *ifp, int disable) |
710 | { |
711 | struct cas_softc *sc = (struct cas_softc *)ifp->if_softc; |
712 | struct cas_sxd *sd; |
713 | u_int32_t i; |
714 | |
715 | DPRINTF(sc, ("%s: cas_stop\n", sc->sc_dev.dv_xname)); |
716 | |
717 | timeout_del(&sc->sc_tick_ch); |
718 | |
719 | /* |
720 | * Mark the interface down and cancel the watchdog timer. |
721 | */ |
722 | ifp->if_flags &= ~IFF_RUNNING0x40; |
723 | ifq_clr_oactive(&ifp->if_snd); |
724 | ifp->if_timer = 0; |
725 | |
726 | mii_down(&sc->sc_mii); |
727 | |
728 | cas_reset_rx(sc); |
729 | cas_reset_tx(sc); |
730 | |
731 | intr_barrier(sc->sc_ih); |
732 | KASSERT((ifp->if_flags & IFF_RUNNING) == 0)(((ifp->if_flags & 0x40) == 0) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/dev/pci/if_cas.c", 732, "(ifp->if_flags & IFF_RUNNING) == 0" )); |
733 | |
734 | /* |
735 | * Release any queued transmit buffers. |
736 | */ |
737 | for (i = 0; i < CAS_NTXDESC(64 * 16); i++) { |
738 | sd = &sc->sc_txd[i]; |
739 | if (sd->sd_mbuf != NULL((void *)0)) { |
740 | bus_dmamap_sync(sc->sc_dmatag, sd->sd_map, 0,(*(sc->sc_dmatag)->_dmamap_sync)((sc->sc_dmatag), (sd ->sd_map), (0), (sd->sd_map->dm_mapsize), (0x08)) |
741 | sd->sd_map->dm_mapsize, BUS_DMASYNC_POSTWRITE)(*(sc->sc_dmatag)->_dmamap_sync)((sc->sc_dmatag), (sd ->sd_map), (0), (sd->sd_map->dm_mapsize), (0x08)); |
742 | bus_dmamap_unload(sc->sc_dmatag, sd->sd_map)(*(sc->sc_dmatag)->_dmamap_unload)((sc->sc_dmatag), ( sd->sd_map)); |
743 | m_freem(sd->sd_mbuf); |
744 | sd->sd_mbuf = NULL((void *)0); |
745 | } |
746 | } |
747 | sc->sc_tx_cnt = sc->sc_tx_prod = sc->sc_tx_cons = 0; |
748 | |
749 | if (disable) |
750 | cas_rxdrain(sc); |
751 | } |
752 | |
753 | |
754 | /* |
755 | * Reset the receiver |
756 | */ |
757 | int |
758 | cas_reset_rx(struct cas_softc *sc) |
759 | { |
760 | bus_space_tag_t t = sc->sc_memt; |
761 | bus_space_handle_t h = sc->sc_memh; |
762 | |
763 | /* |
764 | * Resetting while DMA is in progress can cause a bus hang, so we |
765 | * disable DMA first. |
766 | */ |
767 | cas_disable_rx(sc); |
768 | bus_space_write_4(t, h, CAS_RX_CONFIG, 0)((t)->write_4((h), (0x4000), (0))); |
769 | /* Wait till it finishes */ |
770 | if (!cas_bitwait(sc, h, CAS_RX_CONFIG0x4000, 1, 0)) |
771 | printf("%s: cannot disable rx dma\n", sc->sc_dev.dv_xname); |
772 | /* Wait 5ms extra. */ |
773 | delay(5000)(*delay_func)(5000); |
774 | |
775 | /* Finally, reset the ERX */ |
776 | bus_space_write_4(t, h, CAS_RESET, CAS_RESET_RX)((t)->write_4((h), (0x1010), (0x000000002))); |
777 | /* Wait till it finishes */ |
778 | if (!cas_bitwait(sc, h, CAS_RESET0x1010, CAS_RESET_RX0x000000002, 0)) { |
779 | printf("%s: cannot reset receiver\n", sc->sc_dev.dv_xname); |
780 | return (1); |
781 | } |
782 | return (0); |
783 | } |
784 | |
785 | |
786 | /* |
787 | * Reset the transmitter |
788 | */ |
789 | int |
790 | cas_reset_tx(struct cas_softc *sc) |
791 | { |
792 | bus_space_tag_t t = sc->sc_memt; |
793 | bus_space_handle_t h = sc->sc_memh; |
794 | |
795 | /* |
796 | * Resetting while DMA is in progress can cause a bus hang, so we |
797 | * disable DMA first. |
798 | */ |
799 | cas_disable_tx(sc); |
800 | bus_space_write_4(t, h, CAS_TX_CONFIG, 0)((t)->write_4((h), (0x2004), (0))); |
801 | /* Wait till it finishes */ |
802 | if (!cas_bitwait(sc, h, CAS_TX_CONFIG0x2004, 1, 0)) |
803 | printf("%s: cannot disable tx dma\n", sc->sc_dev.dv_xname); |
804 | /* Wait 5ms extra. */ |
805 | delay(5000)(*delay_func)(5000); |
806 | |
807 | /* Finally, reset the ETX */ |
808 | bus_space_write_4(t, h, CAS_RESET, CAS_RESET_TX)((t)->write_4((h), (0x1010), (0x000000001))); |
809 | /* Wait till it finishes */ |
810 | if (!cas_bitwait(sc, h, CAS_RESET0x1010, CAS_RESET_TX0x000000001, 0)) { |
811 | printf("%s: cannot reset transmitter\n", |
812 | sc->sc_dev.dv_xname); |
813 | return (1); |
814 | } |
815 | return (0); |
816 | } |
817 | |
818 | /* |
819 | * disable receiver. |
820 | */ |
821 | int |
822 | cas_disable_rx(struct cas_softc *sc) |
823 | { |
824 | bus_space_tag_t t = sc->sc_memt; |
825 | bus_space_handle_t h = sc->sc_memh; |
826 | u_int32_t cfg; |
827 | |
828 | /* Flip the enable bit */ |
829 | cfg = bus_space_read_4(t, h, CAS_MAC_RX_CONFIG)((t)->read_4((h), (0x6034))); |
830 | cfg &= ~CAS_MAC_RX_ENABLE0x00000001; |
831 | bus_space_write_4(t, h, CAS_MAC_RX_CONFIG, cfg)((t)->write_4((h), (0x6034), (cfg))); |
832 | |
833 | /* Wait for it to finish */ |
834 | return (cas_bitwait(sc, h, CAS_MAC_RX_CONFIG0x6034, CAS_MAC_RX_ENABLE0x00000001, 0)); |
835 | } |
836 | |
837 | /* |
838 | * disable transmitter. |
839 | */ |
840 | int |
841 | cas_disable_tx(struct cas_softc *sc) |
842 | { |
843 | bus_space_tag_t t = sc->sc_memt; |
844 | bus_space_handle_t h = sc->sc_memh; |
845 | u_int32_t cfg; |
846 | |
847 | /* Flip the enable bit */ |
848 | cfg = bus_space_read_4(t, h, CAS_MAC_TX_CONFIG)((t)->read_4((h), (0x6030))); |
849 | cfg &= ~CAS_MAC_TX_ENABLE0x00000001; |
850 | bus_space_write_4(t, h, CAS_MAC_TX_CONFIG, cfg)((t)->write_4((h), (0x6030), (cfg))); |
851 | |
852 | /* Wait for it to finish */ |
853 | return (cas_bitwait(sc, h, CAS_MAC_TX_CONFIG0x6030, CAS_MAC_TX_ENABLE0x00000001, 0)); |
854 | } |
855 | |
856 | /* |
857 | * Initialize interface. |
858 | */ |
859 | int |
860 | cas_meminit(struct cas_softc *sc) |
861 | { |
862 | struct cas_rxsoft *rxs; |
863 | int i, error; |
864 | |
865 | rxs = (void *)&error; |
Value stored to 'rxs' is never read | |
866 | |
867 | /* |
868 | * Initialize the transmit descriptor ring. |
869 | */ |
870 | for (i = 0; i < CAS_NTXDESC(64 * 16); i++) { |
871 | sc->sc_txdescssc_control_data->ccd_txdescs[i].cd_flags = 0; |
872 | sc->sc_txdescssc_control_data->ccd_txdescs[i].cd_addr = 0; |
873 | } |
874 | CAS_CDTXSYNC(sc, 0, CAS_NTXDESC,do { int __x, __n; __x = (0); __n = ((64 * 16)); if ((__x + __n ) > (64 * 16)) { (*((sc)->sc_dmatag)->_dmamap_sync)( ((sc)->sc_dmatag), ((sc)->sc_cddmamap), (__builtin_offsetof (struct cas_control_data, ccd_txdescs[(__x)])), (sizeof(struct cas_desc) * ((64 * 16) - __x)), ((0x01|0x04))); __n -= ((64 * 16) - __x); __x = 0; } (*((sc)->sc_dmatag)->_dmamap_sync )(((sc)->sc_dmatag), ((sc)->sc_cddmamap), (__builtin_offsetof (struct cas_control_data, ccd_txdescs[(__x)])), (sizeof(struct cas_desc) * __n), ((0x01|0x04))); } while (0) |
875 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)do { int __x, __n; __x = (0); __n = ((64 * 16)); if ((__x + __n ) > (64 * 16)) { (*((sc)->sc_dmatag)->_dmamap_sync)( ((sc)->sc_dmatag), ((sc)->sc_cddmamap), (__builtin_offsetof (struct cas_control_data, ccd_txdescs[(__x)])), (sizeof(struct cas_desc) * ((64 * 16) - __x)), ((0x01|0x04))); __n -= ((64 * 16) - __x); __x = 0; } (*((sc)->sc_dmatag)->_dmamap_sync )(((sc)->sc_dmatag), ((sc)->sc_cddmamap), (__builtin_offsetof (struct cas_control_data, ccd_txdescs[(__x)])), (sizeof(struct cas_desc) * __n), ((0x01|0x04))); } while (0); |
876 | |
877 | /* |
878 | * Initialize the receive descriptor and receive job |
879 | * descriptor rings. |
880 | */ |
881 | for (i = 0; i < CAS_NRXDESC128; i++) |
882 | CAS_INIT_RXDESC(sc, i, i)do { struct cas_rxsoft *__rxs = &sc->sc_rxsoft[(i)]; struct cas_desc *__rxd = &sc->sc_control_data->ccd_rxdescs [(i)]; __rxd->cd_addr = ((__uint64_t)(__rxs->rxs_dmamap ->dm_segs[0].ds_addr)); __rxd->cd_flags = ((__uint64_t) ((i))); (*(((sc))->sc_dmatag)->_dmamap_sync)((((sc))-> sc_dmatag), (((sc))->sc_cddmamap), (__builtin_offsetof(struct cas_control_data, ccd_rxdescs[(((i)))])), (sizeof(struct cas_desc )), ((0x01|0x04))); } while (0); |
883 | sc->sc_rxdptr = 0; |
884 | sc->sc_rxptr = 0; |
885 | |
886 | /* |
887 | * Initialize the receive completion ring. |
888 | */ |
889 | for (i = 0; i < CAS_NRXCOMP256; i++) { |
890 | sc->sc_rxcompssc_control_data->ccd_rxcomps[i].cc_word[0] = 0; |
891 | sc->sc_rxcompssc_control_data->ccd_rxcomps[i].cc_word[1] = 0; |
892 | sc->sc_rxcompssc_control_data->ccd_rxcomps[i].cc_word[2] = 0; |
893 | sc->sc_rxcompssc_control_data->ccd_rxcomps[i].cc_word[3] = CAS_DMA_WRITE(CAS_RC3_OWN)((__uint64_t)(0x0000080000000000ULL)); |
894 | CAS_CDRXCSYNC(sc, i,(*((sc)->sc_dmatag)->_dmamap_sync)(((sc)->sc_dmatag) , ((sc)->sc_cddmamap), (__builtin_offsetof(struct cas_control_data , ccd_rxcomps[((i))])), (sizeof(struct cas_desc)), ((0x01|0x04 ))) |
895 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)(*((sc)->sc_dmatag)->_dmamap_sync)(((sc)->sc_dmatag) , ((sc)->sc_cddmamap), (__builtin_offsetof(struct cas_control_data , ccd_rxcomps[((i))])), (sizeof(struct cas_desc)), ((0x01|0x04 ))); |
896 | } |
897 | |
898 | return (0); |
899 | } |
900 | |
901 | int |
902 | cas_ringsize(int sz) |
903 | { |
904 | switch (sz) { |
905 | case 32: |
906 | return CAS_RING_SZ_320; |
907 | case 64: |
908 | return CAS_RING_SZ_641; |
909 | case 128: |
910 | return CAS_RING_SZ_1282; |
911 | case 256: |
912 | return CAS_RING_SZ_2563; |
913 | case 512: |
914 | return CAS_RING_SZ_5124; |
915 | case 1024: |
916 | return CAS_RING_SZ_10245; |
917 | case 2048: |
918 | return CAS_RING_SZ_20486; |
919 | case 4096: |
920 | return CAS_RING_SZ_40967; |
921 | case 8192: |
922 | return CAS_RING_SZ_81928; |
923 | default: |
924 | printf("cas: invalid Receive Descriptor ring size %d\n", sz); |
925 | return CAS_RING_SZ_320; |
926 | } |
927 | } |
928 | |
929 | int |
930 | cas_cringsize(int sz) |
931 | { |
932 | int i; |
933 | |
934 | for (i = 0; i < 9; i++) |
935 | if (sz == (128 << i)) |
936 | return i; |
937 | |
938 | printf("cas: invalid completion ring size %d\n", sz); |
939 | return 128; |
940 | } |
941 | |
942 | /* |
943 | * Initialization of interface; set up initialization block |
944 | * and transmit/receive descriptor rings. |
945 | */ |
946 | int |
947 | cas_init(struct ifnet *ifp) |
948 | { |
949 | struct cas_softc *sc = (struct cas_softc *)ifp->if_softc; |
950 | bus_space_tag_t t = sc->sc_memt; |
951 | bus_space_handle_t h = sc->sc_memh; |
952 | int s; |
953 | u_int max_frame_size; |
954 | u_int32_t v; |
955 | |
956 | s = splnet()splraise(0x4); |
957 | |
958 | DPRINTF(sc, ("%s: cas_init: calling stop\n", sc->sc_dev.dv_xname)); |
959 | /* |
960 | * Initialization sequence. The numbered steps below correspond |
961 | * to the sequence outlined in section 6.3.5.1 in the Ethernet |
962 | * Channel Engine manual (part of the PCIO manual). |
963 | * See also the STP2002-STQ document from Sun Microsystems. |
964 | */ |
965 | |
966 | /* step 1 & 2. Reset the Ethernet Channel */ |
967 | cas_stop(ifp, 0); |
968 | cas_reset(sc); |
969 | DPRINTF(sc, ("%s: cas_init: restarting\n", sc->sc_dev.dv_xname)); |
970 | |
971 | /* Re-initialize the MIF */ |
972 | cas_mifinit(sc); |
973 | |
974 | /* step 3. Setup data structures in host memory */ |
975 | cas_meminit(sc); |
976 | |
977 | /* step 4. TX MAC registers & counters */ |
978 | cas_init_regs(sc); |
979 | max_frame_size = ETHER_MAX_LEN1518 + ETHER_VLAN_ENCAP_LEN4; |
980 | v = (max_frame_size) | (0x2000 << 16) /* Burst size */; |
981 | bus_space_write_4(t, h, CAS_MAC_MAC_MAX_FRAME, v)((t)->write_4((h), (0x6054), (v))); |
982 | |
983 | /* step 5. RX MAC registers & counters */ |
984 | cas_iff(sc); |
985 | |
986 | /* step 6 & 7. Program Descriptor Ring Base Addresses */ |
987 | KASSERT((CAS_CDTXADDR(sc, 0) & 0x1fff) == 0)(((((sc)->sc_cddmamap->dm_segs[0].ds_addr + __builtin_offsetof (struct cas_control_data, ccd_txdescs[((0))])) & 0x1fff) == 0) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/pci/if_cas.c" , 987, "(CAS_CDTXADDR(sc, 0) & 0x1fff) == 0")); |
988 | bus_space_write_4(t, h, CAS_TX_RING_PTR_HI,((t)->write_4((h), (0x2074), ((((uint64_t)((sc)->sc_cddmamap ->dm_segs[0].ds_addr + __builtin_offsetof(struct cas_control_data , ccd_txdescs[((0))]))) >> 32)))) |
989 | (((uint64_t)CAS_CDTXADDR(sc,0)) >> 32))((t)->write_4((h), (0x2074), ((((uint64_t)((sc)->sc_cddmamap ->dm_segs[0].ds_addr + __builtin_offsetof(struct cas_control_data , ccd_txdescs[((0))]))) >> 32)))); |
990 | bus_space_write_4(t, h, CAS_TX_RING_PTR_LO, CAS_CDTXADDR(sc, 0))((t)->write_4((h), (0x2070), (((sc)->sc_cddmamap->dm_segs [0].ds_addr + __builtin_offsetof(struct cas_control_data, ccd_txdescs [((0))]))))); |
991 | |
992 | KASSERT((CAS_CDRXADDR(sc, 0) & 0x1fff) == 0)(((((sc)->sc_cddmamap->dm_segs[0].ds_addr + __builtin_offsetof (struct cas_control_data, ccd_rxdescs[((0))])) & 0x1fff) == 0) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/pci/if_cas.c" , 992, "(CAS_CDRXADDR(sc, 0) & 0x1fff) == 0")); |
993 | bus_space_write_4(t, h, CAS_RX_DRING_PTR_HI,((t)->write_4((h), (0x402c), ((((uint64_t)((sc)->sc_cddmamap ->dm_segs[0].ds_addr + __builtin_offsetof(struct cas_control_data , ccd_rxdescs[((0))]))) >> 32)))) |
994 | (((uint64_t)CAS_CDRXADDR(sc,0)) >> 32))((t)->write_4((h), (0x402c), ((((uint64_t)((sc)->sc_cddmamap ->dm_segs[0].ds_addr + __builtin_offsetof(struct cas_control_data , ccd_rxdescs[((0))]))) >> 32)))); |
995 | bus_space_write_4(t, h, CAS_RX_DRING_PTR_LO, CAS_CDRXADDR(sc, 0))((t)->write_4((h), (0x4028), (((sc)->sc_cddmamap->dm_segs [0].ds_addr + __builtin_offsetof(struct cas_control_data, ccd_rxdescs [((0))]))))); |
996 | |
997 | KASSERT((CAS_CDRXCADDR(sc, 0) & 0x1fff) == 0)(((((sc)->sc_cddmamap->dm_segs[0].ds_addr + __builtin_offsetof (struct cas_control_data, ccd_rxcomps[((0))])) & 0x1fff) == 0) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/pci/if_cas.c" , 997, "(CAS_CDRXCADDR(sc, 0) & 0x1fff) == 0")); |
998 | bus_space_write_4(t, h, CAS_RX_CRING_PTR_HI,((t)->write_4((h), (0x4034), ((((uint64_t)((sc)->sc_cddmamap ->dm_segs[0].ds_addr + __builtin_offsetof(struct cas_control_data , ccd_rxcomps[((0))]))) >> 32)))) |
999 | (((uint64_t)CAS_CDRXCADDR(sc,0)) >> 32))((t)->write_4((h), (0x4034), ((((uint64_t)((sc)->sc_cddmamap ->dm_segs[0].ds_addr + __builtin_offsetof(struct cas_control_data , ccd_rxcomps[((0))]))) >> 32)))); |
1000 | bus_space_write_4(t, h, CAS_RX_CRING_PTR_LO, CAS_CDRXCADDR(sc, 0))((t)->write_4((h), (0x4030), (((sc)->sc_cddmamap->dm_segs [0].ds_addr + __builtin_offsetof(struct cas_control_data, ccd_rxcomps [((0))]))))); |
1001 | |
1002 | if (CAS_PLUS(sc)(sc->sc_rev > 0x10)) { |
1003 | KASSERT((CAS_CDRXADDR2(sc, 0) & 0x1fff) == 0)(((((sc)->sc_cddmamap->dm_segs[0].ds_addr + __builtin_offsetof (struct cas_control_data, ccd_rxdescs2[((0))])) & 0x1fff) == 0) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/pci/if_cas.c" , 1003, "(CAS_CDRXADDR2(sc, 0) & 0x1fff) == 0")); |
1004 | bus_space_write_4(t, h, CAS_RX_DRING_PTR_HI2,((t)->write_4((h), (0x4204), ((((uint64_t)((sc)->sc_cddmamap ->dm_segs[0].ds_addr + __builtin_offsetof(struct cas_control_data , ccd_rxdescs2[((0))]))) >> 32)))) |
1005 | (((uint64_t)CAS_CDRXADDR2(sc,0)) >> 32))((t)->write_4((h), (0x4204), ((((uint64_t)((sc)->sc_cddmamap ->dm_segs[0].ds_addr + __builtin_offsetof(struct cas_control_data , ccd_rxdescs2[((0))]))) >> 32)))); |
1006 | bus_space_write_4(t, h, CAS_RX_DRING_PTR_LO2,((t)->write_4((h), (0x4200), (((sc)->sc_cddmamap->dm_segs [0].ds_addr + __builtin_offsetof(struct cas_control_data, ccd_rxdescs2 [((0))]))))) |
1007 | CAS_CDRXADDR2(sc, 0))((t)->write_4((h), (0x4200), (((sc)->sc_cddmamap->dm_segs [0].ds_addr + __builtin_offsetof(struct cas_control_data, ccd_rxdescs2 [((0))]))))); |
1008 | } |
1009 | |
1010 | /* step 8. Global Configuration & Interrupt Mask */ |
1011 | bus_space_write_4(t, h, CAS_INTMASK,((t)->write_4((h), (0x0010), (~(0x000000001|0x000000002| 0x000000008 | 0x000000010|0x000000020| 0x000000040| 0x000000080|0x000002000 | 0x000010000|0x000020000| 0x000040000)))) |
1012 | ~(CAS_INTR_TX_INTME|CAS_INTR_TX_EMPTY|((t)->write_4((h), (0x0010), (~(0x000000001|0x000000002| 0x000000008 | 0x000000010|0x000000020| 0x000000040| 0x000000080|0x000002000 | 0x000010000|0x000020000| 0x000040000)))) |
1013 | CAS_INTR_TX_TAG_ERR|((t)->write_4((h), (0x0010), (~(0x000000001|0x000000002| 0x000000008 | 0x000000010|0x000000020| 0x000000040| 0x000000080|0x000002000 | 0x000010000|0x000020000| 0x000040000)))) |
1014 | CAS_INTR_RX_DONE|CAS_INTR_RX_NOBUF|((t)->write_4((h), (0x0010), (~(0x000000001|0x000000002| 0x000000008 | 0x000000010|0x000000020| 0x000000040| 0x000000080|0x000002000 | 0x000010000|0x000020000| 0x000040000)))) |
1015 | CAS_INTR_RX_TAG_ERR|((t)->write_4((h), (0x0010), (~(0x000000001|0x000000002| 0x000000008 | 0x000000010|0x000000020| 0x000000040| 0x000000080|0x000002000 | 0x000010000|0x000020000| 0x000040000)))) |
1016 | CAS_INTR_RX_COMP_FULL|CAS_INTR_PCS|((t)->write_4((h), (0x0010), (~(0x000000001|0x000000002| 0x000000008 | 0x000000010|0x000000020| 0x000000040| 0x000000080|0x000002000 | 0x000010000|0x000020000| 0x000040000)))) |
1017 | CAS_INTR_MAC_CONTROL|CAS_INTR_MIF|((t)->write_4((h), (0x0010), (~(0x000000001|0x000000002| 0x000000008 | 0x000000010|0x000000020| 0x000000040| 0x000000080|0x000002000 | 0x000010000|0x000020000| 0x000040000)))) |
1018 | CAS_INTR_BERR))((t)->write_4((h), (0x0010), (~(0x000000001|0x000000002| 0x000000008 | 0x000000010|0x000000020| 0x000000040| 0x000000080|0x000002000 | 0x000010000|0x000020000| 0x000040000)))); |
1019 | bus_space_write_4(t, h, CAS_MAC_RX_MASK,((t)->write_4((h), (0x6024), (0x00000001|0x00000004))) |
1020 | CAS_MAC_RX_DONE|CAS_MAC_RX_FRAME_CNT)((t)->write_4((h), (0x6024), (0x00000001|0x00000004))); |
1021 | bus_space_write_4(t, h, CAS_MAC_TX_MASK, CAS_MAC_TX_XMIT_DONE)((t)->write_4((h), (0x6020), (0x00000001))); |
1022 | bus_space_write_4(t, h, CAS_MAC_CONTROL_MASK, 0)((t)->write_4((h), (0x6028), (0))); /* XXXX */ |
1023 | |
1024 | /* step 9. ETX Configuration: use mostly default values */ |
1025 | |
1026 | /* Enable DMA */ |
1027 | v = cas_ringsize(CAS_NTXDESC(64 * 16) /*XXX*/) << 10; |
1028 | bus_space_write_4(t, h, CAS_TX_CONFIG,((t)->write_4((h), (0x2004), (v|0x00000001|(1<<24)|( 1<<29)))) |
1029 | v|CAS_TX_CONFIG_TXDMA_EN|(1<<24)|(1<<29))((t)->write_4((h), (0x2004), (v|0x00000001|(1<<24)|( 1<<29)))); |
1030 | bus_space_write_4(t, h, CAS_TX_KICK, 0)((t)->write_4((h), (0x2040), (0))); |
1031 | |
1032 | /* step 10. ERX Configuration */ |
1033 | |
1034 | /* Encode Receive Descriptor ring size */ |
1035 | v = cas_ringsize(CAS_NRXDESC128) << CAS_RX_CONFIG_RXDRNG_SZ_SHIFT1; |
1036 | if (CAS_PLUS(sc)(sc->sc_rev > 0x10)) |
1037 | v |= cas_ringsize(32) << CAS_RX_CONFIG_RXDRNG2_SZ_SHIFT16; |
1038 | |
1039 | /* Encode Receive Completion ring size */ |
1040 | v |= cas_cringsize(CAS_NRXCOMP256) << CAS_RX_CONFIG_RXCRNG_SZ_SHIFT5; |
1041 | |
1042 | /* Enable DMA */ |
1043 | bus_space_write_4(t, h, CAS_RX_CONFIG,((t)->write_4((h), (0x4000), (v|(2<<10)|0x00000001)) ) |
1044 | v|(2<<CAS_RX_CONFIG_FBOFF_SHFT)|CAS_RX_CONFIG_RXDMA_EN)((t)->write_4((h), (0x4000), (v|(2<<10)|0x00000001)) ); |
1045 | |
1046 | /* |
1047 | * The following value is for an OFF Threshold of about 3/4 full |
1048 | * and an ON Threshold of 1/4 full. |
1049 | */ |
1050 | bus_space_write_4(t, h, CAS_RX_PAUSE_THRESH,((t)->write_4((h), (0x4020), ((3 * sc->sc_rxfifosize / 256 ) | ((sc->sc_rxfifosize / 256) << 12)))) |
1051 | (3 * sc->sc_rxfifosize / 256) |((t)->write_4((h), (0x4020), ((3 * sc->sc_rxfifosize / 256 ) | ((sc->sc_rxfifosize / 256) << 12)))) |
1052 | ((sc->sc_rxfifosize / 256) << 12))((t)->write_4((h), (0x4020), ((3 * sc->sc_rxfifosize / 256 ) | ((sc->sc_rxfifosize / 256) << 12)))); |
1053 | bus_space_write_4(t, h, CAS_RX_BLANKING, (6 << 12) | 6)((t)->write_4((h), (0x4044), ((6 << 12) | 6))); |
1054 | |
1055 | /* step 11. Configure Media */ |
1056 | mii_mediachg(&sc->sc_mii); |
1057 | |
1058 | /* step 12. RX_MAC Configuration Register */ |
1059 | v = bus_space_read_4(t, h, CAS_MAC_RX_CONFIG)((t)->read_4((h), (0x6034))); |
1060 | v |= CAS_MAC_RX_ENABLE0x00000001 | CAS_MAC_RX_STRIP_CRC0x00000004; |
1061 | bus_space_write_4(t, h, CAS_MAC_RX_CONFIG, v)((t)->write_4((h), (0x6034), (v))); |
1062 | |
1063 | /* step 14. Issue Transmit Pending command */ |
1064 | |
1065 | /* step 15. Give the receiver a swift kick */ |
1066 | bus_space_write_4(t, h, CAS_RX_KICK, CAS_NRXDESC-4)((t)->write_4((h), (0x4024), (128 -4))); |
1067 | if (CAS_PLUS(sc)(sc->sc_rev > 0x10)) |
1068 | bus_space_write_4(t, h, CAS_RX_KICK2, 4)((t)->write_4((h), (0x4220), (4))); |
1069 | |
1070 | /* Start the one second timer. */ |
1071 | timeout_add_sec(&sc->sc_tick_ch, 1); |
1072 | |
1073 | ifp->if_flags |= IFF_RUNNING0x40; |
1074 | ifq_clr_oactive(&ifp->if_snd); |
1075 | ifp->if_timer = 0; |
1076 | splx(s)spllower(s); |
1077 | |
1078 | return (0); |
1079 | } |
1080 | |
1081 | void |
1082 | cas_init_regs(struct cas_softc *sc) |
1083 | { |
1084 | bus_space_tag_t t = sc->sc_memt; |
1085 | bus_space_handle_t h = sc->sc_memh; |
1086 | u_int32_t v, r; |
1087 | |
1088 | /* These regs are not cleared on reset */ |
1089 | sc->sc_inited = 0; |
1090 | if (!sc->sc_inited) { |
1091 | /* Load recommended values */ |
1092 | bus_space_write_4(t, h, CAS_MAC_IPG0, 0x00)((t)->write_4((h), (0x6040), (0x00))); |
1093 | bus_space_write_4(t, h, CAS_MAC_IPG1, 0x08)((t)->write_4((h), (0x6044), (0x08))); |
1094 | bus_space_write_4(t, h, CAS_MAC_IPG2, 0x04)((t)->write_4((h), (0x6048), (0x04))); |
1095 | |
1096 | bus_space_write_4(t, h, CAS_MAC_MAC_MIN_FRAME, ETHER_MIN_LEN)((t)->write_4((h), (0x6050), (64))); |
1097 | /* Max frame and max burst size */ |
1098 | v = ETHER_MAX_LEN1518 | (0x2000 << 16) /* Burst size */; |
1099 | bus_space_write_4(t, h, CAS_MAC_MAC_MAX_FRAME, v)((t)->write_4((h), (0x6054), (v))); |
1100 | |
1101 | bus_space_write_4(t, h, CAS_MAC_PREAMBLE_LEN, 0x07)((t)->write_4((h), (0x6058), (0x07))); |
1102 | bus_space_write_4(t, h, CAS_MAC_JAM_SIZE, 0x04)((t)->write_4((h), (0x605c), (0x04))); |
1103 | bus_space_write_4(t, h, CAS_MAC_ATTEMPT_LIMIT, 0x10)((t)->write_4((h), (0x6060), (0x10))); |
1104 | bus_space_write_4(t, h, CAS_MAC_CONTROL_TYPE, 0x8088)((t)->write_4((h), (0x6064), (0x8088))); |
1105 | bus_space_write_4(t, h, CAS_MAC_RANDOM_SEED,((t)->write_4((h), (0x61cc), (((sc->sc_arpcom.ac_enaddr [5]<<8)|sc->sc_arpcom.ac_enaddr[4])&0x3ff))) |
1106 | ((sc->sc_arpcom.ac_enaddr[5]<<8)|sc->sc_arpcom.ac_enaddr[4])&0x3ff)((t)->write_4((h), (0x61cc), (((sc->sc_arpcom.ac_enaddr [5]<<8)|sc->sc_arpcom.ac_enaddr[4])&0x3ff))); |
1107 | |
1108 | /* Secondary MAC addresses set to 0:0:0:0:0:0 */ |
1109 | for (r = CAS_MAC_ADDR30x608c; r < CAS_MAC_ADDR420x6128; r += 4) |
1110 | bus_space_write_4(t, h, r, 0)((t)->write_4((h), (r), (0))); |
1111 | |
1112 | /* MAC control addr set to 0:1:c2:0:1:80 */ |
1113 | bus_space_write_4(t, h, CAS_MAC_ADDR42, 0x0001)((t)->write_4((h), (0x6128), (0x0001))); |
1114 | bus_space_write_4(t, h, CAS_MAC_ADDR43, 0xc200)((t)->write_4((h), (0x612c), (0xc200))); |
1115 | bus_space_write_4(t, h, CAS_MAC_ADDR44, 0x0180)((t)->write_4((h), (0x6130), (0x0180))); |
1116 | |
1117 | /* MAC filter addr set to 0:0:0:0:0:0 */ |
1118 | bus_space_write_4(t, h, CAS_MAC_ADDR_FILTER0, 0)((t)->write_4((h), (0x614c), (0))); |
1119 | bus_space_write_4(t, h, CAS_MAC_ADDR_FILTER1, 0)((t)->write_4((h), (0x6150), (0))); |
1120 | bus_space_write_4(t, h, CAS_MAC_ADDR_FILTER2, 0)((t)->write_4((h), (0x6154), (0))); |
1121 | |
1122 | bus_space_write_4(t, h, CAS_MAC_ADR_FLT_MASK1_2, 0)((t)->write_4((h), (0x6158), (0))); |
1123 | bus_space_write_4(t, h, CAS_MAC_ADR_FLT_MASK0, 0)((t)->write_4((h), (0x615c), (0))); |
1124 | |
1125 | /* Hash table initialized to 0 */ |
1126 | for (r = CAS_MAC_HASH00x6160; r <= CAS_MAC_HASH150x619c; r += 4) |
1127 | bus_space_write_4(t, h, r, 0)((t)->write_4((h), (r), (0))); |
1128 | |
1129 | sc->sc_inited = 1; |
1130 | } |
1131 | |
1132 | /* Counters need to be zeroed */ |
1133 | bus_space_write_4(t, h, CAS_MAC_NORM_COLL_CNT, 0)((t)->write_4((h), (0x61a0), (0))); |
1134 | bus_space_write_4(t, h, CAS_MAC_FIRST_COLL_CNT, 0)((t)->write_4((h), (0x61a4), (0))); |
1135 | bus_space_write_4(t, h, CAS_MAC_EXCESS_COLL_CNT, 0)((t)->write_4((h), (0x61a8), (0))); |
1136 | bus_space_write_4(t, h, CAS_MAC_LATE_COLL_CNT, 0)((t)->write_4((h), (0x61ac), (0))); |
1137 | bus_space_write_4(t, h, CAS_MAC_DEFER_TMR_CNT, 0)((t)->write_4((h), (0x61b0), (0))); |
1138 | bus_space_write_4(t, h, CAS_MAC_PEAK_ATTEMPTS, 0)((t)->write_4((h), (0x61b4), (0))); |
1139 | bus_space_write_4(t, h, CAS_MAC_RX_FRAME_COUNT, 0)((t)->write_4((h), (0x61b8), (0))); |
1140 | bus_space_write_4(t, h, CAS_MAC_RX_LEN_ERR_CNT, 0)((t)->write_4((h), (0x61bc), (0))); |
1141 | bus_space_write_4(t, h, CAS_MAC_RX_ALIGN_ERR, 0)((t)->write_4((h), (0x61c0), (0))); |
1142 | bus_space_write_4(t, h, CAS_MAC_RX_CRC_ERR_CNT, 0)((t)->write_4((h), (0x61c4), (0))); |
1143 | bus_space_write_4(t, h, CAS_MAC_RX_CODE_VIOL, 0)((t)->write_4((h), (0x61c8), (0))); |
1144 | |
1145 | /* Un-pause stuff */ |
1146 | bus_space_write_4(t, h, CAS_MAC_SEND_PAUSE_CMD, 0)((t)->write_4((h), (0x6008), (0))); |
1147 | |
1148 | /* |
1149 | * Set the station address. |
1150 | */ |
1151 | bus_space_write_4(t, h, CAS_MAC_ADDR0,((t)->write_4((h), (0x6080), ((sc->sc_arpcom.ac_enaddr[ 4]<<8) | sc->sc_arpcom.ac_enaddr[5]))) |
1152 | (sc->sc_arpcom.ac_enaddr[4]<<8) | sc->sc_arpcom.ac_enaddr[5])((t)->write_4((h), (0x6080), ((sc->sc_arpcom.ac_enaddr[ 4]<<8) | sc->sc_arpcom.ac_enaddr[5]))); |
1153 | bus_space_write_4(t, h, CAS_MAC_ADDR1,((t)->write_4((h), (0x6084), ((sc->sc_arpcom.ac_enaddr[ 2]<<8) | sc->sc_arpcom.ac_enaddr[3]))) |
1154 | (sc->sc_arpcom.ac_enaddr[2]<<8) | sc->sc_arpcom.ac_enaddr[3])((t)->write_4((h), (0x6084), ((sc->sc_arpcom.ac_enaddr[ 2]<<8) | sc->sc_arpcom.ac_enaddr[3]))); |
1155 | bus_space_write_4(t, h, CAS_MAC_ADDR2,((t)->write_4((h), (0x6088), ((sc->sc_arpcom.ac_enaddr[ 0]<<8) | sc->sc_arpcom.ac_enaddr[1]))) |
1156 | (sc->sc_arpcom.ac_enaddr[0]<<8) | sc->sc_arpcom.ac_enaddr[1])((t)->write_4((h), (0x6088), ((sc->sc_arpcom.ac_enaddr[ 0]<<8) | sc->sc_arpcom.ac_enaddr[1]))); |
1157 | } |
1158 | |
1159 | /* |
1160 | * Receive interrupt. |
1161 | */ |
1162 | int |
1163 | cas_rint(struct cas_softc *sc) |
1164 | { |
1165 | struct ifnet *ifp = &sc->sc_arpcom.ac_if; |
1166 | bus_space_tag_t t = sc->sc_memt; |
1167 | bus_space_handle_t h = sc->sc_memh; |
1168 | struct cas_rxsoft *rxs; |
1169 | struct mbuf_list ml = MBUF_LIST_INITIALIZER(){ ((void *)0), ((void *)0), 0 }; |
1170 | struct mbuf *m; |
1171 | u_int64_t word[4]; |
1172 | int len, off, idx; |
1173 | int i, skip; |
1174 | caddr_t cp; |
1175 | |
1176 | for (i = sc->sc_rxptr;; i = CAS_NEXTRX(i + skip)((i + skip + 1) & (256 - 1))) { |
1177 | CAS_CDRXCSYNC(sc, i,(*((sc)->sc_dmatag)->_dmamap_sync)(((sc)->sc_dmatag) , ((sc)->sc_cddmamap), (__builtin_offsetof(struct cas_control_data , ccd_rxcomps[((i))])), (sizeof(struct cas_desc)), ((0x02|0x08 ))) |
1178 | BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)(*((sc)->sc_dmatag)->_dmamap_sync)(((sc)->sc_dmatag) , ((sc)->sc_cddmamap), (__builtin_offsetof(struct cas_control_data , ccd_rxcomps[((i))])), (sizeof(struct cas_desc)), ((0x02|0x08 ))); |
1179 | |
1180 | word[0] = CAS_DMA_READ(sc->sc_rxcomps[i].cc_word[0])((__uint64_t)(sc->sc_control_data->ccd_rxcomps[i].cc_word [0])); |
1181 | word[1] = CAS_DMA_READ(sc->sc_rxcomps[i].cc_word[1])((__uint64_t)(sc->sc_control_data->ccd_rxcomps[i].cc_word [1])); |
1182 | word[2] = CAS_DMA_READ(sc->sc_rxcomps[i].cc_word[2])((__uint64_t)(sc->sc_control_data->ccd_rxcomps[i].cc_word [2])); |
1183 | word[3] = CAS_DMA_READ(sc->sc_rxcomps[i].cc_word[3])((__uint64_t)(sc->sc_control_data->ccd_rxcomps[i].cc_word [3])); |
1184 | |
1185 | /* Stop if the hardware still owns the descriptor. */ |
1186 | if ((word[0] & CAS_RC0_TYPE0xc000000000000000ULL) == 0 || word[3] & CAS_RC3_OWN0x0000080000000000ULL) |
1187 | break; |
1188 | |
1189 | len = CAS_RC1_HDR_LEN(word[1])(((word[1]) & 0x00000ff800000000ULL) >> 35); |
1190 | if (len > 0) { |
1191 | off = CAS_RC1_HDR_OFF(word[1])(((word[1]) & 0x0003f00000000000ULL) >> 44); |
1192 | idx = CAS_RC1_HDR_IDX(word[1])(((word[1]) & 0xfffc000000000000ULL) >> 50); |
1193 | rxs = &sc->sc_rxsoft[idx]; |
1194 | |
1195 | DPRINTF(sc, ("hdr at idx %d, off %d, len %d\n", |
1196 | idx, off, len)); |
1197 | |
1198 | bus_dmamap_sync(sc->sc_dmatag, rxs->rxs_dmamap, 0,(*(sc->sc_dmatag)->_dmamap_sync)((sc->sc_dmatag), (rxs ->rxs_dmamap), (0), (rxs->rxs_dmamap->dm_mapsize), ( 0x02)) |
1199 | rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD)(*(sc->sc_dmatag)->_dmamap_sync)((sc->sc_dmatag), (rxs ->rxs_dmamap), (0), (rxs->rxs_dmamap->dm_mapsize), ( 0x02)); |
1200 | |
1201 | cp = rxs->rxs_kva + off * 256 + ETHER_ALIGN2; |
1202 | m = m_devget(cp, len, ETHER_ALIGN2); |
1203 | |
1204 | if (word[0] & CAS_RC0_RELEASE_HDR0x2000000000000000ULL) |
1205 | cas_add_rxbuf(sc, idx); |
1206 | |
1207 | if (m != NULL((void *)0)) { |
1208 | ml_enqueue(&ml, m); |
1209 | } else |
1210 | ifp->if_ierrorsif_data.ifi_ierrors++; |
1211 | } |
1212 | |
1213 | len = CAS_RC0_DATA_LEN(word[0])(((word[0]) & 0x0000000007ffe000ULL) >> 13); |
1214 | if (len > 0) { |
1215 | off = CAS_RC0_DATA_OFF(word[0])(((word[0]) & 0x000001fff8000000ULL) >> 27); |
1216 | idx = CAS_RC0_DATA_IDX(word[0])(((word[0]) & 0x007ffe0000000000ULL) >> 41); |
1217 | rxs = &sc->sc_rxsoft[idx]; |
1218 | |
1219 | DPRINTF(sc, ("data at idx %d, off %d, len %d\n", |
1220 | idx, off, len)); |
1221 | |
1222 | bus_dmamap_sync(sc->sc_dmatag, rxs->rxs_dmamap, 0,(*(sc->sc_dmatag)->_dmamap_sync)((sc->sc_dmatag), (rxs ->rxs_dmamap), (0), (rxs->rxs_dmamap->dm_mapsize), ( 0x02)) |
1223 | rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD)(*(sc->sc_dmatag)->_dmamap_sync)((sc->sc_dmatag), (rxs ->rxs_dmamap), (0), (rxs->rxs_dmamap->dm_mapsize), ( 0x02)); |
1224 | |
1225 | /* XXX We should not be copying the packet here. */ |
1226 | cp = rxs->rxs_kva + off + ETHER_ALIGN2; |
1227 | m = m_devget(cp, len, ETHER_ALIGN2); |
1228 | |
1229 | if (word[0] & CAS_RC0_RELEASE_DATA0x1000000000000000ULL) |
1230 | cas_add_rxbuf(sc, idx); |
1231 | |
1232 | if (m != NULL((void *)0)) { |
1233 | ml_enqueue(&ml, m); |
1234 | } else |
1235 | ifp->if_ierrorsif_data.ifi_ierrors++; |
1236 | } |
1237 | |
1238 | if (word[0] & CAS_RC0_SPLIT0x0400000000000000ULL) |
1239 | printf("split packet\n"); |
1240 | |
1241 | skip = CAS_RC0_SKIP(word[0])(((word[0]) & 0x0180000000000000ULL) >> 55); |
1242 | } |
1243 | |
1244 | while (sc->sc_rxptr != i) { |
1245 | sc->sc_rxcompssc_control_data->ccd_rxcomps[sc->sc_rxptr].cc_word[0] = 0; |
1246 | sc->sc_rxcompssc_control_data->ccd_rxcomps[sc->sc_rxptr].cc_word[1] = 0; |
1247 | sc->sc_rxcompssc_control_data->ccd_rxcomps[sc->sc_rxptr].cc_word[2] = 0; |
1248 | sc->sc_rxcompssc_control_data->ccd_rxcomps[sc->sc_rxptr].cc_word[3] = |
1249 | CAS_DMA_WRITE(CAS_RC3_OWN)((__uint64_t)(0x0000080000000000ULL)); |
1250 | CAS_CDRXCSYNC(sc, sc->sc_rxptr,(*((sc)->sc_dmatag)->_dmamap_sync)(((sc)->sc_dmatag) , ((sc)->sc_cddmamap), (__builtin_offsetof(struct cas_control_data , ccd_rxcomps[((sc->sc_rxptr))])), (sizeof(struct cas_desc )), ((0x01|0x04))) |
1251 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)(*((sc)->sc_dmatag)->_dmamap_sync)(((sc)->sc_dmatag) , ((sc)->sc_cddmamap), (__builtin_offsetof(struct cas_control_data , ccd_rxcomps[((sc->sc_rxptr))])), (sizeof(struct cas_desc )), ((0x01|0x04))); |
1252 | |
1253 | sc->sc_rxptr = CAS_NEXTRX(sc->sc_rxptr)((sc->sc_rxptr + 1) & (256 - 1)); |
1254 | } |
1255 | |
1256 | bus_space_write_4(t, h, CAS_RX_COMP_TAIL, sc->sc_rxptr)((t)->write_4((h), (0x4040), (sc->sc_rxptr))); |
1257 | |
1258 | DPRINTF(sc, ("cas_rint: done sc->rxptr %d, complete %d\n", |
1259 | sc->sc_rxptr, bus_space_read_4(t, h, CAS_RX_COMPLETION))); |
1260 | |
1261 | if_input(ifp, &ml); |
1262 | |
1263 | return (1); |
1264 | } |
1265 | |
1266 | /* |
1267 | * cas_add_rxbuf: |
1268 | * |
1269 | * Add a receive buffer to the indicated descriptor. |
1270 | */ |
1271 | int |
1272 | cas_add_rxbuf(struct cas_softc *sc, int idx) |
1273 | { |
1274 | bus_space_tag_t t = sc->sc_memt; |
1275 | bus_space_handle_t h = sc->sc_memh; |
1276 | |
1277 | CAS_INIT_RXDESC(sc, sc->sc_rxdptr, idx)do { struct cas_rxsoft *__rxs = &sc->sc_rxsoft[(idx)]; struct cas_desc *__rxd = &sc->sc_control_data->ccd_rxdescs [(sc->sc_rxdptr)]; __rxd->cd_addr = ((__uint64_t)(__rxs ->rxs_dmamap->dm_segs[0].ds_addr)); __rxd->cd_flags = ((__uint64_t)((idx))); (*(((sc))->sc_dmatag)->_dmamap_sync )((((sc))->sc_dmatag), (((sc))->sc_cddmamap), (__builtin_offsetof (struct cas_control_data, ccd_rxdescs[(((sc->sc_rxdptr)))] )), (sizeof(struct cas_desc)), ((0x01|0x04))); } while (0); |
1278 | |
1279 | if ((sc->sc_rxdptr % 4) == 0) |
1280 | bus_space_write_4(t, h, CAS_RX_KICK, sc->sc_rxdptr)((t)->write_4((h), (0x4024), (sc->sc_rxdptr))); |
1281 | |
1282 | if (++sc->sc_rxdptr == CAS_NRXDESC128) |
1283 | sc->sc_rxdptr = 0; |
1284 | |
1285 | return (0); |
1286 | } |
1287 | |
1288 | int |
1289 | cas_eint(struct cas_softc *sc, u_int status) |
1290 | { |
1291 | if ((status & CAS_INTR_MIF0x000020000) != 0) { |
1292 | #ifdef CAS_DEBUG |
1293 | printf("%s: link status changed\n", sc->sc_dev.dv_xname); |
1294 | #endif |
1295 | return (1); |
1296 | } |
1297 | |
1298 | printf("%s: status=%b\n", sc->sc_dev.dv_xname, status, CAS_INTR_BITS"\020" "\1INTME\2TXEMPTY\3TXDONE\4TX_TAG_ERR" "\5RXDONE\6RXNOBUF\7RX_TAG_ERR" "\10RX_COMP_FULL" "\16PCS\17TXMAC\20RXMAC" "\21MACCONTROL\22MIF\23BERR"); |
1299 | return (1); |
1300 | } |
1301 | |
1302 | int |
1303 | cas_pint(struct cas_softc *sc) |
1304 | { |
1305 | bus_space_tag_t t = sc->sc_memt; |
1306 | bus_space_handle_t seb = sc->sc_memh; |
1307 | u_int32_t status; |
1308 | |
1309 | status = bus_space_read_4(t, seb, CAS_MII_INTERRUP_STATUS)((t)->read_4((seb), (0x9018))); |
1310 | status |= bus_space_read_4(t, seb, CAS_MII_INTERRUP_STATUS)((t)->read_4((seb), (0x9018))); |
1311 | #ifdef CAS_DEBUG |
1312 | if (status) |
1313 | printf("%s: link status changed\n", sc->sc_dev.dv_xname); |
1314 | #endif |
1315 | return (1); |
1316 | } |
1317 | |
1318 | int |
1319 | cas_intr(void *v) |
1320 | { |
1321 | struct cas_softc *sc = (struct cas_softc *)v; |
1322 | struct ifnet *ifp = &sc->sc_arpcom.ac_if; |
1323 | bus_space_tag_t t = sc->sc_memt; |
1324 | bus_space_handle_t seb = sc->sc_memh; |
1325 | u_int32_t status; |
1326 | int r = 0; |
1327 | |
1328 | status = bus_space_read_4(t, seb, CAS_STATUS)((t)->read_4((seb), (0x000c))); |
1329 | DPRINTF(sc, ("%s: cas_intr: cplt %xstatus %b\n", |
1330 | sc->sc_dev.dv_xname, (status>>19), status, CAS_INTR_BITS)); |
1331 | |
1332 | if ((status & CAS_INTR_PCS0x000002000) != 0) |
1333 | r |= cas_pint(sc); |
1334 | |
1335 | if ((status & (CAS_INTR_TX_TAG_ERR0x000000008 | CAS_INTR_RX_TAG_ERR0x000000040 | |
1336 | CAS_INTR_RX_COMP_FULL0x000000080 | CAS_INTR_BERR0x000040000)) != 0) |
1337 | r |= cas_eint(sc, status); |
1338 | |
1339 | if ((status & (CAS_INTR_TX_EMPTY0x000000002 | CAS_INTR_TX_INTME0x000000001)) != 0) |
1340 | r |= cas_tint(sc, status); |
1341 | |
1342 | if ((status & (CAS_INTR_RX_DONE0x000000010 | CAS_INTR_RX_NOBUF0x000000020)) != 0) |
1343 | r |= cas_rint(sc); |
1344 | |
1345 | /* We should eventually do more than just print out error stats. */ |
1346 | if (status & CAS_INTR_TX_MAC0x000004000) { |
1347 | int txstat = bus_space_read_4(t, seb, CAS_MAC_TX_STATUS)((t)->read_4((seb), (0x6010))); |
1348 | #ifdef CAS_DEBUG |
1349 | if (txstat & ~CAS_MAC_TX_XMIT_DONE0x00000001) |
1350 | printf("%s: MAC tx fault, status %x\n", |
1351 | sc->sc_dev.dv_xname, txstat); |
1352 | #endif |
1353 | if (txstat & (CAS_MAC_TX_UNDERRUN0x00000002 | CAS_MAC_TX_PKT_TOO_LONG0x00000004)) { |
1354 | KERNEL_LOCK()_kernel_lock(); |
1355 | cas_init(ifp); |
1356 | KERNEL_UNLOCK()_kernel_unlock(); |
1357 | } |
1358 | } |
1359 | if (status & CAS_INTR_RX_MAC0x000008000) { |
1360 | int rxstat = bus_space_read_4(t, seb, CAS_MAC_RX_STATUS)((t)->read_4((seb), (0x6014))); |
1361 | #ifdef CAS_DEBUG |
1362 | if (rxstat & ~CAS_MAC_RX_DONE0x00000001) |
1363 | printf("%s: MAC rx fault, status %x\n", |
1364 | sc->sc_dev.dv_xname, rxstat); |
1365 | #endif |
1366 | /* |
1367 | * On some chip revisions CAS_MAC_RX_OVERFLOW happen often |
1368 | * due to a silicon bug so handle them silently. |
1369 | */ |
1370 | if (rxstat & CAS_MAC_RX_OVERFLOW0x00000002) { |
1371 | KERNEL_LOCK()_kernel_lock(); |
1372 | ifp->if_ierrorsif_data.ifi_ierrors++; |
1373 | cas_init(ifp); |
1374 | KERNEL_UNLOCK()_kernel_unlock(); |
1375 | } |
1376 | #ifdef CAS_DEBUG |
1377 | else if (rxstat & ~(CAS_MAC_RX_DONE0x00000001 | CAS_MAC_RX_FRAME_CNT0x00000004)) |
1378 | printf("%s: MAC rx fault, status %x\n", |
1379 | sc->sc_dev.dv_xname, rxstat); |
1380 | #endif |
1381 | } |
1382 | return (r); |
1383 | } |
1384 | |
1385 | |
1386 | void |
1387 | cas_watchdog(struct ifnet *ifp) |
1388 | { |
1389 | struct cas_softc *sc = ifp->if_softc; |
1390 | |
1391 | DPRINTF(sc, ("cas_watchdog: CAS_RX_CONFIG %x CAS_MAC_RX_STATUS %x " |
1392 | "CAS_MAC_RX_CONFIG %x\n", |
1393 | bus_space_read_4(sc->sc_memt, sc->sc_memh, CAS_RX_CONFIG), |
1394 | bus_space_read_4(sc->sc_memt, sc->sc_memh, CAS_MAC_RX_STATUS), |
1395 | bus_space_read_4(sc->sc_memt, sc->sc_memh, CAS_MAC_RX_CONFIG))); |
1396 | |
1397 | log(LOG_ERR3, "%s: device timeout\n", sc->sc_dev.dv_xname); |
1398 | ++ifp->if_oerrorsif_data.ifi_oerrors; |
1399 | |
1400 | /* Try to get more packets going. */ |
1401 | cas_init(ifp); |
1402 | } |
1403 | |
1404 | /* |
1405 | * Initialize the MII Management Interface |
1406 | */ |
1407 | void |
1408 | cas_mifinit(struct cas_softc *sc) |
1409 | { |
1410 | bus_space_tag_t t = sc->sc_memt; |
1411 | bus_space_handle_t mif = sc->sc_memh; |
1412 | |
1413 | /* Configure the MIF in frame mode */ |
1414 | sc->sc_mif_config = bus_space_read_4(t, mif, CAS_MIF_CONFIG)((t)->read_4((mif), (0x6210))); |
1415 | sc->sc_mif_config &= ~CAS_MIF_CONFIG_BB_ENA0x00000004; |
1416 | bus_space_write_4(t, mif, CAS_MIF_CONFIG, sc->sc_mif_config)((t)->write_4((mif), (0x6210), (sc->sc_mif_config))); |
1417 | } |
1418 | |
1419 | /* |
1420 | * MII interface |
1421 | * |
1422 | * The Cassini MII interface supports at least three different operating modes: |
1423 | * |
1424 | * Bitbang mode is implemented using data, clock and output enable registers. |
1425 | * |
1426 | * Frame mode is implemented by loading a complete frame into the frame |
1427 | * register and polling the valid bit for completion. |
1428 | * |
1429 | * Polling mode uses the frame register but completion is indicated by |
1430 | * an interrupt. |
1431 | * |
1432 | */ |
1433 | int |
1434 | cas_mii_readreg(struct device *self, int phy, int reg) |
1435 | { |
1436 | struct cas_softc *sc = (void *)self; |
1437 | bus_space_tag_t t = sc->sc_memt; |
1438 | bus_space_handle_t mif = sc->sc_memh; |
1439 | int n; |
1440 | u_int32_t v; |
1441 | |
1442 | #ifdef CAS_DEBUG |
1443 | if (sc->sc_debug) |
1444 | printf("cas_mii_readreg: phy %d reg %d\n", phy, reg); |
1445 | #endif |
1446 | |
1447 | /* Construct the frame command */ |
1448 | v = (reg << CAS_MIF_REG_SHIFT18) | (phy << CAS_MIF_PHY_SHIFT23) | |
1449 | CAS_MIF_FRAME_READ0x60020000; |
1450 | |
1451 | bus_space_write_4(t, mif, CAS_MIF_FRAME, v)((t)->write_4((mif), (0x620c), (v))); |
1452 | for (n = 0; n < 100; n++) { |
1453 | DELAY(1)(*delay_func)(1); |
1454 | v = bus_space_read_4(t, mif, CAS_MIF_FRAME)((t)->read_4((mif), (0x620c))); |
1455 | if (v & CAS_MIF_FRAME_TA00x00010000) |
1456 | return (v & CAS_MIF_FRAME_DATA0x0000ffff); |
1457 | } |
1458 | |
1459 | printf("%s: mii_read timeout\n", sc->sc_dev.dv_xname); |
1460 | return (0); |
1461 | } |
1462 | |
1463 | void |
1464 | cas_mii_writereg(struct device *self, int phy, int reg, int val) |
1465 | { |
1466 | struct cas_softc *sc = (void *)self; |
1467 | bus_space_tag_t t = sc->sc_memt; |
1468 | bus_space_handle_t mif = sc->sc_memh; |
1469 | int n; |
1470 | u_int32_t v; |
1471 | |
1472 | #ifdef CAS_DEBUG |
1473 | if (sc->sc_debug) |
1474 | printf("cas_mii_writereg: phy %d reg %d val %x\n", |
1475 | phy, reg, val); |
1476 | #endif |
1477 | |
1478 | /* Construct the frame command */ |
1479 | v = CAS_MIF_FRAME_WRITE0x50020000 | |
1480 | (phy << CAS_MIF_PHY_SHIFT23) | |
1481 | (reg << CAS_MIF_REG_SHIFT18) | |
1482 | (val & CAS_MIF_FRAME_DATA0x0000ffff); |
1483 | |
1484 | bus_space_write_4(t, mif, CAS_MIF_FRAME, v)((t)->write_4((mif), (0x620c), (v))); |
1485 | for (n = 0; n < 100; n++) { |
1486 | DELAY(1)(*delay_func)(1); |
1487 | v = bus_space_read_4(t, mif, CAS_MIF_FRAME)((t)->read_4((mif), (0x620c))); |
1488 | if (v & CAS_MIF_FRAME_TA00x00010000) |
1489 | return; |
1490 | } |
1491 | |
1492 | printf("%s: mii_write timeout\n", sc->sc_dev.dv_xname); |
1493 | } |
1494 | |
1495 | void |
1496 | cas_mii_statchg(struct device *dev) |
1497 | { |
1498 | struct cas_softc *sc = (void *)dev; |
1499 | #ifdef CAS_DEBUG |
1500 | uint64_t instance = IFM_INST(sc->sc_mii.mii_media.ifm_cur->ifm_media)(((sc->sc_mii.mii_media.ifm_cur->ifm_media) & 0xff00000000000000ULL ) >> 56); |
1501 | #endif |
1502 | bus_space_tag_t t = sc->sc_memt; |
1503 | bus_space_handle_t mac = sc->sc_memh; |
1504 | u_int32_t v; |
1505 | |
1506 | #ifdef CAS_DEBUG |
1507 | if (sc->sc_debug) |
1508 | printf("cas_mii_statchg: status change: phy = %d\n", |
1509 | sc->sc_phys[instance]); |
1510 | #endif |
1511 | |
1512 | /* Set tx full duplex options */ |
1513 | bus_space_write_4(t, mac, CAS_MAC_TX_CONFIG, 0)((t)->write_4((mac), (0x6030), (0))); |
1514 | delay(10000)(*delay_func)(10000); /* reg must be cleared and delay before changing. */ |
1515 | v = CAS_MAC_TX_ENA_IPG00x00000008|CAS_MAC_TX_NGU0x00000010|CAS_MAC_TX_NGU_LIMIT0x00000020| |
1516 | CAS_MAC_TX_ENABLE0x00000001; |
1517 | if ((IFM_OPTIONS(sc->sc_mii.mii_media_active)((sc->sc_mii.mii_media_active) & (0x00000000ffff0000ULL |0x00ffff0000000000ULL)) & IFM_FDX0x0000010000000000ULL) != 0) { |
1518 | v |= CAS_MAC_TX_IGN_CARRIER0x00000002|CAS_MAC_TX_IGN_COLLIS0x00000004; |
1519 | } |
1520 | bus_space_write_4(t, mac, CAS_MAC_TX_CONFIG, v)((t)->write_4((mac), (0x6030), (v))); |
1521 | |
1522 | /* XIF Configuration */ |
1523 | v = CAS_MAC_XIF_TX_MII_ENA0x00000001; |
1524 | v |= CAS_MAC_XIF_LINK_LED0x00000020; |
1525 | |
1526 | /* MII needs echo disable if half duplex. */ |
1527 | if ((IFM_OPTIONS(sc->sc_mii.mii_media_active)((sc->sc_mii.mii_media_active) & (0x00000000ffff0000ULL |0x00ffff0000000000ULL)) & IFM_FDX0x0000010000000000ULL) != 0) |
1528 | /* turn on full duplex LED */ |
1529 | v |= CAS_MAC_XIF_FDPLX_LED0x00000040; |
1530 | else |
1531 | /* half duplex -- disable echo */ |
1532 | v |= CAS_MAC_XIF_ECHO_DISABL0x00000004; |
1533 | |
1534 | switch (IFM_SUBTYPE(sc->sc_mii.mii_media_active)((sc->sc_mii.mii_media_active) & 0x00000000000000ffULL )) { |
1535 | case IFM_1000_T16: /* Gigabit using GMII interface */ |
1536 | case IFM_1000_SX11: |
1537 | v |= CAS_MAC_XIF_GMII_MODE0x00000008; |
1538 | break; |
1539 | default: |
1540 | v &= ~CAS_MAC_XIF_GMII_MODE0x00000008; |
1541 | } |
1542 | bus_space_write_4(t, mac, CAS_MAC_XIF_CONFIG, v)((t)->write_4((mac), (0x603c), (v))); |
1543 | } |
1544 | |
1545 | int |
1546 | cas_pcs_readreg(struct device *self, int phy, int reg) |
1547 | { |
1548 | struct cas_softc *sc = (void *)self; |
1549 | bus_space_tag_t t = sc->sc_memt; |
1550 | bus_space_handle_t pcs = sc->sc_memh; |
1551 | |
1552 | #ifdef CAS_DEBUG |
1553 | if (sc->sc_debug) |
1554 | printf("cas_pcs_readreg: phy %d reg %d\n", phy, reg); |
1555 | #endif |
1556 | |
1557 | if (phy != CAS_PHYAD_EXTERNAL0) |
1558 | return (0); |
1559 | |
1560 | switch (reg) { |
1561 | case MII_BMCR0x00: |
1562 | reg = CAS_MII_CONTROL0x9000; |
1563 | break; |
1564 | case MII_BMSR0x01: |
1565 | reg = CAS_MII_STATUS0x9004; |
1566 | break; |
1567 | case MII_ANAR0x04: |
1568 | reg = CAS_MII_ANAR0x9008; |
1569 | break; |
1570 | case MII_ANLPAR0x05: |
1571 | reg = CAS_MII_ANLPAR0x900c; |
1572 | break; |
1573 | case MII_EXTSR0x0f: |
1574 | return (EXTSR_1000XFDX0x8000|EXTSR_1000XHDX0x4000); |
1575 | default: |
1576 | return (0); |
1577 | } |
1578 | |
1579 | return bus_space_read_4(t, pcs, reg)((t)->read_4((pcs), (reg))); |
1580 | } |
1581 | |
1582 | void |
1583 | cas_pcs_writereg(struct device *self, int phy, int reg, int val) |
1584 | { |
1585 | struct cas_softc *sc = (void *)self; |
1586 | bus_space_tag_t t = sc->sc_memt; |
1587 | bus_space_handle_t pcs = sc->sc_memh; |
1588 | int reset = 0; |
1589 | |
1590 | #ifdef CAS_DEBUG |
1591 | if (sc->sc_debug) |
1592 | printf("cas_pcs_writereg: phy %d reg %d val %x\n", |
1593 | phy, reg, val); |
1594 | #endif |
1595 | |
1596 | if (phy != CAS_PHYAD_EXTERNAL0) |
1597 | return; |
1598 | |
1599 | if (reg == MII_ANAR0x04) |
1600 | bus_space_write_4(t, pcs, CAS_MII_CONFIG, 0)((t)->write_4((pcs), (0x9010), (0))); |
1601 | |
1602 | switch (reg) { |
1603 | case MII_BMCR0x00: |
1604 | reset = (val & CAS_MII_CONTROL_RESET0x00008000); |
1605 | reg = CAS_MII_CONTROL0x9000; |
1606 | break; |
1607 | case MII_BMSR0x01: |
1608 | reg = CAS_MII_STATUS0x9004; |
1609 | break; |
1610 | case MII_ANAR0x04: |
1611 | reg = CAS_MII_ANAR0x9008; |
1612 | break; |
1613 | case MII_ANLPAR0x05: |
1614 | reg = CAS_MII_ANLPAR0x900c; |
1615 | break; |
1616 | default: |
1617 | return; |
1618 | } |
1619 | |
1620 | bus_space_write_4(t, pcs, reg, val)((t)->write_4((pcs), (reg), (val))); |
1621 | |
1622 | if (reset) |
1623 | cas_bitwait(sc, pcs, CAS_MII_CONTROL0x9000, CAS_MII_CONTROL_RESET0x00008000, 0); |
1624 | |
1625 | if (reg == CAS_MII_ANAR0x9008 || reset) |
1626 | bus_space_write_4(t, pcs, CAS_MII_CONFIG,((t)->write_4((pcs), (0x9010), (0x00000001))) |
1627 | CAS_MII_CONFIG_ENABLE)((t)->write_4((pcs), (0x9010), (0x00000001))); |
1628 | } |
1629 | |
1630 | int |
1631 | cas_mediachange(struct ifnet *ifp) |
1632 | { |
1633 | struct cas_softc *sc = ifp->if_softc; |
1634 | struct mii_data *mii = &sc->sc_mii; |
1635 | |
1636 | if (mii->mii_instance) { |
1637 | struct mii_softc *miisc; |
1638 | LIST_FOREACH(miisc, &mii->mii_phys, mii_list)for((miisc) = ((&mii->mii_phys)->lh_first); (miisc) != ((void *)0); (miisc) = ((miisc)->mii_list.le_next)) |
1639 | mii_phy_reset(miisc); |
1640 | } |
1641 | |
1642 | return (mii_mediachg(&sc->sc_mii)); |
1643 | } |
1644 | |
1645 | void |
1646 | cas_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) |
1647 | { |
1648 | struct cas_softc *sc = ifp->if_softc; |
1649 | |
1650 | mii_pollstat(&sc->sc_mii); |
1651 | ifmr->ifm_active = sc->sc_mii.mii_media_active; |
1652 | ifmr->ifm_status = sc->sc_mii.mii_media_status; |
1653 | } |
1654 | |
1655 | /* |
1656 | * Process an ioctl request. |
1657 | */ |
1658 | int |
1659 | cas_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) |
1660 | { |
1661 | struct cas_softc *sc = ifp->if_softc; |
1662 | struct ifreq *ifr = (struct ifreq *)data; |
1663 | int s, error = 0; |
1664 | |
1665 | s = splnet()splraise(0x4); |
1666 | |
1667 | switch (cmd) { |
1668 | case SIOCSIFADDR((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((12))): |
1669 | ifp->if_flags |= IFF_UP0x1; |
1670 | if ((ifp->if_flags & IFF_RUNNING0x40) == 0) |
1671 | cas_init(ifp); |
1672 | break; |
1673 | |
1674 | case SIOCSIFFLAGS((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((16))): |
1675 | if (ifp->if_flags & IFF_UP0x1) { |
1676 | if (ifp->if_flags & IFF_RUNNING0x40) |
1677 | error = ENETRESET52; |
1678 | else |
1679 | cas_init(ifp); |
1680 | } else { |
1681 | if (ifp->if_flags & IFF_RUNNING0x40) |
1682 | cas_stop(ifp, 1); |
1683 | } |
1684 | #ifdef CAS_DEBUG |
1685 | sc->sc_debug = (ifp->if_flags & IFF_DEBUG0x4) != 0 ? 1 : 0; |
1686 | #endif |
1687 | break; |
1688 | |
1689 | case SIOCGIFMEDIA(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct ifmediareq) & 0x1fff) << 16) | ((('i')) << 8) | ((56))): |
1690 | case SIOCSIFMEDIA(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct ifreq) & 0x1fff) << 16) | ((('i')) << 8) | ((55))): |
1691 | error = ifmedia_ioctl(ifp, ifr, &sc->sc_mediasc_mii.mii_media, cmd); |
1692 | break; |
1693 | |
1694 | default: |
1695 | error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data); |
1696 | } |
1697 | |
1698 | if (error == ENETRESET52) { |
1699 | if (ifp->if_flags & IFF_RUNNING0x40) |
1700 | cas_iff(sc); |
1701 | error = 0; |
1702 | } |
1703 | |
1704 | splx(s)spllower(s); |
1705 | return (error); |
1706 | } |
1707 | |
1708 | void |
1709 | cas_iff(struct cas_softc *sc) |
1710 | { |
1711 | struct ifnet *ifp = &sc->sc_arpcom.ac_if; |
1712 | struct arpcom *ac = &sc->sc_arpcom; |
1713 | struct ether_multi *enm; |
1714 | struct ether_multistep step; |
1715 | bus_space_tag_t t = sc->sc_memt; |
1716 | bus_space_handle_t h = sc->sc_memh; |
1717 | u_int32_t crc, hash[16], rxcfg; |
1718 | int i; |
1719 | |
1720 | rxcfg = bus_space_read_4(t, h, CAS_MAC_RX_CONFIG)((t)->read_4((h), (0x6034))); |
1721 | rxcfg &= ~(CAS_MAC_RX_HASH_FILTER0x00000020 | CAS_MAC_RX_PROMISCUOUS0x00000008 | |
1722 | CAS_MAC_RX_PROMISC_GRP0x00000010); |
1723 | ifp->if_flags &= ~IFF_ALLMULTI0x200; |
1724 | |
1725 | if (ifp->if_flags & IFF_PROMISC0x100 || ac->ac_multirangecnt > 0) { |
1726 | ifp->if_flags |= IFF_ALLMULTI0x200; |
1727 | if (ifp->if_flags & IFF_PROMISC0x100) |
1728 | rxcfg |= CAS_MAC_RX_PROMISCUOUS0x00000008; |
1729 | else |
1730 | rxcfg |= CAS_MAC_RX_PROMISC_GRP0x00000010; |
1731 | } else { |
1732 | /* |
1733 | * Set up multicast address filter by passing all multicast |
1734 | * addresses through a crc generator, and then using the |
1735 | * high order 8 bits as an index into the 256 bit logical |
1736 | * address filter. The high order 4 bits selects the word, |
1737 | * while the other 4 bits select the bit within the word |
1738 | * (where bit 0 is the MSB). |
1739 | */ |
1740 | |
1741 | rxcfg |= CAS_MAC_RX_HASH_FILTER0x00000020; |
1742 | |
1743 | /* Clear hash table */ |
1744 | for (i = 0; i < 16; i++) |
1745 | hash[i] = 0; |
1746 | |
1747 | ETHER_FIRST_MULTI(step, ac, enm)do { (step).e_enm = ((&(ac)->ac_multiaddrs)->lh_first ); do { if ((((enm)) = ((step)).e_enm) != ((void *)0)) ((step )).e_enm = ((((enm)))->enm_list.le_next); } while ( 0); } while ( 0); |
1748 | while (enm != NULL((void *)0)) { |
1749 | crc = ether_crc32_le(enm->enm_addrlo, |
1750 | ETHER_ADDR_LEN6); |
1751 | |
1752 | /* Just want the 8 most significant bits. */ |
1753 | crc >>= 24; |
1754 | |
1755 | /* Set the corresponding bit in the filter. */ |
1756 | hash[crc >> 4] |= 1 << (15 - (crc & 15)); |
1757 | |
1758 | ETHER_NEXT_MULTI(step, enm)do { if (((enm) = (step).e_enm) != ((void *)0)) (step).e_enm = (((enm))->enm_list.le_next); } while ( 0); |
1759 | } |
1760 | |
1761 | /* Now load the hash table into the chip (if we are using it) */ |
1762 | for (i = 0; i < 16; i++) { |
1763 | bus_space_write_4(t, h,((t)->write_4((h), (0x6160 + i * (0x6164 - 0x6160)), (hash [i]))) |
1764 | CAS_MAC_HASH0 + i * (CAS_MAC_HASH1 - CAS_MAC_HASH0),((t)->write_4((h), (0x6160 + i * (0x6164 - 0x6160)), (hash [i]))) |
1765 | hash[i])((t)->write_4((h), (0x6160 + i * (0x6164 - 0x6160)), (hash [i]))); |
1766 | } |
1767 | } |
1768 | |
1769 | bus_space_write_4(t, h, CAS_MAC_RX_CONFIG, rxcfg)((t)->write_4((h), (0x6034), (rxcfg))); |
1770 | } |
1771 | |
1772 | int |
1773 | cas_encap(struct cas_softc *sc, struct mbuf *m, int *used) |
1774 | { |
1775 | u_int64_t flags; |
1776 | u_int32_t first, cur, frag, i; |
1777 | bus_dmamap_t map; |
1778 | |
1779 | cur = frag = (sc->sc_tx_prod + *used) % CAS_NTXDESC(64 * 16); |
1780 | map = sc->sc_txd[cur].sd_map; |
1781 | |
1782 | switch (bus_dmamap_load_mbuf(sc->sc_dmatag, map, m, BUS_DMA_NOWAIT)(*(sc->sc_dmatag)->_dmamap_load_mbuf)((sc->sc_dmatag ), (map), (m), (0x0001))) { |
1783 | case 0: |
1784 | break; |
1785 | case EFBIG27: |
1786 | if (m_defrag(m, M_DONTWAIT0x0002) == 0 && |
1787 | bus_dmamap_load_mbuf(sc->sc_dmatag, map, m,(*(sc->sc_dmatag)->_dmamap_load_mbuf)((sc->sc_dmatag ), (map), (m), (0x0001)) |
1788 | BUS_DMA_NOWAIT)(*(sc->sc_dmatag)->_dmamap_load_mbuf)((sc->sc_dmatag ), (map), (m), (0x0001)) == 0) |
1789 | break; |
1790 | /* FALLTHROUGH */ |
1791 | default: |
1792 | return (ENOBUFS55); |
1793 | } |
1794 | |
1795 | bus_dmamap_sync(sc->sc_dmatag, map, 0, map->dm_mapsize,(*(sc->sc_dmatag)->_dmamap_sync)((sc->sc_dmatag), (map ), (0), (map->dm_mapsize), (0x04)) |
1796 | BUS_DMASYNC_PREWRITE)(*(sc->sc_dmatag)->_dmamap_sync)((sc->sc_dmatag), (map ), (0), (map->dm_mapsize), (0x04)); |
1797 | |
1798 | first = cur; |
1799 | for (i = 0; i < map->dm_nsegs; i++) { |
1800 | sc->sc_txdescssc_control_data->ccd_txdescs[frag].cd_addr = |
1801 | CAS_DMA_WRITE(map->dm_segs[i].ds_addr)((__uint64_t)(map->dm_segs[i].ds_addr)); |
1802 | flags = (map->dm_segs[i].ds_len & CAS_TD_BUFSIZE0x0000000000007fffLL) | |
1803 | (i == 0 ? CAS_TD_START_OF_PACKET0x0000000080000000LL : 0) | |
1804 | ((i == (map->dm_nsegs - 1)) ? CAS_TD_END_OF_PACKET0x0000000040000000LL : 0); |
1805 | sc->sc_txdescssc_control_data->ccd_txdescs[frag].cd_flags = CAS_DMA_WRITE(flags)((__uint64_t)(flags)); |
1806 | bus_dmamap_sync(sc->sc_dmatag, sc->sc_cddmamap,(*(sc->sc_dmatag)->_dmamap_sync)((sc->sc_dmatag), (sc ->sc_cddmamap), (__builtin_offsetof(struct cas_control_data , ccd_txdescs[(frag)])), (sizeof(struct cas_desc)), (0x04)) |
1807 | CAS_CDTXOFF(frag), sizeof(struct cas_desc),(*(sc->sc_dmatag)->_dmamap_sync)((sc->sc_dmatag), (sc ->sc_cddmamap), (__builtin_offsetof(struct cas_control_data , ccd_txdescs[(frag)])), (sizeof(struct cas_desc)), (0x04)) |
1808 | BUS_DMASYNC_PREWRITE)(*(sc->sc_dmatag)->_dmamap_sync)((sc->sc_dmatag), (sc ->sc_cddmamap), (__builtin_offsetof(struct cas_control_data , ccd_txdescs[(frag)])), (sizeof(struct cas_desc)), (0x04)); |
1809 | cur = frag; |
1810 | if (++frag == CAS_NTXDESC(64 * 16)) |
1811 | frag = 0; |
1812 | } |
1813 | |
1814 | sc->sc_txd[first].sd_map = sc->sc_txd[cur].sd_map; |
1815 | sc->sc_txd[cur].sd_map = map; |
1816 | sc->sc_txd[cur].sd_mbuf = m; |
1817 | |
1818 | bus_space_write_4(sc->sc_memt, sc->sc_memh, CAS_TX_KICK, frag)((sc->sc_memt)->write_4((sc->sc_memh), (0x2040), (frag ))); |
1819 | |
1820 | *used += map->dm_nsegs; |
1821 | |
1822 | /* sync descriptors */ |
1823 | |
1824 | return (0); |
1825 | } |
1826 | |
1827 | /* |
1828 | * Transmit interrupt. |
1829 | */ |
1830 | int |
1831 | cas_tint(struct cas_softc *sc, u_int32_t status) |
1832 | { |
1833 | struct ifnet *ifp = &sc->sc_arpcom.ac_if; |
1834 | struct cas_sxd *sd; |
1835 | u_int32_t cons, comp; |
1836 | int freed, used; |
1837 | |
1838 | comp = bus_space_read_4(sc->sc_memt, sc->sc_memh, CAS_TX_COMPLETION)((sc->sc_memt)->read_4((sc->sc_memh), (0x2050))); |
1839 | cons = sc->sc_tx_cons; |
1840 | freed = 0; |
1841 | while (cons != comp) { |
1842 | sd = &sc->sc_txd[cons]; |
1843 | if (sd->sd_mbuf != NULL((void *)0)) { |
1844 | bus_dmamap_sync(sc->sc_dmatag, sd->sd_map, 0,(*(sc->sc_dmatag)->_dmamap_sync)((sc->sc_dmatag), (sd ->sd_map), (0), (sd->sd_map->dm_mapsize), (0x08)) |
1845 | sd->sd_map->dm_mapsize, BUS_DMASYNC_POSTWRITE)(*(sc->sc_dmatag)->_dmamap_sync)((sc->sc_dmatag), (sd ->sd_map), (0), (sd->sd_map->dm_mapsize), (0x08)); |
1846 | bus_dmamap_unload(sc->sc_dmatag, sd->sd_map)(*(sc->sc_dmatag)->_dmamap_unload)((sc->sc_dmatag), ( sd->sd_map)); |
1847 | m_freem(sd->sd_mbuf); |
1848 | sd->sd_mbuf = NULL((void *)0); |
1849 | } |
1850 | freed++; |
1851 | if (++cons == CAS_NTXDESC(64 * 16)) |
1852 | cons = 0; |
1853 | } |
1854 | sc->sc_tx_cons = cons; |
1855 | |
1856 | used = atomic_sub_int_nv(&sc->sc_tx_cnt, freed)_atomic_sub_int_nv(&sc->sc_tx_cnt, freed); |
1857 | if (used < CAS_NTXDESC(64 * 16) - 2) |
1858 | ifq_clr_oactive(&ifp->if_snd); |
1859 | if (used == 0) |
1860 | ifp->if_timer = 0; |
1861 | |
1862 | if (!ifq_empty(&ifp->if_snd)(({ typeof((&ifp->if_snd)->ifq_len) __tmp = *(volatile typeof((&ifp->if_snd)->ifq_len) *)&((&ifp-> if_snd)->ifq_len); membar_datadep_consumer(); __tmp; }) == 0)) { |
1863 | KERNEL_LOCK()_kernel_lock(); |
1864 | cas_start(ifp); |
1865 | KERNEL_UNLOCK()_kernel_unlock(); |
1866 | } |
1867 | |
1868 | return (1); |
1869 | } |
1870 | |
1871 | void |
1872 | cas_start(struct ifnet *ifp) |
1873 | { |
1874 | struct cas_softc *sc = ifp->if_softc; |
1875 | struct mbuf *m = NULL((void *)0); |
1876 | int used; |
1877 | |
1878 | if (!(ifp->if_flags & IFF_RUNNING0x40) || ifq_is_oactive(&ifp->if_snd)) |
1879 | return; |
1880 | |
1881 | used = 0; |
1882 | while (1) { |
1883 | if ((sc->sc_tx_cnt + used + CAS_NTXSEGS16) >= (CAS_NTXDESC(64 * 16) - 2)) { |
1884 | ifq_set_oactive(&ifp->if_snd); |
1885 | break; |
1886 | } |
1887 | |
1888 | m = ifq_dequeue(&ifp->if_snd); |
1889 | if (m == NULL((void *)0)) |
1890 | break; |
1891 | |
1892 | if (cas_encap(sc, m, &used)) { |
1893 | m_freem(m); |
1894 | continue; |
1895 | } |
1896 | |
1897 | #if NBPFILTER1 > 0 |
1898 | if (ifp->if_bpf) |
1899 | bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT(1 << 1)); |
1900 | #endif |
1901 | } |
1902 | |
1903 | if (used != 0) { |
1904 | ifp->if_timer = 5; |
1905 | sc->sc_tx_prod = (sc->sc_tx_prod + used) % CAS_NTXDESC(64 * 16); |
1906 | atomic_add_int(&sc->sc_tx_cnt, used)_atomic_add_int(&sc->sc_tx_cnt, used); |
1907 | } |
1908 | } |