Annotation of sys/dev/pci/if_vic.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: if_vic.c,v 1.49 2007/06/15 02:29:50 dlg Exp $ */
2:
3: /*
4: * Copyright (c) 2006 Reyk Floeter <reyk@openbsd.org>
5: * Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
6: *
7: * Permission to use, copy, modify, and distribute this software for any
8: * purpose with or without fee is hereby granted, provided that the above
9: * copyright notice and this permission notice appear in all copies.
10: *
11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18: */
19:
20: /*
21: * Driver for the VMware Virtual NIC ("vmxnet")
22: */
23:
24: #include "bpfilter.h"
25:
26: #include <sys/param.h>
27: #include <sys/systm.h>
28: #include <sys/sockio.h>
29: #include <sys/mbuf.h>
30: #include <sys/kernel.h>
31: #include <sys/socket.h>
32: #include <sys/malloc.h>
33: #include <sys/timeout.h>
34: #include <sys/device.h>
35:
36: #include <machine/bus.h>
37: #include <machine/intr.h>
38:
39: #include <net/if.h>
40: #include <net/if_dl.h>
41: #include <net/if_media.h>
42: #include <net/if_types.h>
43:
44: #if NBPFILTER > 0
45: #include <net/bpf.h>
46: #endif
47:
48: #ifdef INET
49: #include <netinet/in.h>
50: #include <netinet/if_ether.h>
51: #endif
52:
53: #include <dev/pci/pcireg.h>
54: #include <dev/pci/pcivar.h>
55: #include <dev/pci/pcidevs.h>
56:
57: #define VIC_PCI_BAR PCI_MAPREG_START /* Base Address Register */
58:
59: #define VIC_MAGIC 0xbabe864f
60:
61: /* Register address offsets */
62: #define VIC_DATA_ADDR 0x0000 /* Shared data address */
63: #define VIC_DATA_LENGTH 0x0004 /* Shared data length */
64: #define VIC_Tx_ADDR 0x0008 /* Tx pointer address */
65:
66: /* Command register */
67: #define VIC_CMD 0x000c /* Command register */
68: #define VIC_CMD_INTR_ACK 0x0001 /* Acknowledge interrupt */
69: #define VIC_CMD_MCASTFIL 0x0002 /* Multicast address filter */
70: #define VIC_CMD_MCASTFIL_LENGTH 2
71: #define VIC_CMD_IFF 0x0004 /* Interface flags */
72: #define VIC_CMD_IFF_PROMISC 0x0001 /* Promiscous enabled */
73: #define VIC_CMD_IFF_BROADCAST 0x0002 /* Broadcast enabled */
74: #define VIC_CMD_IFF_MULTICAST 0x0004 /* Multicast enabled */
75: #define VIC_CMD_INTR_DISABLE 0x0020 /* Enable interrupts */
76: #define VIC_CMD_INTR_ENABLE 0x0040 /* Disable interrupts */
77: #define VIC_CMD_Tx_DONE 0x0100 /* Tx done register */
78: #define VIC_CMD_NUM_Rx_BUF 0x0200 /* Number of Rx buffers */
79: #define VIC_CMD_NUM_Tx_BUF 0x0400 /* Number of Tx buffers */
80: #define VIC_CMD_NUM_PINNED_BUF 0x0800 /* Number of pinned buffers */
81: #define VIC_CMD_HWCAP 0x1000 /* Capability register */
82: #define VIC_CMD_HWCAP_SG (1<<0) /* Scatter-gather transmits */
83: #define VIC_CMD_HWCAP_CSUM_IPv4 (1<<1) /* TCP/UDP cksum */
84: #define VIC_CMD_HWCAP_CSUM_ALL (1<<3) /* Hardware cksum */
85: #define VIC_CMD_HWCAP_CSUM \
86: (VIC_CMD_HWCAP_CSUM_IPv4 | VIC_CMD_HWCAP_CSUM_ALL)
87: #define VIC_CMD_HWCAP_DMA_HIGH (1<<4) /* High DMA mapping */
88: #define VIC_CMD_HWCAP_TOE (1<<5) /* TCP offload engine */
89: #define VIC_CMD_HWCAP_TSO (1<<6) /* TCP segmentation offload */
90: #define VIC_CMD_HWCAP_TSO_SW (1<<7) /* Software TCP segmentation */
91: #define VIC_CMD_HWCAP_VPROM (1<<8) /* Virtual PROM available */
92: #define VIC_CMD_HWCAP_VLAN_Tx (1<<9) /* Hardware VLAN MTU Rx */
93: #define VIC_CMD_HWCAP_VLAN_Rx (1<<10) /* Hardware VLAN MTU Tx */
94: #define VIC_CMD_HWCAP_VLAN_SW (1<<11) /* Software VLAN MTU */
95: #define VIC_CMD_HWCAP_VLAN \
96: (VIC_CMD_HWCAP_VLAN_Tx | VIC_CMD_HWCAP_VLAN_Rx | \
97: VIC_CMD_HWCAP_VLAN_SW)
98: #define VIC_CMD_HWCAP_BITS \
99: "\20\01SG\02CSUM4\03CSUM\04HDMA\05TOE\06TSO" \
100: "\07TSOSW\10VPROM\13VLANTx\14VLANRx\15VLANSW"
101: #define VIC_CMD_FEATURE 0x2000 /* Additional feature register */
102: #define VIC_CMD_FEATURE_0_Tx (1<<0)
103: #define VIC_CMD_FEATURE_TSO (1<<1)
104:
105: #define VIC_LLADDR 0x0010 /* MAC address register */
106: #define VIC_VERSION_MINOR 0x0018 /* Minor version register */
107: #define VIC_VERSION_MAJOR 0x001c /* Major version register */
108: #define VIC_VERSION_MAJOR_M 0xffff0000
109:
110: /* Status register */
111: #define VIC_STATUS 0x0020
112: #define VIC_STATUS_CONNECTED (1<<0)
113: #define VIC_STATUS_ENABLED (1<<1)
114:
115: #define VIC_TOE_ADDR 0x0024 /* TCP offload address */
116:
117: /* Virtual PROM address */
118: #define VIC_VPROM 0x0028
119: #define VIC_VPROM_LENGTH 6
120:
121: /* Shared DMA data structures */
122:
123: struct vic_sg {
124: u_int32_t sg_addr_low;
125: u_int16_t sg_addr_high;
126: u_int16_t sg_length;
127: } __packed;
128:
129: #define VIC_SG_MAX 6
130: #define VIC_SG_ADDR_MACH 0
131: #define VIC_SG_ADDR_PHYS 1
132: #define VIC_SG_ADDR_VIRT 3
133:
134: struct vic_sgarray {
135: u_int16_t sa_addr_type;
136: u_int16_t sa_length;
137: struct vic_sg sa_sg[VIC_SG_MAX];
138: } __packed;
139:
140: struct vic_rxdesc {
141: u_int64_t rx_physaddr;
142: u_int32_t rx_buflength;
143: u_int32_t rx_length;
144: u_int16_t rx_owner;
145: u_int16_t rx_flags;
146: u_int32_t rx_priv;
147: } __packed;
148:
149: #define VIC_RX_FLAGS_CSUMHW_OK 0x0001
150:
151: struct vic_txdesc {
152: u_int16_t tx_flags;
153: u_int16_t tx_owner;
154: u_int32_t tx_priv;
155: u_int32_t tx_tsomss;
156: struct vic_sgarray tx_sa;
157: } __packed;
158:
159: #define VIC_TX_FLAGS_KEEP 0x0001
160: #define VIC_TX_FLAGS_TXURN 0x0002
161: #define VIC_TX_FLAGS_CSUMHW 0x0004
162: #define VIC_TX_FLAGS_TSO 0x0008
163: #define VIC_TX_FLAGS_PINNED 0x0010
164: #define VIC_TX_FLAGS_QRETRY 0x1000
165:
166: struct vic_stats {
167: u_int32_t vs_tx_count;
168: u_int32_t vs_tx_packets;
169: u_int32_t vs_tx_0copy;
170: u_int32_t vs_tx_copy;
171: u_int32_t vs_tx_maxpending;
172: u_int32_t vs_tx_stopped;
173: u_int32_t vs_tx_overrun;
174: u_int32_t vs_intr;
175: u_int32_t vs_rx_packets;
176: u_int32_t vs_rx_underrun;
177: } __packed;
178:
179: struct vic_data {
180: u_int32_t vd_magic;
181:
182: u_int32_t vd_rx_length;
183: u_int32_t vd_rx_nextidx;
184: u_int32_t vd_rx_length2;
185: u_int32_t vd_rx_nextidx2;
186:
187: u_int32_t vd_irq;
188: u_int32_t vd_iff;
189:
190: u_int32_t vd_mcastfil[VIC_CMD_MCASTFIL_LENGTH];
191:
192: u_int32_t vd_reserved1[1];
193:
194: u_int32_t vd_tx_length;
195: u_int32_t vd_tx_curidx;
196: u_int32_t vd_tx_nextidx;
197: u_int32_t vd_tx_stopped;
198: u_int32_t vd_tx_triggerlvl;
199: u_int32_t vd_tx_queued;
200: u_int32_t vd_tx_minlength;
201:
202: u_int32_t vd_reserved2[6];
203:
204: u_int32_t vd_rx_saved_nextidx;
205: u_int32_t vd_rx_saved_nextidx2;
206: u_int32_t vd_tx_saved_nextidx;
207:
208: u_int32_t vd_length;
209: u_int32_t vd_rx_offset;
210: u_int32_t vd_rx_offset2;
211: u_int32_t vd_tx_offset;
212: u_int32_t vd_debug;
213: u_int32_t vd_tx_physaddr;
214: u_int32_t vd_tx_physaddr_length;
215: u_int32_t vd_tx_maxlength;
216:
217: struct vic_stats vd_stats;
218: } __packed;
219:
220: #define VIC_OWNER_DRIVER 0
221: #define VIC_OWNER_DRIVER_PEND 1
222: #define VIC_OWNER_NIC 2
223: #define VIC_OWNER_NIC_PEND 3
224:
225: #define VIC_JUMBO_FRAMELEN 9018
226: #define VIC_JUMBO_MTU (VIC_JUMBO_FRAMELEN - ETHER_HDR_LEN - ETHER_CRC_LEN)
227:
228: #define VIC_NBUF 100
229: #define VIC_NBUF_MAX 128
230: #define VIC_MAX_SCATTER 1 /* 8? */
231: #define VIC_QUEUE_SIZE VIC_NBUF_MAX
232: #define VIC_QUEUE2_SIZE 1
233: #define VIC_INC(_x, _y) (_x) = ((_x) + 1) % (_y)
234: #define VIC_TX_TIMEOUT 5
235:
236: #define VIC_MIN_FRAMELEN (ETHER_MIN_LEN - ETHER_CRC_LEN)
237:
238: #define VIC_TXURN_WARN(_sc) ((_sc)->sc_txpending >= ((_sc)->sc_ntxbuf - 5))
239: #define VIC_TXURN(_sc) ((_sc)->sc_txpending >= (_sc)->sc_ntxbuf)
240:
241: struct vic_rxbuf {
242: bus_dmamap_t rxb_dmamap;
243: struct mbuf *rxb_m;
244: };
245:
246: struct vic_txbuf {
247: bus_dmamap_t txb_dmamap;
248: struct mbuf *txb_m;
249: };
250:
251: struct vic_softc {
252: struct device sc_dev;
253:
254: pci_chipset_tag_t sc_pc;
255: pcitag_t sc_tag;
256:
257: bus_space_tag_t sc_iot;
258: bus_space_handle_t sc_ioh;
259: bus_size_t sc_ios;
260: bus_dma_tag_t sc_dmat;
261:
262: void *sc_ih;
263:
264: struct timeout sc_tick;
265:
266: struct arpcom sc_ac;
267: struct ifmedia sc_media;
268:
269: u_int32_t sc_nrxbuf;
270: u_int32_t sc_ntxbuf;
271: u_int32_t sc_cap;
272: u_int32_t sc_feature;
273: u_int8_t sc_lladdr[ETHER_ADDR_LEN];
274:
275: bus_dmamap_t sc_dma_map;
276: bus_dma_segment_t sc_dma_seg;
277: size_t sc_dma_size;
278: caddr_t sc_dma_kva;
279: #define VIC_DMA_DVA(_sc) ((_sc)->sc_dma_map->dm_segs[0].ds_addr)
280: #define VIC_DMA_KVA(_sc) ((void *)(_sc)->sc_dma_kva)
281:
282: struct vic_data *sc_data;
283:
284: struct vic_rxbuf *sc_rxbuf;
285: struct vic_rxdesc *sc_rxq;
286: struct vic_rxdesc *sc_rxq2;
287:
288: struct vic_txbuf *sc_txbuf;
289: struct vic_txdesc *sc_txq;
290: volatile u_int sc_txpending;
291: };
292:
293: struct cfdriver vic_cd = {
294: 0, "vic", DV_IFNET
295: };
296:
297: int vic_match(struct device *, void *, void *);
298: void vic_attach(struct device *, struct device *, void *);
299:
300: struct cfattach vic_ca = {
301: sizeof(struct vic_softc), vic_match, vic_attach
302: };
303:
304: int vic_intr(void *);
305: void vic_shutdown(void *);
306:
307: int vic_map_pci(struct vic_softc *, struct pci_attach_args *);
308: int vic_query(struct vic_softc *);
309: int vic_alloc_data(struct vic_softc *);
310: int vic_init_data(struct vic_softc *sc);
311: int vic_uninit_data(struct vic_softc *sc);
312:
313: u_int32_t vic_read(struct vic_softc *, bus_size_t);
314: void vic_write(struct vic_softc *, bus_size_t, u_int32_t);
315:
316: u_int32_t vic_read_cmd(struct vic_softc *, u_int32_t);
317:
318: int vic_alloc_dmamem(struct vic_softc *);
319: void vic_free_dmamem(struct vic_softc *);
320:
321: void vic_link_state(struct vic_softc *);
322: void vic_rx_proc(struct vic_softc *);
323: void vic_tx_proc(struct vic_softc *);
324: void vic_iff(struct vic_softc *);
325: void vic_getlladdr(struct vic_softc *);
326: void vic_setlladdr(struct vic_softc *);
327: int vic_media_change(struct ifnet *);
328: void vic_media_status(struct ifnet *, struct ifmediareq *);
329: void vic_start(struct ifnet *);
330: int vic_load_txb(struct vic_softc *, struct vic_txbuf *,
331: struct mbuf *);
332: void vic_watchdog(struct ifnet *);
333: int vic_ioctl(struct ifnet *, u_long, caddr_t);
334: void vic_init(struct ifnet *);
335: void vic_stop(struct ifnet *);
336: void vic_tick(void *);
337:
338: #define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
339:
340: struct mbuf *vic_alloc_mbuf(struct vic_softc *, bus_dmamap_t);
341:
342: const struct pci_matchid vic_devices[] = {
343: { PCI_VENDOR_VMWARE, PCI_PRODUCT_VMWARE_NET }
344: };
345:
346: int
347: vic_match(struct device *parent, void *match, void *aux)
348: {
349: return (pci_matchbyid((struct pci_attach_args *)aux,
350: vic_devices, sizeof(vic_devices)/sizeof(vic_devices[0])));
351: }
352:
353: void
354: vic_attach(struct device *parent, struct device *self, void *aux)
355: {
356: struct vic_softc *sc = (struct vic_softc *)self;
357: struct pci_attach_args *pa = aux;
358: struct ifnet *ifp;
359:
360: if (vic_map_pci(sc, pa) != 0) {
361: /* error printed by vic_map_pci */
362: return;
363: }
364:
365: if (vic_query(sc) != 0) {
366: /* error printed by vic_query */
367: return;
368: }
369:
370: if (vic_alloc_data(sc) != 0) {
371: /* error printed by vic_alloc */
372: return;
373: }
374:
375: timeout_set(&sc->sc_tick, vic_tick, sc);
376:
377: bcopy(sc->sc_lladdr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN);
378:
379: ifp = &sc->sc_ac.ac_if;
380: ifp->if_softc = sc;
381: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
382: ifp->if_ioctl = vic_ioctl;
383: ifp->if_start = vic_start;
384: ifp->if_watchdog = vic_watchdog;
385: ifp->if_hardmtu = VIC_JUMBO_MTU;
386: strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
387: IFQ_SET_MAXLEN(&ifp->if_snd, sc->sc_ntxbuf - 1);
388: IFQ_SET_READY(&ifp->if_snd);
389:
390: ifp->if_capabilities = IFCAP_VLAN_MTU;
391:
392: #if 0
393: /* XXX interface capabilities */
394: if (sc->sc_cap & VIC_CMD_HWCAP_VLAN)
395: ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
396: if (sc->sc_cap & VIC_CMD_HWCAP_CSUM)
397: ifp->if_capabilities |= IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 |
398: IFCAP_CSUM_UDPv4;
399: #endif
400:
401: ifmedia_init(&sc->sc_media, 0, vic_media_change, vic_media_status);
402: ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
403: ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
404:
405: if_attach(ifp);
406: ether_ifattach(ifp);
407:
408: return;
409: }
410:
411: int
412: vic_map_pci(struct vic_softc *sc, struct pci_attach_args *pa)
413: {
414: pcireg_t memtype;
415: pci_intr_handle_t ih;
416: const char *intrstr;
417:
418: sc->sc_pc = pa->pa_pc;
419: sc->sc_tag = pa->pa_tag;
420: sc->sc_dmat = pa->pa_dmat;
421:
422: memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, VIC_PCI_BAR);
423: if (pci_mapreg_map(pa, VIC_PCI_BAR, memtype, 0, &sc->sc_iot,
424: &sc->sc_ioh, NULL, &sc->sc_ios, 0) != 0) {
425: printf(": unable to map system interface register\n");
426: return (1);
427: }
428:
429: if (pci_intr_map(pa, &ih) != 0) {
430: printf(": unable to map interrupt\n");
431: goto unmap;
432: }
433:
434: intrstr = pci_intr_string(pa->pa_pc, ih);
435: sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET,
436: vic_intr, sc, DEVNAME(sc));
437: if (sc->sc_ih == NULL) {
438: printf(": unable to map interrupt%s%s\n",
439: intrstr == NULL ? "" : " at ",
440: intrstr == NULL ? "" : intrstr);
441: goto unmap;
442: }
443: printf(": %s\n", intrstr);
444:
445: return (0);
446:
447: unmap:
448: bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
449: sc->sc_ios = 0;
450: return (1);
451: }
452:
453: int
454: vic_query(struct vic_softc *sc)
455: {
456: u_int32_t major, minor;
457:
458: major = vic_read(sc, VIC_VERSION_MAJOR);
459: minor = vic_read(sc, VIC_VERSION_MINOR);
460:
461: /* Check for a supported version */
462: if ((major & VIC_VERSION_MAJOR_M) !=
463: (VIC_MAGIC & VIC_VERSION_MAJOR_M)) {
464: printf("%s: magic mismatch\n", DEVNAME(sc));
465: return (1);
466: }
467:
468: if (VIC_MAGIC > major || VIC_MAGIC < minor) {
469: printf("%s: unsupported version (%X)\n", DEVNAME(sc),
470: major & ~VIC_VERSION_MAJOR_M);
471: return (1);
472: }
473:
474: sc->sc_nrxbuf = vic_read_cmd(sc, VIC_CMD_NUM_Rx_BUF);
475: sc->sc_ntxbuf = vic_read_cmd(sc, VIC_CMD_NUM_Tx_BUF);
476: sc->sc_feature = vic_read_cmd(sc, VIC_CMD_FEATURE);
477: sc->sc_cap = vic_read_cmd(sc, VIC_CMD_HWCAP);
478:
479: vic_getlladdr(sc);
480:
481: printf("%s: VMXnet %04X, address %s\n", DEVNAME(sc),
482: major & ~VIC_VERSION_MAJOR_M, ether_sprintf(sc->sc_lladdr));
483:
484: #ifdef VIC_DEBUG
485: printf("%s: feature 0x%8x, cap 0x%8x, rx/txbuf %d/%d\n", DEVNAME(sc),
486: sc->sc_feature, sc->sc_cap, sc->sc_nrxbuf, sc->sc_ntxbuf);
487: #endif
488:
489: if (sc->sc_nrxbuf > VIC_NBUF_MAX || sc->sc_nrxbuf == 0)
490: sc->sc_nrxbuf = VIC_NBUF;
491: if (sc->sc_ntxbuf > VIC_NBUF_MAX || sc->sc_ntxbuf == 0)
492: sc->sc_ntxbuf = VIC_NBUF;
493:
494: return (0);
495: }
496:
497: int
498: vic_alloc_data(struct vic_softc *sc)
499: {
500: u_int8_t *kva;
501: u_int offset;
502: struct vic_rxdesc *rxd;
503: int i;
504:
505: sc->sc_rxbuf = malloc(sizeof(struct vic_rxbuf) * sc->sc_nrxbuf,
506: M_NOWAIT, M_DEVBUF);
507: if (sc->sc_rxbuf == NULL) {
508: printf("%s: unable to allocate rxbuf\n", DEVNAME(sc));
509: goto err;
510: }
511:
512: sc->sc_txbuf = malloc(sizeof(struct vic_txbuf) * sc->sc_ntxbuf,
513: M_NOWAIT, M_DEVBUF);
514: if (sc->sc_txbuf == NULL) {
515: printf("%s: unable to allocate txbuf\n", DEVNAME(sc));
516: goto freerx;
517: }
518:
519: sc->sc_dma_size = sizeof(struct vic_data) +
520: (sc->sc_nrxbuf + VIC_QUEUE2_SIZE) * sizeof(struct vic_rxdesc) +
521: sc->sc_ntxbuf * sizeof(struct vic_txdesc);
522:
523: if (vic_alloc_dmamem(sc) != 0) {
524: printf("%s: unable to allocate dma region\n", DEVNAME(sc));
525: goto freetx;
526: }
527: kva = VIC_DMA_KVA(sc);
528:
529: /* set up basic vic data */
530: sc->sc_data = VIC_DMA_KVA(sc);
531:
532: sc->sc_data->vd_magic = VIC_MAGIC;
533: sc->sc_data->vd_length = sc->sc_dma_size;
534:
535: offset = sizeof(struct vic_data);
536:
537: /* set up the rx ring */
538: sc->sc_rxq = (struct vic_rxdesc *)&kva[offset];
539:
540: sc->sc_data->vd_rx_offset = offset;
541: sc->sc_data->vd_rx_length = sc->sc_nrxbuf;
542:
543: offset += sizeof(struct vic_rxdesc) * sc->sc_nrxbuf;
544:
545: /* set up the dummy rx ring 2 with an unusable entry */
546: sc->sc_rxq2 = (struct vic_rxdesc *)&kva[offset];
547:
548: sc->sc_data->vd_rx_offset2 = offset;
549: sc->sc_data->vd_rx_length2 = VIC_QUEUE2_SIZE;
550:
551: for (i = 0; i < VIC_QUEUE2_SIZE; i++) {
552: rxd = &sc->sc_rxq2[i];
553:
554: rxd->rx_physaddr = 0;
555: rxd->rx_buflength = 0;
556: rxd->rx_length = 0;
557: rxd->rx_owner = VIC_OWNER_DRIVER;
558:
559: offset += sizeof(struct vic_rxdesc);
560: }
561:
562: /* set up the tx ring */
563: sc->sc_txq = (struct vic_txdesc *)&kva[offset];
564:
565: sc->sc_data->vd_tx_offset = offset;
566: sc->sc_data->vd_tx_length = sc->sc_ntxbuf;
567:
568: return (0);
569: freetx:
570: free(sc->sc_txbuf, M_DEVBUF);
571: freerx:
572: free(sc->sc_rxbuf, M_DEVBUF);
573: err:
574: return (1);
575: }
576:
577: int
578: vic_init_data(struct vic_softc *sc)
579: {
580: struct vic_rxbuf *rxb;
581: struct vic_rxdesc *rxd;
582: struct vic_txbuf *txb;
583:
584: int i;
585:
586: for (i = 0; i < sc->sc_nrxbuf; i++) {
587: rxb = &sc->sc_rxbuf[i];
588: rxd = &sc->sc_rxq[i];
589:
590: if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
591: MCLBYTES, 0, BUS_DMA_NOWAIT, &rxb->rxb_dmamap) != 0) {
592: printf("%s: unable to create dmamap for rxb %d\n",
593: DEVNAME(sc), i);
594: goto freerxbs;
595: }
596:
597: rxb->rxb_m = vic_alloc_mbuf(sc, rxb->rxb_dmamap);
598: if (rxb->rxb_m == NULL) {
599: /* error already printed */
600: bus_dmamap_destroy(sc->sc_dmat, rxb->rxb_dmamap);
601: goto freerxbs;
602: }
603:
604: bus_dmamap_sync(sc->sc_dmat, rxb->rxb_dmamap, 0,
605: rxb->rxb_m->m_pkthdr.len, BUS_DMASYNC_PREREAD);
606:
607: rxd->rx_physaddr = rxb->rxb_dmamap->dm_segs[0].ds_addr;
608: rxd->rx_buflength = rxb->rxb_m->m_pkthdr.len; /* XXX? */
609: rxd->rx_length = 0;
610: rxd->rx_owner = VIC_OWNER_NIC;
611: }
612:
613: for (i = 0; i < sc->sc_ntxbuf; i++) {
614: txb = &sc->sc_txbuf[i];
615: if (bus_dmamap_create(sc->sc_dmat, MCLBYTES,
616: (sc->sc_cap & VIC_CMD_HWCAP_SG) ? VIC_SG_MAX : 1,
617: MCLBYTES, 0, BUS_DMA_NOWAIT, &txb->txb_dmamap) != 0) {
618: printf("%s: unable to create dmamap for tx %d\n",
619: DEVNAME(sc), i);
620: goto freetxbs;
621: }
622: txb->txb_m = NULL;
623: }
624:
625: return (0);
626:
627: freetxbs:
628: while (i--) {
629: txb = &sc->sc_txbuf[i];
630: bus_dmamap_destroy(sc->sc_dmat, txb->txb_dmamap);
631: }
632:
633: i = sc->sc_nrxbuf;
634: freerxbs:
635: while (i--) {
636: rxb = &sc->sc_rxbuf[i];
637: bus_dmamap_sync(sc->sc_dmat, rxb->rxb_dmamap, 0,
638: rxb->rxb_m->m_pkthdr.len, BUS_DMASYNC_POSTREAD);
639: bus_dmamap_unload(sc->sc_dmat, rxb->rxb_dmamap);
640: bus_dmamap_destroy(sc->sc_dmat, rxb->rxb_dmamap);
641: }
642:
643: return (1);
644: }
645:
646: int
647: vic_uninit_data(struct vic_softc *sc)
648: {
649: struct vic_rxbuf *rxb;
650: struct vic_rxdesc *rxd;
651: struct vic_txbuf *txb;
652:
653: int i;
654:
655: for (i = 0; i < sc->sc_nrxbuf; i++) {
656: rxb = &sc->sc_rxbuf[i];
657: rxd = &sc->sc_rxq[i];
658:
659: bus_dmamap_sync(sc->sc_dmat, rxb->rxb_dmamap, 0,
660: rxb->rxb_m->m_pkthdr.len, BUS_DMASYNC_POSTREAD);
661: bus_dmamap_unload(sc->sc_dmat, rxb->rxb_dmamap);
662: bus_dmamap_destroy(sc->sc_dmat, rxb->rxb_dmamap);
663:
664: m_freem(rxb->rxb_m);
665: rxb->rxb_m = NULL;
666: }
667:
668: for (i = 0; i < sc->sc_ntxbuf; i++) {
669: txb = &sc->sc_txbuf[i];
670: bus_dmamap_destroy(sc->sc_dmat, txb->txb_dmamap);
671: }
672:
673: return (0);
674: }
675:
676: void
677: vic_link_state(struct vic_softc *sc)
678: {
679: struct ifnet *ifp = &sc->sc_ac.ac_if;
680: u_int32_t status;
681: int link_state = LINK_STATE_DOWN;
682:
683: status = vic_read(sc, VIC_STATUS);
684: if (status & VIC_STATUS_CONNECTED)
685: link_state = LINK_STATE_FULL_DUPLEX;
686: if (ifp->if_link_state != link_state) {
687: ifp->if_link_state = link_state;
688: if_link_state_change(ifp);
689: }
690: }
691:
692: void
693: vic_shutdown(void *self)
694: {
695: struct vic_softc *sc = (struct vic_softc *)self;
696:
697: vic_stop(&sc->sc_ac.ac_if);
698: }
699:
700: int
701: vic_intr(void *arg)
702: {
703: struct vic_softc *sc = (struct vic_softc *)arg;
704:
705: vic_rx_proc(sc);
706: vic_tx_proc(sc);
707:
708: vic_write(sc, VIC_CMD, VIC_CMD_INTR_ACK);
709:
710: return (1);
711: }
712:
713: void
714: vic_rx_proc(struct vic_softc *sc)
715: {
716: struct ifnet *ifp = &sc->sc_ac.ac_if;
717: struct vic_rxdesc *rxd;
718: struct vic_rxbuf *rxb;
719: struct mbuf *m;
720: int len, idx;
721:
722: if ((ifp->if_flags & IFF_RUNNING) == 0)
723: return;
724:
725: bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size,
726: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
727:
728: for (;;) {
729: idx = sc->sc_data->vd_rx_nextidx;
730: if (idx >= sc->sc_data->vd_rx_length) {
731: ifp->if_ierrors++;
732: if (ifp->if_flags & IFF_DEBUG)
733: printf("%s: receive index error\n",
734: sc->sc_dev.dv_xname);
735: break;
736: }
737:
738: rxd = &sc->sc_rxq[idx];
739: if (rxd->rx_owner != VIC_OWNER_DRIVER)
740: break;
741:
742: rxb = &sc->sc_rxbuf[idx];
743:
744: len = rxd->rx_length;
745: if (len < VIC_MIN_FRAMELEN) {
746: ifp->if_iqdrops++;
747: goto nextp;
748: }
749:
750: if (rxb->rxb_m == NULL) {
751: ifp->if_ierrors++;
752: printf("%s: rxb %d has no mbuf\n", DEVNAME(sc), idx);
753: break;
754: }
755:
756: bus_dmamap_sync(sc->sc_dmat, rxb->rxb_dmamap, 0,
757: rxb->rxb_m->m_pkthdr.len, BUS_DMASYNC_POSTREAD);
758: bus_dmamap_unload(sc->sc_dmat, rxb->rxb_dmamap);
759:
760: m = rxb->rxb_m;
761: rxb->rxb_m = NULL;
762: m->m_pkthdr.rcvif = ifp;
763: m->m_pkthdr.len = m->m_len = len;
764:
765: /* Get new mbuf for the Rx queue */
766: rxb->rxb_m = vic_alloc_mbuf(sc, rxb->rxb_dmamap);
767: if (rxb->rxb_m == NULL) {
768: ifp->if_ierrors++;
769: printf("%s: mbuf alloc failed\n", DEVNAME(sc));
770: break;
771: }
772: bus_dmamap_sync(sc->sc_dmat, rxb->rxb_dmamap, 0,
773: rxb->rxb_m->m_pkthdr.len, BUS_DMASYNC_PREREAD);
774:
775: rxd->rx_physaddr = rxb->rxb_dmamap->dm_segs[0].ds_addr;
776: rxd->rx_buflength = rxb->rxb_m->m_pkthdr.len;
777: rxd->rx_length = 0;
778: rxd->rx_owner = VIC_OWNER_DRIVER;
779:
780: ifp->if_ipackets++;
781:
782: #if NBPFILTER > 0
783: if (ifp->if_bpf)
784: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
785: #endif
786:
787: ether_input_mbuf(ifp, m);
788:
789: nextp:
790: rxd->rx_owner = VIC_OWNER_NIC;
791: VIC_INC(sc->sc_data->vd_rx_nextidx, sc->sc_data->vd_rx_length);
792: }
793:
794: bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size,
795: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
796: }
797:
798: void
799: vic_tx_proc(struct vic_softc *sc)
800: {
801: struct ifnet *ifp = &sc->sc_ac.ac_if;
802: struct vic_txdesc *txd;
803: struct vic_txbuf *txb;
804: int idx;
805:
806: bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size,
807: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
808:
809: while (sc->sc_txpending > 0) {
810: idx = sc->sc_data->vd_tx_curidx;
811: if (idx >= sc->sc_data->vd_tx_length) {
812: ifp->if_oerrors++;
813: break;
814: }
815:
816: txd = &sc->sc_txq[idx];
817: if (txd->tx_owner != VIC_OWNER_DRIVER)
818: break;
819:
820: txb = &sc->sc_txbuf[idx];
821: if (txb->txb_m == NULL) {
822: printf("%s: tx ring is corrupt\n", DEVNAME(sc));
823: ifp->if_oerrors++;
824: break;
825: }
826:
827: bus_dmamap_sync(sc->sc_dmat, txb->txb_dmamap, 0,
828: txb->txb_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE);
829: bus_dmamap_unload(sc->sc_dmat, txb->txb_dmamap);
830:
831: m_freem(txb->txb_m);
832: txb->txb_m = NULL;
833: ifp->if_flags &= ~IFF_OACTIVE;
834:
835: sc->sc_txpending--;
836: sc->sc_data->vd_tx_stopped = 0;
837:
838: VIC_INC(sc->sc_data->vd_tx_curidx, sc->sc_data->vd_tx_length);
839: }
840:
841: bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size,
842: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
843:
844: vic_start(ifp);
845: }
846:
847: void
848: vic_iff(struct vic_softc *sc)
849: {
850: struct arpcom *ac = &sc->sc_ac;
851: struct ifnet *ifp = &sc->sc_ac.ac_if;
852: struct ether_multi *enm;
853: struct ether_multistep step;
854: u_int32_t crc;
855: u_int16_t *mcastfil = (u_int16_t *)sc->sc_data->vd_mcastfil;
856: u_int flags = 0;
857:
858: bzero(&sc->sc_data->vd_mcastfil, sizeof(sc->sc_data->vd_mcastfil));
859: ifp->if_flags &= ~IFF_ALLMULTI;
860:
861: if ((ifp->if_flags & IFF_RUNNING) == 0)
862: goto domulti;
863: if (ifp->if_flags & IFF_PROMISC)
864: goto allmulti;
865:
866: ETHER_FIRST_MULTI(step, ac, enm);
867: while (enm != NULL) {
868: if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN))
869: goto allmulti;
870:
871: crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN);
872: crc >>= 26;
873: mcastfil[crc >> 4] |= htole16(1 << (crc & 0xf));
874:
875: ETHER_NEXT_MULTI(step, enm);
876: }
877:
878: goto domulti;
879:
880: allmulti:
881: ifp->if_flags |= IFF_ALLMULTI;
882: memset(&sc->sc_data->vd_mcastfil, 0xff,
883: sizeof(sc->sc_data->vd_mcastfil));
884:
885: domulti:
886: vic_write(sc, VIC_CMD, VIC_CMD_MCASTFIL);
887:
888: if (ifp->if_flags & IFF_RUNNING) {
889: flags = (ifp->if_flags & IFF_PROMISC) ?
890: VIC_CMD_IFF_PROMISC :
891: (VIC_CMD_IFF_BROADCAST | VIC_CMD_IFF_MULTICAST);
892: }
893: sc->sc_data->vd_iff = flags;
894: vic_write(sc, VIC_CMD, VIC_CMD_IFF);
895: }
896:
897: void
898: vic_getlladdr(struct vic_softc *sc)
899: {
900: u_int32_t reg;
901:
902: /* Get MAC address */
903: reg = (sc->sc_cap & VIC_CMD_HWCAP_VPROM) ? VIC_VPROM : VIC_LLADDR;
904:
905: bus_space_barrier(sc->sc_iot, sc->sc_ioh, reg, ETHER_ADDR_LEN,
906: BUS_SPACE_BARRIER_READ);
907: bus_space_read_region_1(sc->sc_iot, sc->sc_ioh, reg, sc->sc_lladdr,
908: ETHER_ADDR_LEN);
909:
910: /* Update the MAC address register */
911: if (reg == VIC_VPROM)
912: vic_setlladdr(sc);
913: }
914:
915: void
916: vic_setlladdr(struct vic_softc *sc)
917: {
918: bus_space_write_region_1(sc->sc_iot, sc->sc_ioh, VIC_LLADDR,
919: sc->sc_lladdr, ETHER_ADDR_LEN);
920: bus_space_barrier(sc->sc_iot, sc->sc_ioh, VIC_LLADDR, ETHER_ADDR_LEN,
921: BUS_SPACE_BARRIER_WRITE);
922: }
923:
924: int
925: vic_media_change(struct ifnet *ifp)
926: {
927: /* Ignore */
928: return (0);
929: }
930:
931: void
932: vic_media_status(struct ifnet *ifp, struct ifmediareq *imr)
933: {
934: struct vic_softc *sc = (struct vic_softc *)ifp->if_softc;
935:
936: imr->ifm_active = IFM_ETHER | IFM_AUTO;
937: imr->ifm_status = IFM_AVALID;
938:
939: vic_link_state(sc);
940:
941: if (LINK_STATE_IS_UP(ifp->if_link_state) &&
942: ifp->if_flags & IFF_UP)
943: imr->ifm_status |= IFM_ACTIVE;
944: }
945:
946: void
947: vic_start(struct ifnet *ifp)
948: {
949: struct vic_softc *sc;
950: struct mbuf *m;
951: struct vic_txbuf *txb;
952: struct vic_txdesc *txd;
953: struct vic_sg *sge;
954: bus_dmamap_t dmap;
955: int i, idx;
956: int tx = 0;
957:
958: if (!(ifp->if_flags & IFF_RUNNING))
959: return;
960:
961: if (ifp->if_flags & IFF_OACTIVE)
962: return;
963:
964: if (IFQ_IS_EMPTY(&ifp->if_snd))
965: return;
966:
967: sc = (struct vic_softc *)ifp->if_softc;
968:
969: bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size,
970: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
971:
972: for (;;) {
973: if (VIC_TXURN(sc)) {
974: ifp->if_flags |= IFF_OACTIVE;
975: break;
976: }
977:
978: IFQ_POLL(&ifp->if_snd, m);
979: if (m == NULL)
980: break;
981:
982: idx = sc->sc_data->vd_tx_nextidx;
983: if (idx >= sc->sc_data->vd_tx_length) {
984: printf("%s: tx idx is corrupt\n", DEVNAME(sc));
985: ifp->if_oerrors++;
986: break;
987: }
988:
989: txd = &sc->sc_txq[idx];
990: txb = &sc->sc_txbuf[idx];
991:
992: if (txb->txb_m != NULL) {
993: printf("%s: tx ring is corrupt\n", DEVNAME(sc));
994: sc->sc_data->vd_tx_stopped = 1;
995: ifp->if_oerrors++;
996: break;
997: }
998:
999: /*
1000: * we're committed to sending it now. if we cant map it into
1001: * dma memory then we drop it.
1002: */
1003: IFQ_DEQUEUE(&ifp->if_snd, m);
1004: if (vic_load_txb(sc, txb, m) != 0) {
1005: m_freem(m);
1006: ifp->if_oerrors++;
1007: /* continue? */
1008: break;
1009: }
1010:
1011: #if NBPFILTER > 0
1012: if (ifp->if_bpf)
1013: bpf_mtap(ifp->if_bpf, txb->txb_m, BPF_DIRECTION_OUT);
1014: #endif
1015:
1016: dmap = txb->txb_dmamap;
1017: txd->tx_flags = VIC_TX_FLAGS_KEEP;
1018: txd->tx_owner = VIC_OWNER_NIC;
1019: txd->tx_sa.sa_addr_type = VIC_SG_ADDR_PHYS;
1020: txd->tx_sa.sa_length = dmap->dm_nsegs;
1021: for (i = 0; i < dmap->dm_nsegs; i++) {
1022: sge = &txd->tx_sa.sa_sg[i];
1023: sge->sg_length = dmap->dm_segs[i].ds_len;
1024: sge->sg_addr_low = dmap->dm_segs[i].ds_addr;
1025: }
1026:
1027: if (VIC_TXURN_WARN(sc)) {
1028: txd->tx_flags |= VIC_TX_FLAGS_TXURN;
1029: }
1030:
1031: bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
1032: BUS_DMASYNC_PREWRITE);
1033:
1034: ifp->if_opackets++;
1035: sc->sc_txpending++;
1036:
1037: VIC_INC(sc->sc_data->vd_tx_nextidx, sc->sc_data->vd_tx_length);
1038:
1039: tx = 1;
1040: }
1041:
1042: bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size,
1043: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1044:
1045: if (tx)
1046: vic_read(sc, VIC_Tx_ADDR);
1047: }
1048:
1049: int
1050: vic_load_txb(struct vic_softc *sc, struct vic_txbuf *txb, struct mbuf *m)
1051: {
1052: bus_dmamap_t dmap = txb->txb_dmamap;
1053: struct mbuf *m0 = NULL;
1054: int error;
1055:
1056: error = bus_dmamap_load_mbuf(sc->sc_dmat, dmap, m, BUS_DMA_NOWAIT);
1057: switch (error) {
1058: case 0:
1059: txb->txb_m = m;
1060: break;
1061:
1062: case EFBIG: /* mbuf chain is too fragmented */
1063: MGETHDR(m0, M_DONTWAIT, MT_DATA);
1064: if (m0 == NULL)
1065: return (ENOBUFS);
1066: if (m->m_pkthdr.len > MHLEN) {
1067: MCLGET(m0, M_DONTWAIT);
1068: if (!(m0->m_flags & M_EXT)) {
1069: m_freem(m0);
1070: return (ENOBUFS);
1071: }
1072: }
1073: m_copydata(m, 0, m->m_pkthdr.len, mtod(m0, caddr_t));
1074: m0->m_pkthdr.len = m0->m_len = m->m_pkthdr.len;
1075: error = bus_dmamap_load_mbuf(sc->sc_dmat, dmap, m0,
1076: BUS_DMA_NOWAIT);
1077: if (error != 0) {
1078: m_freem(m0);
1079: printf("%s: tx dmamap load error %d\n", DEVNAME(sc),
1080: error);
1081: return (ENOBUFS);
1082: }
1083: m_freem(m);
1084: txb->txb_m = m0;
1085: break;
1086:
1087: default:
1088: printf("%s: tx dmamap load error %d\n", DEVNAME(sc), error);
1089: return (ENOBUFS);
1090: }
1091:
1092: return (0);
1093: }
1094:
1095: void
1096: vic_watchdog(struct ifnet *ifp)
1097: {
1098: #if 0
1099: struct vic_softc *sc = (struct vic_softc *)ifp->if_softc;
1100:
1101: if (sc->sc_txpending && sc->sc_txtimeout > 0) {
1102: if (--sc->sc_txtimeout == 0) {
1103: printf("%s: device timeout\n", sc->sc_dev.dv_xname);
1104: ifp->if_flags &= ~IFF_RUNNING;
1105: vic_init(ifp);
1106: ifp->if_oerrors++;
1107: return;
1108: }
1109: }
1110:
1111: if (!IFQ_IS_EMPTY(&ifp->if_snd))
1112: vic_start(ifp);
1113: #endif
1114: }
1115:
1116: int
1117: vic_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1118: {
1119: struct vic_softc *sc = (struct vic_softc *)ifp->if_softc;
1120: struct ifreq *ifr = (struct ifreq *)data;
1121: struct ifaddr *ifa;
1122: int s, error = 0;
1123:
1124: s = splnet();
1125:
1126: if ((error = ether_ioctl(ifp, &sc->sc_ac, cmd, data)) > 0) {
1127: splx(s);
1128: return (error);
1129: }
1130:
1131: switch (cmd) {
1132: case SIOCSIFADDR:
1133: ifa = (struct ifaddr *)data;
1134: ifp->if_flags |= IFF_UP;
1135: #ifdef INET
1136: if (ifa->ifa_addr->sa_family == AF_INET)
1137: arp_ifinit(&sc->sc_ac, ifa);
1138: #endif
1139: /* FALLTHROUGH */
1140: case SIOCSIFFLAGS:
1141: if (ifp->if_flags & IFF_UP) {
1142: if (ifp->if_flags & IFF_RUNNING)
1143: vic_iff(sc);
1144: else
1145: vic_init(ifp);
1146: } else {
1147: if (ifp->if_flags & IFF_RUNNING)
1148: vic_stop(ifp);
1149: }
1150: break;
1151:
1152: case SIOCSIFMTU:
1153: if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ifp->if_hardmtu)
1154: error = EINVAL;
1155: else if (ifp->if_mtu != ifr->ifr_mtu)
1156: ifp->if_mtu = ifr->ifr_mtu;
1157: break;
1158:
1159: case SIOCADDMULTI:
1160: case SIOCDELMULTI:
1161: ifr = (struct ifreq *)data;
1162: error = (cmd == SIOCADDMULTI) ?
1163: ether_addmulti(ifr, &sc->sc_ac) :
1164: ether_delmulti(ifr, &sc->sc_ac);
1165:
1166: if (error == ENETRESET) {
1167: if (ifp->if_flags & IFF_RUNNING)
1168: vic_iff(sc);
1169: error = 0;
1170: }
1171: break;
1172:
1173: case SIOCGIFMEDIA:
1174: case SIOCSIFMEDIA:
1175: error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
1176: break;
1177:
1178: default:
1179: error = ENOTTY;
1180: break;
1181: }
1182:
1183: if (error == ENETRESET) {
1184: if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
1185: (IFF_UP | IFF_RUNNING))
1186: vic_iff(ifp->if_softc);
1187: error = 0;
1188: }
1189:
1190: splx(s);
1191:
1192: return (error);
1193: }
1194:
1195: void
1196: vic_init(struct ifnet *ifp)
1197: {
1198: struct vic_softc *sc = (struct vic_softc *)ifp->if_softc;
1199: int s;
1200:
1201: if (vic_init_data(sc) != 0)
1202: return;
1203:
1204: sc->sc_data->vd_tx_curidx = 0;
1205: sc->sc_data->vd_tx_nextidx = 0;
1206: sc->sc_data->vd_tx_stopped = sc->sc_data->vd_tx_queued = 0;
1207:
1208: sc->sc_data->vd_rx_nextidx = 0;
1209: sc->sc_data->vd_rx_nextidx2 = 0;
1210:
1211: sc->sc_data->vd_rx_saved_nextidx = 0;
1212: sc->sc_data->vd_rx_saved_nextidx2 = 0;
1213: sc->sc_data->vd_tx_saved_nextidx = 0;
1214:
1215: bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size,
1216: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1217:
1218: s = splnet();
1219:
1220: vic_write(sc, VIC_DATA_ADDR, VIC_DMA_DVA(sc));
1221: vic_write(sc, VIC_DATA_LENGTH, sc->sc_dma_size);
1222:
1223: ifp->if_flags |= IFF_RUNNING;
1224: ifp->if_flags &= ~IFF_OACTIVE;
1225:
1226: vic_iff(sc);
1227: vic_write(sc, VIC_CMD, VIC_CMD_INTR_ENABLE);
1228:
1229: splx(s);
1230:
1231: timeout_add(&sc->sc_tick, hz);
1232: }
1233:
1234: void
1235: vic_stop(struct ifnet *ifp)
1236: {
1237: struct vic_softc *sc = (struct vic_softc *)ifp->if_softc;
1238: int s;
1239:
1240: s = splnet();
1241:
1242: timeout_del(&sc->sc_tick);
1243:
1244: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
1245:
1246: bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size,
1247: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1248:
1249: /* XXX wait for tx to complete */
1250: while (sc->sc_txpending > 0) {
1251: splx(s);
1252: delay(1000);
1253: s = splnet();
1254: }
1255:
1256: sc->sc_data->vd_tx_stopped = 1;
1257:
1258: vic_write(sc, VIC_CMD, VIC_CMD_INTR_DISABLE);
1259:
1260: vic_iff(sc);
1261: vic_write(sc, VIC_DATA_ADDR, 0);
1262:
1263: vic_uninit_data(sc);
1264:
1265: splx(s);
1266: }
1267:
1268: struct mbuf *
1269: vic_alloc_mbuf(struct vic_softc *sc, bus_dmamap_t map)
1270: {
1271: struct mbuf *m = NULL;
1272:
1273: MGETHDR(m, M_DONTWAIT, MT_DATA);
1274: if (m == NULL)
1275: return (NULL);
1276:
1277: MCLGET(m, M_DONTWAIT);
1278: if ((m->m_flags & M_EXT) == 0) {
1279: m_freem(m);
1280: return (NULL);
1281: }
1282: m->m_len = m->m_pkthdr.len = MCLBYTES;
1283:
1284: if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT) != 0) {
1285: printf("%s: could not load mbuf DMA map", DEVNAME(sc));
1286: m_freem(m);
1287: return (NULL);
1288: }
1289:
1290: return (m);
1291: }
1292:
1293: void
1294: vic_tick(void *arg)
1295: {
1296: struct vic_softc *sc = (struct vic_softc *)arg;
1297:
1298: vic_link_state(sc);
1299:
1300: timeout_add(&sc->sc_tick, hz);
1301: }
1302:
1303: u_int32_t
1304: vic_read(struct vic_softc *sc, bus_size_t r)
1305: {
1306: bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
1307: BUS_SPACE_BARRIER_READ);
1308: return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, r));
1309: }
1310:
1311: void
1312: vic_write(struct vic_softc *sc, bus_size_t r, u_int32_t v)
1313: {
1314: bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v);
1315: bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
1316: BUS_SPACE_BARRIER_WRITE);
1317: }
1318:
1319: u_int32_t
1320: vic_read_cmd(struct vic_softc *sc, u_int32_t cmd)
1321: {
1322: vic_write(sc, VIC_CMD, cmd);
1323: return (vic_read(sc, VIC_CMD));
1324: }
1325:
1326: int
1327: vic_alloc_dmamem(struct vic_softc *sc)
1328: {
1329: int nsegs;
1330:
1331: if (bus_dmamap_create(sc->sc_dmat, sc->sc_dma_size, 1,
1332: sc->sc_dma_size, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
1333: &sc->sc_dma_map) != 0)
1334: goto err;
1335:
1336: if (bus_dmamem_alloc(sc->sc_dmat, sc->sc_dma_size, 16, 0,
1337: &sc->sc_dma_seg, 1, &nsegs, BUS_DMA_NOWAIT) != 0)
1338: goto destroy;
1339:
1340: if (bus_dmamem_map(sc->sc_dmat, &sc->sc_dma_seg, nsegs,
1341: sc->sc_dma_size, &sc->sc_dma_kva, BUS_DMA_NOWAIT) != 0)
1342: goto free;
1343:
1344: if (bus_dmamap_load(sc->sc_dmat, sc->sc_dma_map, sc->sc_dma_kva,
1345: sc->sc_dma_size, NULL, BUS_DMA_NOWAIT) != 0)
1346: goto unmap;
1347:
1348: bzero(sc->sc_dma_kva, sc->sc_dma_size);
1349:
1350: return (0);
1351:
1352: unmap:
1353: bus_dmamem_unmap(sc->sc_dmat, sc->sc_dma_kva, sc->sc_dma_size);
1354: free:
1355: bus_dmamem_free(sc->sc_dmat, &sc->sc_dma_seg, 1);
1356: destroy:
1357: bus_dmamap_destroy(sc->sc_dmat, sc->sc_dma_map);
1358: err:
1359: return (1);
1360: }
1361:
1362: void
1363: vic_free_dmamem(struct vic_softc *sc)
1364: {
1365: bus_dmamap_unload(sc->sc_dmat, sc->sc_dma_map);
1366: bus_dmamem_unmap(sc->sc_dmat, sc->sc_dma_kva, sc->sc_dma_size);
1367: bus_dmamem_free(sc->sc_dmat, &sc->sc_dma_seg, 1);
1368: bus_dmamap_destroy(sc->sc_dmat, sc->sc_dma_map);
1369: }
CVSweb