| File: | dev/pv/if_xnf.c |
| Warning: | line 649, column 25 Dereference of null pointer |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: if_xnf.c,v 1.67 2022/01/09 05:42:58 jsg Exp $ */ | |||
| 2 | ||||
| 3 | /* | |||
| 4 | * Copyright (c) 2015, 2016 Mike Belopuhov | |||
| 5 | * | |||
| 6 | * Permission to use, copy, modify, and distribute this software for any | |||
| 7 | * purpose with or without fee is hereby granted, provided that the above | |||
| 8 | * copyright notice and this permission notice appear in all copies. | |||
| 9 | * | |||
| 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
| 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
| 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
| 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
| 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
| 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| 17 | */ | |||
| 18 | ||||
| 19 | #include "bpfilter.h" | |||
| 20 | #include "vlan.h" | |||
| 21 | #include "xen.h" | |||
| 22 | ||||
| 23 | #include <sys/param.h> | |||
| 24 | #include <sys/systm.h> | |||
| 25 | #include <sys/atomic.h> | |||
| 26 | #include <sys/device.h> | |||
| 27 | #include <sys/kernel.h> | |||
| 28 | #include <sys/malloc.h> | |||
| 29 | #include <sys/mbuf.h> | |||
| 30 | #include <sys/pool.h> | |||
| 31 | #include <sys/queue.h> | |||
| 32 | #include <sys/socket.h> | |||
| 33 | #include <sys/sockio.h> | |||
| 34 | #include <sys/task.h> | |||
| 35 | #include <sys/timeout.h> | |||
| 36 | ||||
| 37 | #include <machine/bus.h> | |||
| 38 | ||||
| 39 | #include <dev/pv/xenreg.h> | |||
| 40 | #include <dev/pv/xenvar.h> | |||
| 41 | ||||
| 42 | #include <net/if.h> | |||
| 43 | #include <net/if_media.h> | |||
| 44 | ||||
| 45 | #include <netinet/in.h> | |||
| 46 | #include <netinet/if_ether.h> | |||
| 47 | ||||
| 48 | #ifdef INET61 | |||
| 49 | #include <netinet/ip6.h> | |||
| 50 | #endif | |||
| 51 | ||||
| 52 | #if NBPFILTER1 > 0 | |||
| 53 | #include <net/bpf.h> | |||
| 54 | #endif | |||
| 55 | ||||
| 56 | /* #define XNF_DEBUG */ | |||
| 57 | ||||
| 58 | #ifdef XNF_DEBUG | |||
| 59 | #define DPRINTF(x...) printf(x) | |||
| 60 | #else | |||
| 61 | #define DPRINTF(x...) | |||
| 62 | #endif | |||
| 63 | ||||
| 64 | /* | |||
| 65 | * Rx ring | |||
| 66 | */ | |||
| 67 | ||||
| 68 | struct xnf_rx_req { | |||
| 69 | uint16_t rxq_id; | |||
| 70 | uint16_t rxq_pad; | |||
| 71 | uint32_t rxq_ref; | |||
| 72 | } __packed__attribute__((__packed__)); | |||
| 73 | ||||
| 74 | struct xnf_rx_rsp { | |||
| 75 | uint16_t rxp_id; | |||
| 76 | uint16_t rxp_offset; | |||
| 77 | uint16_t rxp_flags; | |||
| 78 | #define XNF_RXF_CSUM_VALID0x0001 0x0001 | |||
| 79 | #define XNF_RXF_CSUM_BLANK0x0002 0x0002 | |||
| 80 | #define XNF_RXF_CHUNK0x0004 0x0004 | |||
| 81 | #define XNF_RXF_MGMT0x0008 0x0008 | |||
| 82 | int16_t rxp_status; | |||
| 83 | } __packed__attribute__((__packed__)); | |||
| 84 | ||||
| 85 | union xnf_rx_desc { | |||
| 86 | struct xnf_rx_req rxd_req; | |||
| 87 | struct xnf_rx_rsp rxd_rsp; | |||
| 88 | } __packed__attribute__((__packed__)); | |||
| 89 | ||||
| 90 | #define XNF_RX_DESC256 256 | |||
| 91 | #define XNF_MCLEN(1 << 12) PAGE_SIZE(1 << 12) | |||
| 92 | #define XNF_RX_MIN32 32 | |||
| 93 | ||||
| 94 | struct xnf_rx_ring { | |||
| 95 | volatile uint32_t rxr_prod; | |||
| 96 | volatile uint32_t rxr_prod_event; | |||
| 97 | volatile uint32_t rxr_cons; | |||
| 98 | volatile uint32_t rxr_cons_event; | |||
| 99 | uint32_t rxr_reserved[12]; | |||
| 100 | union xnf_rx_desc rxr_desc[XNF_RX_DESC256]; | |||
| 101 | } __packed__attribute__((__packed__)); | |||
| 102 | ||||
| 103 | ||||
| 104 | /* | |||
| 105 | * Tx ring | |||
| 106 | */ | |||
| 107 | ||||
| 108 | struct xnf_tx_req { | |||
| 109 | uint32_t txq_ref; | |||
| 110 | uint16_t txq_offset; | |||
| 111 | uint16_t txq_flags; | |||
| 112 | #define XNF_TXF_CSUM_BLANK0x0001 0x0001 | |||
| 113 | #define XNF_TXF_CSUM_VALID0x0002 0x0002 | |||
| 114 | #define XNF_TXF_CHUNK0x0004 0x0004 | |||
| 115 | #define XNF_TXF_ETXRA0x0008 0x0008 | |||
| 116 | uint16_t txq_id; | |||
| 117 | uint16_t txq_size; | |||
| 118 | } __packed__attribute__((__packed__)); | |||
| 119 | ||||
| 120 | struct xnf_tx_rsp { | |||
| 121 | uint16_t txp_id; | |||
| 122 | int16_t txp_status; | |||
| 123 | } __packed__attribute__((__packed__)); | |||
| 124 | ||||
| 125 | union xnf_tx_desc { | |||
| 126 | struct xnf_tx_req txd_req; | |||
| 127 | struct xnf_tx_rsp txd_rsp; | |||
| 128 | } __packed__attribute__((__packed__)); | |||
| 129 | ||||
| 130 | #define XNF_TX_DESC256 256 | |||
| 131 | #define XNF_TX_FRAG18 18 | |||
| 132 | ||||
| 133 | struct xnf_tx_ring { | |||
| 134 | volatile uint32_t txr_prod; | |||
| 135 | volatile uint32_t txr_prod_event; | |||
| 136 | volatile uint32_t txr_cons; | |||
| 137 | volatile uint32_t txr_cons_event; | |||
| 138 | uint32_t txr_reserved[12]; | |||
| 139 | union xnf_tx_desc txr_desc[XNF_TX_DESC256]; | |||
| 140 | } __packed__attribute__((__packed__)); | |||
| 141 | ||||
| 142 | struct xnf_tx_buf { | |||
| 143 | uint32_t txb_ndesc; | |||
| 144 | bus_dmamap_t txb_dmap; | |||
| 145 | struct mbuf *txb_mbuf; | |||
| 146 | }; | |||
| 147 | ||||
| 148 | /* Management frame, "extra info" in Xen parlance */ | |||
| 149 | struct xnf_mgmt { | |||
| 150 | uint8_t mg_type; | |||
| 151 | #define XNF_MGMT_MCAST_ADD2 2 | |||
| 152 | #define XNF_MGMT_MCAST_DEL3 3 | |||
| 153 | uint8_t mg_flags; | |||
| 154 | union { | |||
| 155 | uint8_t mgu_mcaddr[ETHER_ADDR_LEN6]; | |||
| 156 | uint16_t mgu_pad[3]; | |||
| 157 | } u; | |||
| 158 | #define mg_mcaddru.mgu_mcaddr u.mgu_mcaddr | |||
| 159 | } __packed__attribute__((__packed__)); | |||
| 160 | ||||
| 161 | ||||
| 162 | struct xnf_softc { | |||
| 163 | struct device sc_dev; | |||
| 164 | struct device *sc_parent; | |||
| 165 | char sc_node[XEN_MAX_NODE_LEN64]; | |||
| 166 | char sc_backend[XEN_MAX_BACKEND_LEN128]; | |||
| 167 | bus_dma_tag_t sc_dmat; | |||
| 168 | int sc_domid; | |||
| 169 | ||||
| 170 | struct arpcom sc_ac; | |||
| 171 | struct ifmedia sc_media; | |||
| 172 | ||||
| 173 | xen_intr_handle_t sc_xih; | |||
| 174 | ||||
| 175 | int sc_caps; | |||
| 176 | #define XNF_CAP_SG0x0001 0x0001 | |||
| 177 | #define XNF_CAP_CSUM40x0002 0x0002 | |||
| 178 | #define XNF_CAP_CSUM60x0004 0x0004 | |||
| 179 | #define XNF_CAP_MCAST0x0008 0x0008 | |||
| 180 | #define XNF_CAP_SPLIT0x0010 0x0010 | |||
| 181 | #define XNF_CAP_MULTIQ0x0020 0x0020 | |||
| 182 | ||||
| 183 | /* Rx ring */ | |||
| 184 | struct xnf_rx_ring *sc_rx_ring; | |||
| 185 | bus_dmamap_t sc_rx_rmap; /* map for the ring */ | |||
| 186 | bus_dma_segment_t sc_rx_seg; | |||
| 187 | uint32_t sc_rx_ref; /* grant table ref */ | |||
| 188 | uint32_t sc_rx_cons; | |||
| 189 | struct mbuf *sc_rx_buf[XNF_RX_DESC256]; | |||
| 190 | bus_dmamap_t sc_rx_dmap[XNF_RX_DESC256]; /* maps for packets */ | |||
| 191 | struct mbuf *sc_rx_cbuf[2]; /* chain handling */ | |||
| 192 | ||||
| 193 | /* Tx ring */ | |||
| 194 | struct xnf_tx_ring *sc_tx_ring; | |||
| 195 | bus_dmamap_t sc_tx_rmap; /* map for the ring */ | |||
| 196 | bus_dma_segment_t sc_tx_seg; | |||
| 197 | uint32_t sc_tx_ref; /* grant table ref */ | |||
| 198 | uint32_t sc_tx_cons; | |||
| 199 | int sc_tx_frags; | |||
| 200 | uint32_t sc_tx_next; /* next buffer */ | |||
| 201 | volatile unsigned int sc_tx_avail; | |||
| 202 | struct xnf_tx_buf sc_tx_buf[XNF_TX_DESC256]; | |||
| 203 | }; | |||
| 204 | ||||
| 205 | int xnf_match(struct device *, void *, void *); | |||
| 206 | void xnf_attach(struct device *, struct device *, void *); | |||
| 207 | int xnf_detach(struct device *, int); | |||
| 208 | int xnf_lladdr(struct xnf_softc *); | |||
| 209 | int xnf_ioctl(struct ifnet *, u_long, caddr_t); | |||
| 210 | int xnf_media_change(struct ifnet *); | |||
| 211 | void xnf_media_status(struct ifnet *, struct ifmediareq *); | |||
| 212 | int xnf_iff(struct xnf_softc *); | |||
| 213 | void xnf_init(struct xnf_softc *); | |||
| 214 | void xnf_stop(struct xnf_softc *); | |||
| 215 | void xnf_start(struct ifqueue *); | |||
| 216 | int xnf_encap(struct xnf_softc *, struct mbuf *, uint32_t *); | |||
| 217 | void xnf_intr(void *); | |||
| 218 | void xnf_watchdog(struct ifnet *); | |||
| 219 | void xnf_txeof(struct xnf_softc *); | |||
| 220 | void xnf_rxeof(struct xnf_softc *); | |||
| 221 | int xnf_rx_ring_fill(struct xnf_softc *); | |||
| 222 | int xnf_rx_ring_create(struct xnf_softc *); | |||
| 223 | void xnf_rx_ring_drain(struct xnf_softc *); | |||
| 224 | void xnf_rx_ring_destroy(struct xnf_softc *); | |||
| 225 | int xnf_tx_ring_create(struct xnf_softc *); | |||
| 226 | void xnf_tx_ring_drain(struct xnf_softc *); | |||
| 227 | void xnf_tx_ring_destroy(struct xnf_softc *); | |||
| 228 | int xnf_capabilities(struct xnf_softc *sc); | |||
| 229 | int xnf_init_backend(struct xnf_softc *); | |||
| 230 | ||||
| 231 | struct cfdriver xnf_cd = { | |||
| 232 | NULL((void *)0), "xnf", DV_IFNET | |||
| 233 | }; | |||
| 234 | ||||
| 235 | const struct cfattach xnf_ca = { | |||
| 236 | sizeof(struct xnf_softc), xnf_match, xnf_attach, xnf_detach | |||
| 237 | }; | |||
| 238 | ||||
| 239 | int | |||
| 240 | xnf_match(struct device *parent, void *match, void *aux) | |||
| 241 | { | |||
| 242 | struct xen_attach_args *xa = aux; | |||
| 243 | ||||
| 244 | if (strcmp("vif", xa->xa_name)) | |||
| 245 | return (0); | |||
| 246 | ||||
| 247 | return (1); | |||
| 248 | } | |||
| 249 | ||||
| 250 | void | |||
| 251 | xnf_attach(struct device *parent, struct device *self, void *aux) | |||
| 252 | { | |||
| 253 | struct xen_attach_args *xa = aux; | |||
| 254 | struct xnf_softc *sc = (struct xnf_softc *)self; | |||
| 255 | struct ifnet *ifp = &sc->sc_ac.ac_if; | |||
| 256 | ||||
| 257 | sc->sc_parent = parent; | |||
| 258 | sc->sc_dmat = xa->xa_dmat; | |||
| 259 | sc->sc_domid = xa->xa_domid; | |||
| 260 | ||||
| 261 | memcpy(sc->sc_node, xa->xa_node, XEN_MAX_NODE_LEN)__builtin_memcpy((sc->sc_node), (xa->xa_node), (64)); | |||
| 262 | memcpy(sc->sc_backend, xa->xa_backend, XEN_MAX_BACKEND_LEN)__builtin_memcpy((sc->sc_backend), (xa->xa_backend), (128 )); | |||
| 263 | ||||
| 264 | strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ16); | |||
| 265 | ||||
| 266 | if (xnf_lladdr(sc)) { | |||
| 267 | printf(": failed to obtain MAC address\n"); | |||
| 268 | return; | |||
| 269 | } | |||
| 270 | ||||
| 271 | if (xen_intr_establish(0, &sc->sc_xih, sc->sc_domid, xnf_intr, sc, | |||
| 272 | ifp->if_xname)) { | |||
| 273 | printf(": failed to establish an interrupt\n"); | |||
| 274 | return; | |||
| 275 | } | |||
| 276 | xen_intr_mask(sc->sc_xih); | |||
| 277 | ||||
| 278 | printf(" backend %d channel %u: address %s\n", sc->sc_domid, | |||
| 279 | sc->sc_xih, ether_sprintf(sc->sc_ac.ac_enaddr)); | |||
| 280 | ||||
| 281 | if (xnf_capabilities(sc)) { | |||
| 282 | xen_intr_disestablish(sc->sc_xih); | |||
| 283 | return; | |||
| 284 | } | |||
| 285 | ||||
| 286 | if (sc->sc_caps & XNF_CAP_SG0x0001) | |||
| 287 | ifp->if_hardmtu = 9000; | |||
| 288 | ||||
| 289 | if (xnf_rx_ring_create(sc)) { | |||
| 290 | xen_intr_disestablish(sc->sc_xih); | |||
| 291 | return; | |||
| 292 | } | |||
| 293 | if (xnf_tx_ring_create(sc)) { | |||
| 294 | xen_intr_disestablish(sc->sc_xih); | |||
| 295 | xnf_rx_ring_destroy(sc); | |||
| 296 | return; | |||
| 297 | } | |||
| 298 | if (xnf_init_backend(sc)) { | |||
| 299 | xen_intr_disestablish(sc->sc_xih); | |||
| 300 | xnf_rx_ring_destroy(sc); | |||
| 301 | xnf_tx_ring_destroy(sc); | |||
| 302 | return; | |||
| 303 | } | |||
| 304 | ||||
| 305 | ifp->if_flags = IFF_BROADCAST0x2 | IFF_SIMPLEX0x800 | IFF_MULTICAST0x8000; | |||
| 306 | ifp->if_xflags = IFXF_MPSAFE0x1; | |||
| 307 | ifp->if_ioctl = xnf_ioctl; | |||
| 308 | ifp->if_qstart = xnf_start; | |||
| 309 | ifp->if_watchdog = xnf_watchdog; | |||
| 310 | ifp->if_softc = sc; | |||
| 311 | ||||
| 312 | ifp->if_capabilitiesif_data.ifi_capabilities = IFCAP_VLAN_MTU0x00000010; | |||
| 313 | if (sc->sc_caps & XNF_CAP_CSUM40x0002) | |||
| 314 | ifp->if_capabilitiesif_data.ifi_capabilities |= IFCAP_CSUM_TCPv40x00000002 | IFCAP_CSUM_UDPv40x00000004; | |||
| 315 | if (sc->sc_caps & XNF_CAP_CSUM60x0004) | |||
| 316 | ifp->if_capabilitiesif_data.ifi_capabilities |= IFCAP_CSUM_TCPv60x00000080 | IFCAP_CSUM_UDPv60x00000100; | |||
| 317 | ||||
| 318 | ifq_set_maxlen(&ifp->if_snd, XNF_TX_DESC - 1)((&ifp->if_snd)->ifq_maxlen = (256 - 1)); | |||
| 319 | ||||
| 320 | ifmedia_init(&sc->sc_media, IFM_IMASK0xff00000000000000ULL, xnf_media_change, | |||
| 321 | xnf_media_status); | |||
| 322 | ifmedia_add(&sc->sc_media, IFM_ETHER0x0000000000000100ULL | IFM_MANUAL1ULL, 0, NULL((void *)0)); | |||
| 323 | ifmedia_set(&sc->sc_media, IFM_ETHER0x0000000000000100ULL | IFM_MANUAL1ULL); | |||
| 324 | ||||
| 325 | if_attach(ifp); | |||
| 326 | ether_ifattach(ifp); | |||
| 327 | ||||
| 328 | /* Kick out emulated em's and re's */ | |||
| 329 | xen_unplug_emulated(parent, XEN_UNPLUG_NIC0x0001); | |||
| 330 | } | |||
| 331 | ||||
| 332 | int | |||
| 333 | xnf_detach(struct device *self, int flags) | |||
| 334 | { | |||
| 335 | struct xnf_softc *sc = (struct xnf_softc *)self; | |||
| 336 | struct ifnet *ifp = &sc->sc_ac.ac_if; | |||
| 337 | ||||
| 338 | xnf_stop(sc); | |||
| 339 | ||||
| 340 | ether_ifdetach(ifp); | |||
| 341 | if_detach(ifp); | |||
| 342 | ||||
| 343 | xen_intr_disestablish(sc->sc_xih); | |||
| 344 | ||||
| 345 | if (sc->sc_tx_ring) | |||
| 346 | xnf_tx_ring_destroy(sc); | |||
| 347 | if (sc->sc_rx_ring) | |||
| 348 | xnf_rx_ring_destroy(sc); | |||
| 349 | ||||
| 350 | return (0); | |||
| 351 | } | |||
| 352 | ||||
| 353 | static int | |||
| 354 | nibble(int ch) | |||
| 355 | { | |||
| 356 | if (ch >= '0' && ch <= '9') | |||
| 357 | return (ch - '0'); | |||
| 358 | if (ch >= 'A' && ch <= 'F') | |||
| 359 | return (10 + ch - 'A'); | |||
| 360 | if (ch >= 'a' && ch <= 'f') | |||
| 361 | return (10 + ch - 'a'); | |||
| 362 | return (-1); | |||
| 363 | } | |||
| 364 | ||||
| 365 | int | |||
| 366 | xnf_lladdr(struct xnf_softc *sc) | |||
| 367 | { | |||
| 368 | char enaddr[ETHER_ADDR_LEN6]; | |||
| 369 | char mac[32]; | |||
| 370 | int i, j, lo, hi; | |||
| 371 | ||||
| 372 | if (xs_getprop(sc->sc_parent, sc->sc_backend, "mac", mac, sizeof(mac))) | |||
| 373 | return (-1); | |||
| 374 | ||||
| 375 | for (i = 0, j = 0; j < ETHER_ADDR_LEN6; i += 3, j++) { | |||
| 376 | if ((hi = nibble(mac[i])) == -1 || | |||
| 377 | (lo = nibble(mac[i+1])) == -1) | |||
| 378 | return (-1); | |||
| 379 | enaddr[j] = hi << 4 | lo; | |||
| 380 | } | |||
| 381 | ||||
| 382 | memcpy(sc->sc_ac.ac_enaddr, enaddr, ETHER_ADDR_LEN)__builtin_memcpy((sc->sc_ac.ac_enaddr), (enaddr), (6)); | |||
| 383 | return (0); | |||
| 384 | } | |||
| 385 | ||||
| 386 | int | |||
| 387 | xnf_ioctl(struct ifnet *ifp, u_long command, caddr_t data) | |||
| 388 | { | |||
| 389 | struct xnf_softc *sc = ifp->if_softc; | |||
| 390 | struct ifreq *ifr = (struct ifreq *)data; | |||
| 391 | int s, error = 0; | |||
| 392 | ||||
| 393 | s = splnet()splraise(0x7); | |||
| 394 | ||||
| 395 | switch (command) { | |||
| 396 | case SIOCSIFADDR((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((12))): | |||
| 397 | ifp->if_flags |= IFF_UP0x1; | |||
| 398 | if (!(ifp->if_flags & IFF_RUNNING0x40)) | |||
| 399 | xnf_init(sc); | |||
| 400 | break; | |||
| 401 | case SIOCSIFFLAGS((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((16))): | |||
| 402 | if (ifp->if_flags & IFF_UP0x1) { | |||
| 403 | if (ifp->if_flags & IFF_RUNNING0x40) | |||
| 404 | error = ENETRESET52; | |||
| 405 | else | |||
| 406 | xnf_init(sc); | |||
| 407 | } else { | |||
| 408 | if (ifp->if_flags & IFF_RUNNING0x40) | |||
| 409 | xnf_stop(sc); | |||
| 410 | } | |||
| 411 | break; | |||
| 412 | case SIOCGIFMEDIA(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct ifmediareq) & 0x1fff) << 16) | ((('i')) << 8) | ((56))): | |||
| 413 | case SIOCSIFMEDIA(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct ifreq) & 0x1fff) << 16) | ((('i')) << 8) | ((55))): | |||
| 414 | error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command); | |||
| 415 | break; | |||
| 416 | default: | |||
| 417 | error = ether_ioctl(ifp, &sc->sc_ac, command, data); | |||
| 418 | break; | |||
| 419 | } | |||
| 420 | ||||
| 421 | if (error == ENETRESET52) { | |||
| 422 | if (ifp->if_flags & IFF_RUNNING0x40) | |||
| 423 | xnf_iff(sc); | |||
| 424 | error = 0; | |||
| 425 | } | |||
| 426 | ||||
| 427 | splx(s)spllower(s); | |||
| 428 | ||||
| 429 | return (error); | |||
| 430 | } | |||
| 431 | ||||
| 432 | int | |||
| 433 | xnf_media_change(struct ifnet *ifp) | |||
| 434 | { | |||
| 435 | return (0); | |||
| 436 | } | |||
| 437 | ||||
| 438 | void | |||
| 439 | xnf_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) | |||
| 440 | { | |||
| 441 | ifmr->ifm_status = IFM_ACTIVE0x0000000000000002ULL | IFM_AVALID0x0000000000000001ULL; | |||
| 442 | ifmr->ifm_active = IFM_ETHER0x0000000000000100ULL | IFM_MANUAL1ULL; | |||
| 443 | } | |||
| 444 | ||||
| 445 | int | |||
| 446 | xnf_iff(struct xnf_softc *sc) | |||
| 447 | { | |||
| 448 | return (0); | |||
| 449 | } | |||
| 450 | ||||
| 451 | void | |||
| 452 | xnf_init(struct xnf_softc *sc) | |||
| 453 | { | |||
| 454 | struct ifnet *ifp = &sc->sc_ac.ac_if; | |||
| 455 | ||||
| 456 | xnf_stop(sc); | |||
| 457 | ||||
| 458 | xnf_iff(sc); | |||
| 459 | ||||
| 460 | xnf_rx_ring_fill(sc); | |||
| 461 | ||||
| 462 | if (xen_intr_unmask(sc->sc_xih)) { | |||
| 463 | printf("%s: failed to enable interrupts\n", ifp->if_xname); | |||
| 464 | xnf_stop(sc); | |||
| 465 | return; | |||
| 466 | } | |||
| 467 | ||||
| 468 | ifp->if_flags |= IFF_RUNNING0x40; | |||
| 469 | ifq_clr_oactive(&ifp->if_snd); | |||
| 470 | } | |||
| 471 | ||||
| 472 | void | |||
| 473 | xnf_stop(struct xnf_softc *sc) | |||
| 474 | { | |||
| 475 | struct ifnet *ifp = &sc->sc_ac.ac_if; | |||
| 476 | ||||
| 477 | ifp->if_flags &= ~IFF_RUNNING0x40; | |||
| 478 | ||||
| 479 | xen_intr_mask(sc->sc_xih); | |||
| 480 | ||||
| 481 | ifp->if_timer = 0; | |||
| 482 | ||||
| 483 | ifq_barrier(&ifp->if_snd); | |||
| 484 | xen_intr_barrier(sc->sc_xih); | |||
| 485 | ||||
| 486 | ifq_clr_oactive(&ifp->if_snd); | |||
| 487 | ||||
| 488 | if (sc->sc_tx_ring) | |||
| 489 | xnf_tx_ring_drain(sc); | |||
| 490 | if (sc->sc_rx_ring) | |||
| 491 | xnf_rx_ring_drain(sc); | |||
| 492 | } | |||
| 493 | ||||
| 494 | void | |||
| 495 | xnf_start(struct ifqueue *ifq) | |||
| 496 | { | |||
| 497 | struct ifnet *ifp = ifq->ifq_if; | |||
| 498 | struct xnf_softc *sc = ifp->if_softc; | |||
| 499 | struct xnf_tx_ring *txr = sc->sc_tx_ring; | |||
| 500 | struct mbuf *m; | |||
| 501 | int pkts = 0; | |||
| 502 | uint32_t prod, oprod; | |||
| 503 | ||||
| 504 | bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_rmap, 0, 0,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_tx_rmap), (0), (0), (0x02)) | |||
| 505 | BUS_DMASYNC_POSTREAD)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_tx_rmap), (0), (0), (0x02)); | |||
| 506 | ||||
| 507 | prod = oprod = txr->txr_prod; | |||
| 508 | ||||
| 509 | for (;;) { | |||
| ||||
| 510 | if (((XNF_TX_DESC256 - (prod - sc->sc_tx_cons)) < | |||
| 511 | sc->sc_tx_frags) || !sc->sc_tx_avail) { | |||
| 512 | /* transient */ | |||
| 513 | ifq_set_oactive(ifq); | |||
| 514 | break; | |||
| 515 | } | |||
| 516 | ||||
| 517 | m = ifq_dequeue(ifq); | |||
| 518 | if (m == NULL((void *)0)) | |||
| 519 | break; | |||
| 520 | ||||
| 521 | if (xnf_encap(sc, m, &prod)) { | |||
| 522 | /* the chain is too large */ | |||
| 523 | ifp->if_oerrorsif_data.ifi_oerrors++; | |||
| 524 | m_freem(m); | |||
| 525 | continue; | |||
| 526 | } | |||
| 527 | ||||
| 528 | #if NBPFILTER1 > 0 | |||
| 529 | if (ifp->if_bpf) | |||
| 530 | bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT(1 << 1)); | |||
| 531 | #endif | |||
| 532 | pkts++; | |||
| 533 | } | |||
| 534 | if (pkts > 0) { | |||
| 535 | txr->txr_prod = prod; | |||
| 536 | if (txr->txr_cons_event <= txr->txr_cons) | |||
| 537 | txr->txr_cons_event = txr->txr_cons + | |||
| 538 | ((txr->txr_prod - txr->txr_cons) >> 1) + 1; | |||
| 539 | bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_rmap, 0, 0,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_tx_rmap), (0), (0), (0x01 | 0x04)) | |||
| 540 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_tx_rmap), (0), (0), (0x01 | 0x04)); | |||
| 541 | if (prod - txr->txr_prod_event < prod - oprod) | |||
| 542 | xen_intr_signal(sc->sc_xih); | |||
| 543 | ifp->if_timer = 5; | |||
| 544 | } | |||
| 545 | } | |||
| 546 | ||||
| 547 | static inline int | |||
| 548 | xnf_fragcount(struct mbuf *m_head) | |||
| 549 | { | |||
| 550 | struct mbuf *m; | |||
| 551 | vaddr_t va, va0; | |||
| 552 | int n = 0; | |||
| 553 | ||||
| 554 | for (m = m_head; m != NULL((void *)0); m = m->m_nextm_hdr.mh_next) { | |||
| 555 | if (m->m_lenm_hdr.mh_len == 0) | |||
| 556 | continue; | |||
| 557 | /* start of the buffer */ | |||
| 558 | for (va0 = va = mtod(m, vaddr_t)((vaddr_t)((m)->m_hdr.mh_data)); | |||
| 559 | /* does the buffer end on this page? */ | |||
| 560 | va + (PAGE_SIZE(1 << 12) - (va & PAGE_MASK((1 << 12) - 1))) < va0 + m->m_lenm_hdr.mh_len; | |||
| 561 | /* move on to the next page */ | |||
| 562 | va += PAGE_SIZE(1 << 12) - (va & PAGE_MASK((1 << 12) - 1))) | |||
| 563 | n++; | |||
| 564 | n++; | |||
| 565 | } | |||
| 566 | return (n); | |||
| 567 | } | |||
| 568 | ||||
| 569 | int | |||
| 570 | xnf_encap(struct xnf_softc *sc, struct mbuf *m_head, uint32_t *prod) | |||
| 571 | { | |||
| 572 | struct xnf_tx_ring *txr = sc->sc_tx_ring; | |||
| 573 | struct xnf_tx_buf *txb = NULL((void *)0); | |||
| 574 | union xnf_tx_desc *txd = NULL((void *)0); | |||
| 575 | struct mbuf *m, **next; | |||
| 576 | uint32_t oprod = *prod; | |||
| 577 | uint16_t id; | |||
| 578 | int i, flags, n, used = 0; | |||
| 579 | ||||
| 580 | if ((xnf_fragcount(m_head) > sc->sc_tx_frags) && | |||
| 581 | m_defrag(m_head, M_DONTWAIT0x0002)) | |||
| 582 | return (ENOBUFS55); | |||
| 583 | ||||
| 584 | flags = (sc->sc_domid << 16) | BUS_DMA_WRITE0x0400 | BUS_DMA_NOWAIT0x0001; | |||
| 585 | ||||
| 586 | next = &m_head->m_nextm_hdr.mh_next; | |||
| 587 | for (m = m_head; m
| |||
| 588 | /* Unlink and free zero length nodes. */ | |||
| 589 | if (m->m_lenm_hdr.mh_len == 0) { | |||
| 590 | *next = m->m_nextm_hdr.mh_next; | |||
| 591 | m_free(m); | |||
| 592 | continue; | |||
| 593 | } | |||
| 594 | next = &m->m_nextm_hdr.mh_next; | |||
| 595 | ||||
| 596 | i = *prod & (XNF_TX_DESC256 - 1); | |||
| 597 | txd = &txr->txr_desc[i]; | |||
| 598 | ||||
| 599 | /* | |||
| 600 | * Find an unused TX buffer. We're guaranteed to find one | |||
| 601 | * because xnf_encap cannot be called with sc_tx_avail == 0. | |||
| 602 | */ | |||
| 603 | do { | |||
| 604 | id = sc->sc_tx_next++ & (XNF_TX_DESC256 - 1); | |||
| 605 | txb = &sc->sc_tx_buf[id]; | |||
| 606 | } while (txb->txb_mbuf); | |||
| 607 | ||||
| 608 | if (bus_dmamap_load(sc->sc_dmat, txb->txb_dmap, m->m_data,(*(sc->sc_dmat)->_dmamap_load)((sc->sc_dmat), (txb-> txb_dmap), (m->m_hdr.mh_data), (m->m_hdr.mh_len), (((void *)0)), (flags)) | |||
| 609 | m->m_len, NULL, flags)(*(sc->sc_dmat)->_dmamap_load)((sc->sc_dmat), (txb-> txb_dmap), (m->m_hdr.mh_data), (m->m_hdr.mh_len), (((void *)0)), (flags))) { | |||
| 610 | DPRINTF("%s: failed to load %u bytes @%lu\n", | |||
| 611 | sc->sc_dev.dv_xname, m->m_len, | |||
| 612 | mtod(m, vaddr_t) & PAGE_MASK); | |||
| 613 | goto unroll; | |||
| 614 | } | |||
| 615 | ||||
| 616 | for (n = 0; n < txb->txb_dmap->dm_nsegs; n++) { | |||
| 617 | i = *prod & (XNF_TX_DESC256 - 1); | |||
| 618 | txd = &txr->txr_desc[i]; | |||
| 619 | ||||
| 620 | if (m == m_head && n == 0) { | |||
| 621 | if (m->m_pkthdrM_dat.MH.MH_pkthdr.csum_flags & | |||
| 622 | (M_TCP_CSUM_OUT0x0002 | M_UDP_CSUM_OUT0x0004)) | |||
| 623 | txd->txd_req.txq_flags = | |||
| 624 | XNF_TXF_CSUM_BLANK0x0001 | | |||
| 625 | XNF_TXF_CSUM_VALID0x0002; | |||
| 626 | txd->txd_req.txq_size = m->m_pkthdrM_dat.MH.MH_pkthdr.len; | |||
| 627 | } else { | |||
| 628 | txd->txd_req.txq_size = | |||
| 629 | txb->txb_dmap->dm_segs[n].ds_len; | |||
| 630 | } | |||
| 631 | txd->txd_req.txq_ref = | |||
| 632 | txb->txb_dmap->dm_segs[n].ds_addr; | |||
| 633 | if (n == 0) | |||
| 634 | txd->txd_req.txq_offset = | |||
| 635 | mtod(m, vaddr_t)((vaddr_t)((m)->m_hdr.mh_data)) & PAGE_MASK((1 << 12) - 1); | |||
| 636 | /* The chunk flag will be removed from the last one */ | |||
| 637 | txd->txd_req.txq_flags |= XNF_TXF_CHUNK0x0004; | |||
| 638 | txd->txd_req.txq_id = id; | |||
| 639 | ||||
| 640 | txb->txb_ndesc++; | |||
| 641 | (*prod)++; | |||
| 642 | } | |||
| 643 | ||||
| 644 | txb->txb_mbuf = m; | |||
| 645 | used++; | |||
| 646 | } | |||
| 647 | ||||
| 648 | /* Clear the chunk flag from the last segment */ | |||
| 649 | txd->txd_req.txq_flags &= ~XNF_TXF_CHUNK0x0004; | |||
| ||||
| 650 | bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_rmap, 0, 0,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_tx_rmap), (0), (0), (0x04)) | |||
| 651 | BUS_DMASYNC_PREWRITE)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_tx_rmap), (0), (0), (0x04)); | |||
| 652 | ||||
| 653 | KASSERT(sc->sc_tx_avail > used)((sc->sc_tx_avail > used) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/dev/pv/if_xnf.c", 653, "sc->sc_tx_avail > used" )); | |||
| 654 | atomic_sub_int(&sc->sc_tx_avail, used)_atomic_sub_int(&sc->sc_tx_avail, used); | |||
| 655 | ||||
| 656 | return (0); | |||
| 657 | ||||
| 658 | unroll: | |||
| 659 | DPRINTF("%s: unrolling from %u to %u\n", sc->sc_dev.dv_xname, | |||
| 660 | *prod, oprod); | |||
| 661 | for (; *prod != oprod; (*prod)--) { | |||
| 662 | i = (*prod - 1) & (XNF_TX_DESC256 - 1); | |||
| 663 | txd = &txr->txr_desc[i]; | |||
| 664 | id = txd->txd_req.txq_id; | |||
| 665 | txb = &sc->sc_tx_buf[id]; | |||
| 666 | ||||
| 667 | memset(txd, 0, sizeof(*txd))__builtin_memset((txd), (0), (sizeof(*txd))); | |||
| 668 | ||||
| 669 | if (txb->txb_mbuf) { | |||
| 670 | bus_dmamap_sync(sc->sc_dmat, txb->txb_dmap, 0, 0,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (txb-> txb_dmap), (0), (0), (0x02 | 0x08)) | |||
| 671 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (txb-> txb_dmap), (0), (0), (0x02 | 0x08)); | |||
| 672 | bus_dmamap_unload(sc->sc_dmat, txb->txb_dmap)(*(sc->sc_dmat)->_dmamap_unload)((sc->sc_dmat), (txb ->txb_dmap)); | |||
| 673 | ||||
| 674 | txb->txb_mbuf = NULL((void *)0); | |||
| 675 | txb->txb_ndesc = 0; | |||
| 676 | } | |||
| 677 | } | |||
| 678 | return (ENOBUFS55); | |||
| 679 | } | |||
| 680 | ||||
| 681 | void | |||
| 682 | xnf_intr(void *arg) | |||
| 683 | { | |||
| 684 | struct xnf_softc *sc = arg; | |||
| 685 | struct ifnet *ifp = &sc->sc_ac.ac_if; | |||
| 686 | ||||
| 687 | if (ifp->if_flags & IFF_RUNNING0x40) { | |||
| 688 | xnf_txeof(sc); | |||
| 689 | xnf_rxeof(sc); | |||
| 690 | } | |||
| 691 | } | |||
| 692 | ||||
| 693 | void | |||
| 694 | xnf_watchdog(struct ifnet *ifp) | |||
| 695 | { | |||
| 696 | struct xnf_softc *sc = ifp->if_softc; | |||
| 697 | struct xnf_tx_ring *txr = sc->sc_tx_ring; | |||
| 698 | ||||
| 699 | printf("%s: tx stuck: prod %u cons %u,%u evt %u,%u\n", | |||
| 700 | ifp->if_xname, txr->txr_prod, txr->txr_cons, sc->sc_tx_cons, | |||
| 701 | txr->txr_prod_event, txr->txr_cons_event); | |||
| 702 | } | |||
| 703 | ||||
| 704 | void | |||
| 705 | xnf_txeof(struct xnf_softc *sc) | |||
| 706 | { | |||
| 707 | struct ifnet *ifp = &sc->sc_ac.ac_if; | |||
| 708 | struct xnf_tx_ring *txr = sc->sc_tx_ring; | |||
| 709 | struct xnf_tx_buf *txb; | |||
| 710 | union xnf_tx_desc *txd; | |||
| 711 | uint done = 0; | |||
| 712 | uint32_t cons; | |||
| 713 | uint16_t id; | |||
| 714 | int i; | |||
| 715 | ||||
| 716 | bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_rmap, 0, 0,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_tx_rmap), (0), (0), (0x02 | 0x08)) | |||
| 717 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_tx_rmap), (0), (0), (0x02 | 0x08)); | |||
| 718 | ||||
| 719 | for (cons = sc->sc_tx_cons; cons != txr->txr_cons; cons++) { | |||
| 720 | i = cons & (XNF_TX_DESC256 - 1); | |||
| 721 | txd = &txr->txr_desc[i]; | |||
| 722 | id = txd->txd_rsp.txp_id; | |||
| 723 | txb = &sc->sc_tx_buf[id]; | |||
| 724 | ||||
| 725 | KASSERT(txb->txb_ndesc > 0)((txb->txb_ndesc > 0) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/dev/pv/if_xnf.c", 725, "txb->txb_ndesc > 0" )); | |||
| 726 | if (--txb->txb_ndesc == 0) { | |||
| 727 | bus_dmamap_sync(sc->sc_dmat, txb->txb_dmap, 0, 0,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (txb-> txb_dmap), (0), (0), (0x02 | 0x08)) | |||
| 728 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (txb-> txb_dmap), (0), (0), (0x02 | 0x08)); | |||
| 729 | bus_dmamap_unload(sc->sc_dmat, txb->txb_dmap)(*(sc->sc_dmat)->_dmamap_unload)((sc->sc_dmat), (txb ->txb_dmap)); | |||
| 730 | ||||
| 731 | m_free(txb->txb_mbuf); | |||
| 732 | txb->txb_mbuf = NULL((void *)0); | |||
| 733 | done++; | |||
| 734 | } | |||
| 735 | ||||
| 736 | memset(txd, 0, sizeof(*txd))__builtin_memset((txd), (0), (sizeof(*txd))); | |||
| 737 | } | |||
| 738 | ||||
| 739 | sc->sc_tx_cons = cons; | |||
| 740 | txr->txr_cons_event = sc->sc_tx_cons + | |||
| 741 | ((txr->txr_prod - sc->sc_tx_cons) >> 1) + 1; | |||
| 742 | bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_rmap, 0, 0,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_tx_rmap), (0), (0), (0x01 | 0x04)) | |||
| 743 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_tx_rmap), (0), (0), (0x01 | 0x04)); | |||
| 744 | ||||
| 745 | atomic_add_int(&sc->sc_tx_avail, done)_atomic_add_int(&sc->sc_tx_avail, done); | |||
| 746 | ||||
| 747 | if (sc->sc_tx_cons == txr->txr_prod) | |||
| 748 | ifp->if_timer = 0; | |||
| 749 | if (ifq_is_oactive(&ifp->if_snd)) | |||
| 750 | ifq_restart(&ifp->if_snd); | |||
| 751 | } | |||
| 752 | ||||
| 753 | void | |||
| 754 | xnf_rxeof(struct xnf_softc *sc) | |||
| 755 | { | |||
| 756 | struct ifnet *ifp = &sc->sc_ac.ac_if; | |||
| 757 | struct xnf_rx_ring *rxr = sc->sc_rx_ring; | |||
| 758 | union xnf_rx_desc *rxd; | |||
| 759 | struct mbuf_list ml = MBUF_LIST_INITIALIZER(){ ((void *)0), ((void *)0), 0 }; | |||
| 760 | struct mbuf *fmp = sc->sc_rx_cbuf[0]; | |||
| 761 | struct mbuf *lmp = sc->sc_rx_cbuf[1]; | |||
| 762 | struct mbuf *m; | |||
| 763 | bus_dmamap_t dmap; | |||
| 764 | uint32_t cons; | |||
| 765 | uint16_t id; | |||
| 766 | int i, flags, len, offset; | |||
| 767 | ||||
| 768 | bus_dmamap_sync(sc->sc_dmat, sc->sc_rx_rmap, 0, 0,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_rx_rmap), (0), (0), (0x02 | 0x08)) | |||
| 769 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_rx_rmap), (0), (0), (0x02 | 0x08)); | |||
| 770 | ||||
| 771 | for (cons = sc->sc_rx_cons; cons != rxr->rxr_cons; cons++) { | |||
| 772 | i = cons & (XNF_RX_DESC256 - 1); | |||
| 773 | rxd = &rxr->rxr_desc[i]; | |||
| 774 | ||||
| 775 | id = rxd->rxd_rsp.rxp_id; | |||
| 776 | len = rxd->rxd_rsp.rxp_status; | |||
| 777 | flags = rxd->rxd_rsp.rxp_flags; | |||
| 778 | offset = rxd->rxd_rsp.rxp_offset; | |||
| 779 | ||||
| 780 | dmap = sc->sc_rx_dmap[id]; | |||
| 781 | bus_dmamap_sync(sc->sc_dmat, dmap, 0, 0,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (dmap) , (0), (0), (0x02 | 0x08)) | |||
| 782 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (dmap) , (0), (0), (0x02 | 0x08)); | |||
| 783 | bus_dmamap_unload(sc->sc_dmat, dmap)(*(sc->sc_dmat)->_dmamap_unload)((sc->sc_dmat), (dmap )); | |||
| 784 | ||||
| 785 | m = sc->sc_rx_buf[id]; | |||
| 786 | KASSERT(m != NULL)((m != ((void *)0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/pv/if_xnf.c" , 786, "m != NULL")); | |||
| 787 | sc->sc_rx_buf[id] = NULL((void *)0); | |||
| 788 | ||||
| 789 | if (flags & XNF_RXF_MGMT0x0008) { | |||
| 790 | printf("%s: management data present\n", | |||
| 791 | ifp->if_xname); | |||
| 792 | m_freem(m); | |||
| 793 | continue; | |||
| 794 | } | |||
| 795 | ||||
| 796 | if (flags & XNF_RXF_CSUM_VALID0x0001) | |||
| 797 | m->m_pkthdrM_dat.MH.MH_pkthdr.csum_flags = M_TCP_CSUM_IN_OK0x0020 | | |||
| 798 | M_UDP_CSUM_IN_OK0x0080; | |||
| 799 | ||||
| 800 | if (len < 0 || (len + offset > PAGE_SIZE(1 << 12))) { | |||
| 801 | ifp->if_ierrorsif_data.ifi_ierrors++; | |||
| 802 | m_freem(m); | |||
| 803 | continue; | |||
| 804 | } | |||
| 805 | ||||
| 806 | m->m_lenm_hdr.mh_len = len; | |||
| 807 | m->m_datam_hdr.mh_data += offset; | |||
| 808 | ||||
| 809 | if (fmp == NULL((void *)0)) { | |||
| 810 | m->m_pkthdrM_dat.MH.MH_pkthdr.len = len; | |||
| 811 | fmp = m; | |||
| 812 | } else { | |||
| 813 | m->m_flagsm_hdr.mh_flags &= ~M_PKTHDR0x0002; | |||
| 814 | lmp->m_nextm_hdr.mh_next = m; | |||
| 815 | fmp->m_pkthdrM_dat.MH.MH_pkthdr.len += m->m_lenm_hdr.mh_len; | |||
| 816 | } | |||
| 817 | lmp = m; | |||
| 818 | ||||
| 819 | if (flags & XNF_RXF_CHUNK0x0004) { | |||
| 820 | sc->sc_rx_cbuf[0] = fmp; | |||
| 821 | sc->sc_rx_cbuf[1] = lmp; | |||
| 822 | continue; | |||
| 823 | } | |||
| 824 | ||||
| 825 | m = fmp; | |||
| 826 | ||||
| 827 | ml_enqueue(&ml, m); | |||
| 828 | sc->sc_rx_cbuf[0] = sc->sc_rx_cbuf[1] = fmp = lmp = NULL((void *)0); | |||
| 829 | ||||
| 830 | memset(rxd, 0, sizeof(*rxd))__builtin_memset((rxd), (0), (sizeof(*rxd))); | |||
| 831 | rxd->rxd_req.rxq_id = id; | |||
| 832 | } | |||
| 833 | ||||
| 834 | sc->sc_rx_cons = cons; | |||
| 835 | rxr->rxr_cons_event = sc->sc_rx_cons + 1; | |||
| 836 | bus_dmamap_sync(sc->sc_dmat, sc->sc_rx_rmap, 0, 0,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_rx_rmap), (0), (0), (0x01 | 0x04)) | |||
| 837 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_rx_rmap), (0), (0), (0x01 | 0x04)); | |||
| 838 | ||||
| 839 | if_input(ifp, &ml); | |||
| 840 | ||||
| 841 | if (xnf_rx_ring_fill(sc) || (sc->sc_rx_cons != rxr->rxr_cons)) | |||
| 842 | xen_intr_schedule(sc->sc_xih); | |||
| 843 | } | |||
| 844 | ||||
| 845 | int | |||
| 846 | xnf_rx_ring_fill(struct xnf_softc *sc) | |||
| 847 | { | |||
| 848 | struct ifnet *ifp = &sc->sc_ac.ac_if; | |||
| 849 | struct xnf_rx_ring *rxr = sc->sc_rx_ring; | |||
| 850 | union xnf_rx_desc *rxd; | |||
| 851 | bus_dmamap_t dmap; | |||
| 852 | struct mbuf *m; | |||
| 853 | uint32_t cons, prod, oprod; | |||
| 854 | uint16_t id; | |||
| 855 | int i, flags, resched = 0; | |||
| 856 | ||||
| 857 | cons = rxr->rxr_cons; | |||
| 858 | prod = oprod = rxr->rxr_prod; | |||
| 859 | ||||
| 860 | while (prod - cons < XNF_RX_DESC256) { | |||
| 861 | i = prod & (XNF_RX_DESC256 - 1); | |||
| 862 | rxd = &rxr->rxr_desc[i]; | |||
| 863 | ||||
| 864 | id = rxd->rxd_rsp.rxp_id; | |||
| 865 | if (sc->sc_rx_buf[id]) | |||
| 866 | break; | |||
| 867 | m = MCLGETL(NULL, M_DONTWAIT, XNF_MCLEN)m_clget((((void *)0)), (0x0002), ((1 << 12))); | |||
| 868 | if (m == NULL((void *)0)) | |||
| 869 | break; | |||
| 870 | m->m_lenm_hdr.mh_len = m->m_pkthdrM_dat.MH.MH_pkthdr.len = XNF_MCLEN(1 << 12); | |||
| 871 | dmap = sc->sc_rx_dmap[id]; | |||
| 872 | flags = (sc->sc_domid << 16) | BUS_DMA_READ0x0200 | BUS_DMA_NOWAIT0x0001; | |||
| 873 | if (bus_dmamap_load_mbuf(sc->sc_dmat, dmap, m, flags)(*(sc->sc_dmat)->_dmamap_load_mbuf)((sc->sc_dmat), ( dmap), (m), (flags))) { | |||
| 874 | m_freem(m); | |||
| 875 | break; | |||
| 876 | } | |||
| 877 | sc->sc_rx_buf[id] = m; | |||
| 878 | rxd->rxd_req.rxq_ref = dmap->dm_segs[0].ds_addr; | |||
| 879 | bus_dmamap_sync(sc->sc_dmat, dmap, 0, 0, BUS_DMASYNC_PREWRITE)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (dmap) , (0), (0), (0x04)); | |||
| 880 | prod++; | |||
| 881 | } | |||
| 882 | ||||
| 883 | rxr->rxr_prod = prod; | |||
| 884 | bus_dmamap_sync(sc->sc_dmat, sc->sc_rx_rmap, 0, 0,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_rx_rmap), (0), (0), (0x01 | 0x04)) | |||
| 885 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_rx_rmap), (0), (0), (0x01 | 0x04)); | |||
| 886 | ||||
| 887 | if ((prod - cons < XNF_RX_MIN32) && (ifp->if_flags & IFF_RUNNING0x40)) | |||
| 888 | resched = 1; | |||
| 889 | if (prod - rxr->rxr_prod_event < prod - oprod) | |||
| 890 | xen_intr_signal(sc->sc_xih); | |||
| 891 | ||||
| 892 | return (resched); | |||
| 893 | } | |||
| 894 | ||||
| 895 | int | |||
| 896 | xnf_rx_ring_create(struct xnf_softc *sc) | |||
| 897 | { | |||
| 898 | int i, flags, rsegs; | |||
| 899 | ||||
| 900 | /* Allocate a page of memory for the ring */ | |||
| 901 | if (bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE, 0,(*(sc->sc_dmat)->_dmamem_alloc)((sc->sc_dmat), ((1 << 12)), ((1 << 12)), (0), (&sc->sc_rx_seg), (1), ( &rsegs), (0x1000 | 0x0001)) | |||
| 902 | &sc->sc_rx_seg, 1, &rsegs, BUS_DMA_ZERO | BUS_DMA_NOWAIT)(*(sc->sc_dmat)->_dmamem_alloc)((sc->sc_dmat), ((1 << 12)), ((1 << 12)), (0), (&sc->sc_rx_seg), (1), ( &rsegs), (0x1000 | 0x0001))) { | |||
| 903 | printf("%s: failed to allocate memory for the rx ring\n", | |||
| 904 | sc->sc_dev.dv_xname); | |||
| 905 | return (-1); | |||
| 906 | } | |||
| 907 | /* Map in the allocated memory into the ring structure */ | |||
| 908 | if (bus_dmamem_map(sc->sc_dmat, &sc->sc_rx_seg, 1, PAGE_SIZE,(*(sc->sc_dmat)->_dmamem_map)((sc->sc_dmat), (&sc ->sc_rx_seg), (1), ((1 << 12)), ((caddr_t *)(&sc ->sc_rx_ring)), (0x0001)) | |||
| 909 | (caddr_t *)(&sc->sc_rx_ring), BUS_DMA_NOWAIT)(*(sc->sc_dmat)->_dmamem_map)((sc->sc_dmat), (&sc ->sc_rx_seg), (1), ((1 << 12)), ((caddr_t *)(&sc ->sc_rx_ring)), (0x0001))) { | |||
| 910 | printf("%s: failed to map memory for the rx ring\n", | |||
| 911 | sc->sc_dev.dv_xname); | |||
| 912 | goto errout; | |||
| 913 | } | |||
| 914 | /* Create a map to load the ring memory into */ | |||
| 915 | if (bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 0,(*(sc->sc_dmat)->_dmamap_create)((sc->sc_dmat), ((1 << 12)), (1), ((1 << 12)), (0), (0x0001), (&sc->sc_rx_rmap )) | |||
| 916 | BUS_DMA_NOWAIT, &sc->sc_rx_rmap)(*(sc->sc_dmat)->_dmamap_create)((sc->sc_dmat), ((1 << 12)), (1), ((1 << 12)), (0), (0x0001), (&sc->sc_rx_rmap ))) { | |||
| 917 | printf("%s: failed to create a memory map for the rx ring\n", | |||
| 918 | sc->sc_dev.dv_xname); | |||
| 919 | goto errout; | |||
| 920 | } | |||
| 921 | /* Load the ring into the ring map to extract the PA */ | |||
| 922 | flags = (sc->sc_domid << 16) | BUS_DMA_NOWAIT0x0001; | |||
| 923 | if (bus_dmamap_load(sc->sc_dmat, sc->sc_rx_rmap, sc->sc_rx_ring,(*(sc->sc_dmat)->_dmamap_load)((sc->sc_dmat), (sc-> sc_rx_rmap), (sc->sc_rx_ring), ((1 << 12)), (((void * )0)), (flags)) | |||
| 924 | PAGE_SIZE, NULL, flags)(*(sc->sc_dmat)->_dmamap_load)((sc->sc_dmat), (sc-> sc_rx_rmap), (sc->sc_rx_ring), ((1 << 12)), (((void * )0)), (flags))) { | |||
| 925 | printf("%s: failed to load the rx ring map\n", | |||
| 926 | sc->sc_dev.dv_xname); | |||
| 927 | goto errout; | |||
| 928 | } | |||
| 929 | sc->sc_rx_ref = sc->sc_rx_rmap->dm_segs[0].ds_addr; | |||
| 930 | ||||
| 931 | sc->sc_rx_ring->rxr_prod_event = sc->sc_rx_ring->rxr_cons_event = 1; | |||
| 932 | ||||
| 933 | for (i = 0; i < XNF_RX_DESC256; i++) { | |||
| 934 | if (bus_dmamap_create(sc->sc_dmat, XNF_MCLEN, 1, XNF_MCLEN,(*(sc->sc_dmat)->_dmamap_create)((sc->sc_dmat), ((1 << 12)), (1), ((1 << 12)), ((1 << 12)), (0x0001), ( &sc->sc_rx_dmap[i])) | |||
| 935 | PAGE_SIZE, BUS_DMA_NOWAIT, &sc->sc_rx_dmap[i])(*(sc->sc_dmat)->_dmamap_create)((sc->sc_dmat), ((1 << 12)), (1), ((1 << 12)), ((1 << 12)), (0x0001), ( &sc->sc_rx_dmap[i]))) { | |||
| 936 | printf("%s: failed to create a memory map for the" | |||
| 937 | " rx slot %d\n", sc->sc_dev.dv_xname, i); | |||
| 938 | goto errout; | |||
| 939 | } | |||
| 940 | sc->sc_rx_ring->rxr_desc[i].rxd_req.rxq_id = i; | |||
| 941 | } | |||
| 942 | ||||
| 943 | return (0); | |||
| 944 | ||||
| 945 | errout: | |||
| 946 | xnf_rx_ring_destroy(sc); | |||
| 947 | return (-1); | |||
| 948 | } | |||
| 949 | ||||
| 950 | void | |||
| 951 | xnf_rx_ring_drain(struct xnf_softc *sc) | |||
| 952 | { | |||
| 953 | struct xnf_rx_ring *rxr = sc->sc_rx_ring; | |||
| 954 | ||||
| 955 | if (sc->sc_rx_cons != rxr->rxr_cons) | |||
| 956 | xnf_rxeof(sc); | |||
| 957 | } | |||
| 958 | ||||
| 959 | void | |||
| 960 | xnf_rx_ring_destroy(struct xnf_softc *sc) | |||
| 961 | { | |||
| 962 | int i; | |||
| 963 | ||||
| 964 | for (i = 0; i < XNF_RX_DESC256; i++) { | |||
| 965 | if (sc->sc_rx_buf[i] == NULL((void *)0)) | |||
| 966 | continue; | |||
| 967 | bus_dmamap_sync(sc->sc_dmat, sc->sc_rx_dmap[i], 0, 0,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_rx_dmap[i]), (0), (0), (0x02)) | |||
| 968 | BUS_DMASYNC_POSTREAD)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_rx_dmap[i]), (0), (0), (0x02)); | |||
| 969 | bus_dmamap_unload(sc->sc_dmat, sc->sc_rx_dmap[i])(*(sc->sc_dmat)->_dmamap_unload)((sc->sc_dmat), (sc-> sc_rx_dmap[i])); | |||
| 970 | m_freem(sc->sc_rx_buf[i]); | |||
| 971 | sc->sc_rx_buf[i] = NULL((void *)0); | |||
| 972 | } | |||
| 973 | ||||
| 974 | for (i = 0; i < XNF_RX_DESC256; i++) { | |||
| 975 | if (sc->sc_rx_dmap[i] == NULL((void *)0)) | |||
| 976 | continue; | |||
| 977 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_dmap[i])(*(sc->sc_dmat)->_dmamap_destroy)((sc->sc_dmat), (sc ->sc_rx_dmap[i])); | |||
| 978 | sc->sc_rx_dmap[i] = NULL((void *)0); | |||
| 979 | } | |||
| 980 | if (sc->sc_rx_rmap) { | |||
| 981 | bus_dmamap_sync(sc->sc_dmat, sc->sc_rx_rmap, 0, 0,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_rx_rmap), (0), (0), (0x02 | 0x08)) | |||
| 982 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_rx_rmap), (0), (0), (0x02 | 0x08)); | |||
| 983 | bus_dmamap_unload(sc->sc_dmat, sc->sc_rx_rmap)(*(sc->sc_dmat)->_dmamap_unload)((sc->sc_dmat), (sc-> sc_rx_rmap)); | |||
| 984 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_rmap)(*(sc->sc_dmat)->_dmamap_destroy)((sc->sc_dmat), (sc ->sc_rx_rmap)); | |||
| 985 | } | |||
| 986 | if (sc->sc_rx_ring) { | |||
| 987 | bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_rx_ring,(*(sc->sc_dmat)->_dmamem_unmap)((sc->sc_dmat), ((caddr_t )sc->sc_rx_ring), ((1 << 12))) | |||
| 988 | PAGE_SIZE)(*(sc->sc_dmat)->_dmamem_unmap)((sc->sc_dmat), ((caddr_t )sc->sc_rx_ring), ((1 << 12))); | |||
| 989 | bus_dmamem_free(sc->sc_dmat, &sc->sc_rx_seg, 1)(*(sc->sc_dmat)->_dmamem_free)((sc->sc_dmat), (& sc->sc_rx_seg), (1)); | |||
| 990 | } | |||
| 991 | sc->sc_rx_ring = NULL((void *)0); | |||
| 992 | sc->sc_rx_rmap = NULL((void *)0); | |||
| 993 | sc->sc_rx_cons = 0; | |||
| 994 | } | |||
| 995 | ||||
| 996 | int | |||
| 997 | xnf_tx_ring_create(struct xnf_softc *sc) | |||
| 998 | { | |||
| 999 | struct ifnet *ifp = &sc->sc_ac.ac_if; | |||
| 1000 | int i, flags, nsegs, rsegs; | |||
| 1001 | bus_size_t segsz; | |||
| 1002 | ||||
| 1003 | sc->sc_tx_frags = sc->sc_caps & XNF_CAP_SG0x0001 ? XNF_TX_FRAG18 : 1; | |||
| 1004 | ||||
| 1005 | /* Allocate a page of memory for the ring */ | |||
| 1006 | if (bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE, 0,(*(sc->sc_dmat)->_dmamem_alloc)((sc->sc_dmat), ((1 << 12)), ((1 << 12)), (0), (&sc->sc_tx_seg), (1), ( &rsegs), (0x1000 | 0x0001)) | |||
| 1007 | &sc->sc_tx_seg, 1, &rsegs, BUS_DMA_ZERO | BUS_DMA_NOWAIT)(*(sc->sc_dmat)->_dmamem_alloc)((sc->sc_dmat), ((1 << 12)), ((1 << 12)), (0), (&sc->sc_tx_seg), (1), ( &rsegs), (0x1000 | 0x0001))) { | |||
| 1008 | printf("%s: failed to allocate memory for the tx ring\n", | |||
| 1009 | sc->sc_dev.dv_xname); | |||
| 1010 | return (-1); | |||
| 1011 | } | |||
| 1012 | /* Map in the allocated memory into the ring structure */ | |||
| 1013 | if (bus_dmamem_map(sc->sc_dmat, &sc->sc_tx_seg, 1, PAGE_SIZE,(*(sc->sc_dmat)->_dmamem_map)((sc->sc_dmat), (&sc ->sc_tx_seg), (1), ((1 << 12)), ((caddr_t *)&sc-> sc_tx_ring), (0x0001)) | |||
| 1014 | (caddr_t *)&sc->sc_tx_ring, BUS_DMA_NOWAIT)(*(sc->sc_dmat)->_dmamem_map)((sc->sc_dmat), (&sc ->sc_tx_seg), (1), ((1 << 12)), ((caddr_t *)&sc-> sc_tx_ring), (0x0001))) { | |||
| 1015 | printf("%s: failed to map memory for the tx ring\n", | |||
| 1016 | sc->sc_dev.dv_xname); | |||
| 1017 | goto errout; | |||
| 1018 | } | |||
| 1019 | /* Create a map to load the ring memory into */ | |||
| 1020 | if (bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 0,(*(sc->sc_dmat)->_dmamap_create)((sc->sc_dmat), ((1 << 12)), (1), ((1 << 12)), (0), (0x0001), (&sc->sc_tx_rmap )) | |||
| 1021 | BUS_DMA_NOWAIT, &sc->sc_tx_rmap)(*(sc->sc_dmat)->_dmamap_create)((sc->sc_dmat), ((1 << 12)), (1), ((1 << 12)), (0), (0x0001), (&sc->sc_tx_rmap ))) { | |||
| 1022 | printf("%s: failed to create a memory map for the tx ring\n", | |||
| 1023 | sc->sc_dev.dv_xname); | |||
| 1024 | goto errout; | |||
| 1025 | } | |||
| 1026 | /* Load the ring into the ring map to extract the PA */ | |||
| 1027 | flags = (sc->sc_domid << 16) | BUS_DMA_NOWAIT0x0001; | |||
| 1028 | if (bus_dmamap_load(sc->sc_dmat, sc->sc_tx_rmap, sc->sc_tx_ring,(*(sc->sc_dmat)->_dmamap_load)((sc->sc_dmat), (sc-> sc_tx_rmap), (sc->sc_tx_ring), ((1 << 12)), (((void * )0)), (flags)) | |||
| 1029 | PAGE_SIZE, NULL, flags)(*(sc->sc_dmat)->_dmamap_load)((sc->sc_dmat), (sc-> sc_tx_rmap), (sc->sc_tx_ring), ((1 << 12)), (((void * )0)), (flags))) { | |||
| 1030 | printf("%s: failed to load the tx ring map\n", | |||
| 1031 | sc->sc_dev.dv_xname); | |||
| 1032 | goto errout; | |||
| 1033 | } | |||
| 1034 | sc->sc_tx_ref = sc->sc_tx_rmap->dm_segs[0].ds_addr; | |||
| 1035 | ||||
| 1036 | sc->sc_tx_ring->txr_prod_event = sc->sc_tx_ring->txr_cons_event = 1; | |||
| 1037 | ||||
| 1038 | if (sc->sc_caps & XNF_CAP_SG0x0001) { | |||
| 1039 | nsegs = roundup(ifp->if_hardmtu, XNF_MCLEN)((((ifp->if_hardmtu)+(((1 << 12))-1))/((1 << 12 )))*((1 << 12))) / XNF_MCLEN(1 << 12) + 1; | |||
| 1040 | segsz = nsegs * XNF_MCLEN(1 << 12); | |||
| 1041 | } else { | |||
| 1042 | nsegs = 1; | |||
| 1043 | segsz = XNF_MCLEN(1 << 12); | |||
| 1044 | } | |||
| 1045 | for (i = 0; i < XNF_TX_DESC256; i++) { | |||
| 1046 | if (bus_dmamap_create(sc->sc_dmat, segsz, nsegs, XNF_MCLEN,(*(sc->sc_dmat)->_dmamap_create)((sc->sc_dmat), (segsz ), (nsegs), ((1 << 12)), ((1 << 12)), (0x0001), ( &sc->sc_tx_buf[i].txb_dmap)) | |||
| 1047 | PAGE_SIZE, BUS_DMA_NOWAIT, &sc->sc_tx_buf[i].txb_dmap)(*(sc->sc_dmat)->_dmamap_create)((sc->sc_dmat), (segsz ), (nsegs), ((1 << 12)), ((1 << 12)), (0x0001), ( &sc->sc_tx_buf[i].txb_dmap))) { | |||
| 1048 | printf("%s: failed to create a memory map for the" | |||
| 1049 | " tx slot %d\n", sc->sc_dev.dv_xname, i); | |||
| 1050 | goto errout; | |||
| 1051 | } | |||
| 1052 | } | |||
| 1053 | ||||
| 1054 | sc->sc_tx_avail = XNF_TX_DESC256; | |||
| 1055 | sc->sc_tx_next = 0; | |||
| 1056 | ||||
| 1057 | return (0); | |||
| 1058 | ||||
| 1059 | errout: | |||
| 1060 | xnf_tx_ring_destroy(sc); | |||
| 1061 | return (-1); | |||
| 1062 | } | |||
| 1063 | ||||
| 1064 | void | |||
| 1065 | xnf_tx_ring_drain(struct xnf_softc *sc) | |||
| 1066 | { | |||
| 1067 | struct xnf_tx_ring *txr = sc->sc_tx_ring; | |||
| 1068 | ||||
| 1069 | if (sc->sc_tx_cons != txr->txr_cons) | |||
| 1070 | xnf_txeof(sc); | |||
| 1071 | } | |||
| 1072 | ||||
| 1073 | void | |||
| 1074 | xnf_tx_ring_destroy(struct xnf_softc *sc) | |||
| 1075 | { | |||
| 1076 | int i; | |||
| 1077 | ||||
| 1078 | for (i = 0; i < XNF_TX_DESC256; i++) { | |||
| 1079 | if (sc->sc_tx_buf[i].txb_dmap == NULL((void *)0)) | |||
| 1080 | continue; | |||
| 1081 | bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_buf[i].txb_dmap, 0, 0,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_tx_buf[i].txb_dmap), (0), (0), (0x08)) | |||
| 1082 | BUS_DMASYNC_POSTWRITE)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_tx_buf[i].txb_dmap), (0), (0), (0x08)); | |||
| 1083 | bus_dmamap_unload(sc->sc_dmat, sc->sc_tx_buf[i].txb_dmap)(*(sc->sc_dmat)->_dmamap_unload)((sc->sc_dmat), (sc-> sc_tx_buf[i].txb_dmap)); | |||
| 1084 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_buf[i].txb_dmap)(*(sc->sc_dmat)->_dmamap_destroy)((sc->sc_dmat), (sc ->sc_tx_buf[i].txb_dmap)); | |||
| 1085 | sc->sc_tx_buf[i].txb_dmap = NULL((void *)0); | |||
| 1086 | if (sc->sc_tx_buf[i].txb_mbuf == NULL((void *)0)) | |||
| 1087 | continue; | |||
| 1088 | m_free(sc->sc_tx_buf[i].txb_mbuf); | |||
| 1089 | sc->sc_tx_buf[i].txb_mbuf = NULL((void *)0); | |||
| 1090 | sc->sc_tx_buf[i].txb_ndesc = 0; | |||
| 1091 | } | |||
| 1092 | if (sc->sc_tx_rmap) { | |||
| 1093 | bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_rmap, 0, 0,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_tx_rmap), (0), (0), (0x02 | 0x08)) | |||
| 1094 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_tx_rmap), (0), (0), (0x02 | 0x08)); | |||
| 1095 | bus_dmamap_unload(sc->sc_dmat, sc->sc_tx_rmap)(*(sc->sc_dmat)->_dmamap_unload)((sc->sc_dmat), (sc-> sc_tx_rmap)); | |||
| 1096 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_rmap)(*(sc->sc_dmat)->_dmamap_destroy)((sc->sc_dmat), (sc ->sc_tx_rmap)); | |||
| 1097 | } | |||
| 1098 | if (sc->sc_tx_ring) { | |||
| 1099 | bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_tx_ring,(*(sc->sc_dmat)->_dmamem_unmap)((sc->sc_dmat), ((caddr_t )sc->sc_tx_ring), ((1 << 12))) | |||
| 1100 | PAGE_SIZE)(*(sc->sc_dmat)->_dmamem_unmap)((sc->sc_dmat), ((caddr_t )sc->sc_tx_ring), ((1 << 12))); | |||
| 1101 | bus_dmamem_free(sc->sc_dmat, &sc->sc_tx_seg, 1)(*(sc->sc_dmat)->_dmamem_free)((sc->sc_dmat), (& sc->sc_tx_seg), (1)); | |||
| 1102 | } | |||
| 1103 | sc->sc_tx_ring = NULL((void *)0); | |||
| 1104 | sc->sc_tx_rmap = NULL((void *)0); | |||
| 1105 | sc->sc_tx_avail = XNF_TX_DESC256; | |||
| 1106 | sc->sc_tx_next = 0; | |||
| 1107 | } | |||
| 1108 | ||||
| 1109 | int | |||
| 1110 | xnf_capabilities(struct xnf_softc *sc) | |||
| 1111 | { | |||
| 1112 | unsigned long long res; | |||
| 1113 | const char *prop; | |||
| 1114 | int error; | |||
| 1115 | ||||
| 1116 | /* Query scatter-gather capability */ | |||
| 1117 | prop = "feature-sg"; | |||
| 1118 | if ((error = xs_getnum(sc->sc_parent, sc->sc_backend, prop, &res)) != 0 | |||
| 1119 | && error != ENOENT2) | |||
| 1120 | goto errout; | |||
| 1121 | if (error == 0 && res == 1) | |||
| 1122 | sc->sc_caps |= XNF_CAP_SG0x0001; | |||
| 1123 | ||||
| 1124 | #if 0 | |||
| 1125 | /* Query IPv4 checksum offloading capability, enabled by default */ | |||
| 1126 | sc->sc_caps |= XNF_CAP_CSUM40x0002; | |||
| 1127 | prop = "feature-no-csum-offload"; | |||
| 1128 | if ((error = xs_getnum(sc->sc_parent, sc->sc_backend, prop, &res)) != 0 | |||
| 1129 | && error != ENOENT2) | |||
| 1130 | goto errout; | |||
| 1131 | if (error == 0 && res == 1) | |||
| 1132 | sc->sc_caps &= ~XNF_CAP_CSUM40x0002; | |||
| 1133 | ||||
| 1134 | /* Query IPv6 checksum offloading capability */ | |||
| 1135 | prop = "feature-ipv6-csum-offload"; | |||
| 1136 | if ((error = xs_getnum(sc->sc_parent, sc->sc_backend, prop, &res)) != 0 | |||
| 1137 | && error != ENOENT2) | |||
| 1138 | goto errout; | |||
| 1139 | if (error == 0 && res == 1) | |||
| 1140 | sc->sc_caps |= XNF_CAP_CSUM60x0004; | |||
| 1141 | #endif | |||
| 1142 | ||||
| 1143 | /* Query multicast traffic control capability */ | |||
| 1144 | prop = "feature-multicast-control"; | |||
| 1145 | if ((error = xs_getnum(sc->sc_parent, sc->sc_backend, prop, &res)) != 0 | |||
| 1146 | && error != ENOENT2) | |||
| 1147 | goto errout; | |||
| 1148 | if (error == 0 && res == 1) | |||
| 1149 | sc->sc_caps |= XNF_CAP_MCAST0x0008; | |||
| 1150 | ||||
| 1151 | /* Query split Rx/Tx event channel capability */ | |||
| 1152 | prop = "feature-split-event-channels"; | |||
| 1153 | if ((error = xs_getnum(sc->sc_parent, sc->sc_backend, prop, &res)) != 0 | |||
| 1154 | && error != ENOENT2) | |||
| 1155 | goto errout; | |||
| 1156 | if (error == 0 && res == 1) | |||
| 1157 | sc->sc_caps |= XNF_CAP_SPLIT0x0010; | |||
| 1158 | ||||
| 1159 | /* Query multiqueue capability */ | |||
| 1160 | prop = "multi-queue-max-queues"; | |||
| 1161 | if ((error = xs_getnum(sc->sc_parent, sc->sc_backend, prop, &res)) != 0 | |||
| 1162 | && error != ENOENT2) | |||
| 1163 | goto errout; | |||
| 1164 | if (error == 0) | |||
| 1165 | sc->sc_caps |= XNF_CAP_MULTIQ0x0020; | |||
| 1166 | ||||
| 1167 | DPRINTF("%s: capabilities %b\n", sc->sc_dev.dv_xname, sc->sc_caps, | |||
| 1168 | "\20\006MULTIQ\005SPLIT\004MCAST\003CSUM6\002CSUM4\001SG"); | |||
| 1169 | return (0); | |||
| 1170 | ||||
| 1171 | errout: | |||
| 1172 | printf("%s: failed to read \"%s\" property\n", sc->sc_dev.dv_xname, | |||
| 1173 | prop); | |||
| 1174 | return (-1); | |||
| 1175 | } | |||
| 1176 | ||||
| 1177 | int | |||
| 1178 | xnf_init_backend(struct xnf_softc *sc) | |||
| 1179 | { | |||
| 1180 | const char *prop; | |||
| 1181 | ||||
| 1182 | /* Plumb the Rx ring */ | |||
| 1183 | prop = "rx-ring-ref"; | |||
| 1184 | if (xs_setnum(sc->sc_parent, sc->sc_node, prop, sc->sc_rx_ref)) | |||
| 1185 | goto errout; | |||
| 1186 | /* Enable "copy" mode */ | |||
| 1187 | prop = "request-rx-copy"; | |||
| 1188 | if (xs_setnum(sc->sc_parent, sc->sc_node, prop, 1)) | |||
| 1189 | goto errout; | |||
| 1190 | /* Enable notify mode */ | |||
| 1191 | prop = "feature-rx-notify"; | |||
| 1192 | if (xs_setnum(sc->sc_parent, sc->sc_node, prop, 1)) | |||
| 1193 | goto errout; | |||
| 1194 | ||||
| 1195 | /* Plumb the Tx ring */ | |||
| 1196 | prop = "tx-ring-ref"; | |||
| 1197 | if (xs_setnum(sc->sc_parent, sc->sc_node, prop, sc->sc_tx_ref)) | |||
| 1198 | goto errout; | |||
| 1199 | /* Enable scatter-gather mode */ | |||
| 1200 | if (sc->sc_tx_frags > 1) { | |||
| 1201 | prop = "feature-sg"; | |||
| 1202 | if (xs_setnum(sc->sc_parent, sc->sc_node, prop, 1)) | |||
| 1203 | goto errout; | |||
| 1204 | } | |||
| 1205 | ||||
| 1206 | /* Disable IPv4 checksum offloading */ | |||
| 1207 | if (!(sc->sc_caps & XNF_CAP_CSUM40x0002)) { | |||
| 1208 | prop = "feature-no-csum-offload"; | |||
| 1209 | if (xs_setnum(sc->sc_parent, sc->sc_node, prop, 1)) | |||
| 1210 | goto errout; | |||
| 1211 | } | |||
| 1212 | ||||
| 1213 | /* Enable IPv6 checksum offloading */ | |||
| 1214 | if (sc->sc_caps & XNF_CAP_CSUM60x0004) { | |||
| 1215 | prop = "feature-ipv6-csum-offload"; | |||
| 1216 | if (xs_setnum(sc->sc_parent, sc->sc_node, prop, 1)) | |||
| 1217 | goto errout; | |||
| 1218 | } | |||
| 1219 | ||||
| 1220 | /* Plumb the event channel port */ | |||
| 1221 | prop = "event-channel"; | |||
| 1222 | if (xs_setnum(sc->sc_parent, sc->sc_node, prop, sc->sc_xih)) | |||
| 1223 | goto errout; | |||
| 1224 | ||||
| 1225 | /* Connect the device */ | |||
| 1226 | prop = "state"; | |||
| 1227 | if (xs_setprop(sc->sc_parent, sc->sc_node, prop, XEN_STATE_CONNECTED"4", | |||
| 1228 | strlen(XEN_STATE_CONNECTED"4"))) | |||
| 1229 | goto errout; | |||
| 1230 | ||||
| 1231 | return (0); | |||
| 1232 | ||||
| 1233 | errout: | |||
| 1234 | printf("%s: failed to set \"%s\" property\n", sc->sc_dev.dv_xname, prop); | |||
| 1235 | return (-1); | |||
| 1236 | } |