uipc_mvec.c revision 168496
1/************************************************************************** 2 * 3 * Copyright (c) 2007, Kip Macy kmacy@freebsd.org 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 * 28 * 29 ***************************************************************************/ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD: head/sys/dev/cxgb/sys/uipc_mvec.c 168496 2007-04-08 15:59:07Z kmacy $"); 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/kernel.h> 37#include <sys/lock.h> 38#include <sys/malloc.h> 39#include <sys/mbuf.h> 40#include <sys/ktr.h> 41 42#include <machine/bus.h> 43 44#include <dev/cxgb/sys/mvec.h> 45 46int 47_m_explode(struct mbuf *m) 48{ 49 int i, offset, type; 50 void *cl; 51 struct mbuf *m0, *head = NULL; 52 struct mbuf_vec *mv; 53 54 mv = mtomv(m); 55 for (i = mv->mv_count + mv->mv_first - 1; 56 i > mv->mv_first; i--) { 57 cl = mv->mv_vec[i].mi_base; 58 if ((m0 = m_get(M_NOWAIT, MT_DATA)) == NULL) { 59 m_freem(head); 60 return (ENOMEM); 61 } 62 m0->m_flags = 0; 63 type = mbuf_vec_get_type(mv, i); 64 m_cljset(m0, (uint8_t *)cl, type); 65 m0->m_len = mv->mv_vec[i].mi_size; 66 67 offset = mv->mv_vec[i].mi_offset; 68 69 if (offset) 70 m_adj(m, offset); 71 72 m0->m_next = head; 73 m->m_len -= m0->m_len; 74 head = m0; 75 } 76 offset = mv->mv_vec[0].mi_offset; 77 cl = mv->mv_vec[0].mi_base; 78 type = mbuf_vec_get_type(mv, 0); 79 m->m_flags &= ~(M_IOVEC); 80 m_cljset(m, cl, type); 81 if (offset) 82 m_adj(m, offset); 83 m->m_next = head; 84 85 return (0); 86} 87 88#define MAX_BUFS 36 89 90int 91_m_collapse(struct mbuf *m, int maxbufs, struct mbuf **mnew) 92{ 93 struct mbuf *m0, *lvec[MAX_BUFS]; 94 struct mbuf **mnext, **vec = &lvec[0]; 95 struct mbuf *mhead = NULL; 96 struct mbuf_vec *mv; 97 int i, j, max; 98 99 if (maxbufs > MAX_BUFS) 100 if ((vec = malloc(maxbufs * sizeof(struct mbuf *), 101 M_DEVBUF, M_NOWAIT)) == NULL) 102 return (ENOMEM); 103 104 m0 = m; 105 for (i = 0; i < maxbufs; i++) { 106 if (m0 == NULL) 107 goto batch; 108 vec[i] = m0; 109 m0 = m0->m_next; 110 } 111 112 if (i == maxbufs) 113 return (EFBIG); 114batch: 115 max = i; 116 i = 0; 117 m0 = NULL; 118 mnext = NULL; 119 while (i < max) { 120 if ((vec[i]->m_flags & M_EXT) == 0) { 121 m0 = m_get(M_NOWAIT, MT_DATA); 122 } else { 123 m0 = vec[i]; 124 m0->m_flags = (vec[i]->m_flags & ~M_EXT); 125 } 126 m0->m_flags |= M_IOVEC; 127 if (m0 == NULL) 128 goto m_getfail; 129 if (i == 0) 130 mhead = m0; 131 if (mnext) 132 *mnext = m0; 133 mv = mtomv(m0); 134 mv->mv_count = mv->mv_first = 0; 135 for (j = 0; j < MAX_MBUF_IOV; j++, i++) { 136 if (vec[i]->m_flags & M_EXT) { 137 mv->mv_vec[j].mi_base = vec[i]->m_ext.ext_buf; 138 mv->mv_vec[j].mi_offset = 139 (vec[i]->m_ext.ext_buf - vec[i]->m_data); 140 mv->mv_vec[j].mi_size = vec[i]->m_ext.ext_size; 141 mv->mv_vec[j].mi_flags = vec[i]->m_ext.ext_type; 142 } else { 143 mv->mv_vec[j].mi_base = (caddr_t)vec[i]; 144 mv->mv_vec[j].mi_offset = 145 ((caddr_t)vec[i] - vec[i]->m_data); 146 mv->mv_vec[j].mi_size = MSIZE; 147 mv->mv_vec[j].mi_flags = EXT_MBUF; 148 } 149 } 150 mnext = &m0->m_next; 151 } 152 153 mhead->m_flags |= (m0->m_flags & M_PKTHDR); 154 *mnew = mhead; 155 return (0); 156 157m_getfail: 158 m0 = mhead; 159 while (mhead) { 160 mhead = m0->m_next; 161 uma_zfree(zone_mbuf, m0); 162 } 163 return (ENOMEM); 164} 165 166void 167mb_free_vec(struct mbuf *m) 168{ 169 struct mbuf_vec *mv; 170 int i; 171 172 KASSERT((m->m_flags & (M_EXT|M_IOVEC)) == M_IOVEC, 173 ("%s: M_IOVEC not set", __func__)); 174 175 mv = mtomv(m); 176 KASSERT(mv->mv_count <= MAX_MBUF_IOV, 177 ("%s: mi_count too large %d", __func__, mv->mv_count)); 178 179 for (i = mv->mv_first; i < mv->mv_count; i++) { 180 uma_zone_t zone = NULL; 181 int *refcnt; 182 int type = mbuf_vec_get_type(mv, i); 183 void *cl = mv->mv_vec[i].mi_base; 184 int size = mv->mv_vec[i].mi_size; 185 186 zone = m_getzone(size); 187 refcnt = uma_find_refcnt(zone, cl); 188 if (*refcnt != 1 && atomic_fetchadd_int(refcnt, -1) != 1) 189 continue; 190 191 switch (type) { 192 case EXT_PACKET: /* The packet zone is special. */ 193 if (*refcnt == 0) 194 *refcnt = 1; 195 uma_zfree(zone_pack, m); 196 return; /* Job done. */ 197 case EXT_CLUSTER: 198 case EXT_JUMBOP: 199 case EXT_JUMBO9: 200 case EXT_JUMBO16: 201 uma_zfree(zone, cl); 202 continue; 203 case EXT_SFBUF: 204 *refcnt = 0; 205 uma_zfree(zone_ext_refcnt, __DEVOLATILE(u_int *, 206 refcnt)); 207 /* FALLTHROUGH */ 208 case EXT_EXTREF: 209#ifdef notyet 210 KASSERT(m->m_ext.ext_free != NULL, 211 ("%s: ext_free not set", __func__)); 212 (*(m->m_ext.ext_free))(m->m_ext.ext_buf, 213 m->m_ext.ext_args); 214#endif 215 /* 216 * XXX 217 */ 218 panic("unsupported mbuf_vec type: %d\n", type); 219 break; 220 default: 221 KASSERT(m->m_ext.ext_type == 0, 222 ("%s: unknown ext_type", __func__)); 223 224 } 225 } 226 /* 227 * Free this mbuf back to the mbuf zone with all m_ext 228 * information purged. 229 */ 230 m->m_flags &= ~M_IOVEC; 231 uma_zfree(zone_mbuf, m); 232} 233 234struct mvec_sg_cb_arg { 235 int error; 236 bus_dma_segment_t seg; 237 int nseg; 238}; 239 240struct bus_dma_tag { 241 bus_dma_tag_t parent; 242 bus_size_t alignment; 243 bus_size_t boundary; 244 bus_addr_t lowaddr; 245 bus_addr_t highaddr; 246 bus_dma_filter_t *filter; 247 void *filterarg; 248 bus_size_t maxsize; 249 u_int nsegments; 250 bus_size_t maxsegsz; 251 int flags; 252 int ref_count; 253 int map_count; 254 bus_dma_lock_t *lockfunc; 255 void *lockfuncarg; 256 bus_dma_segment_t *segments; 257 struct bounce_zone *bounce_zone; 258}; 259 260static void 261mvec_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 262{ 263 struct mvec_sg_cb_arg *cb_arg = arg; 264 265 cb_arg->error = error; 266 cb_arg->seg = segs[0]; 267 cb_arg->nseg = nseg; 268 269} 270 271int 272bus_dmamap_load_mvec_sg(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0, 273 bus_dma_segment_t *segs, int *nsegs, int flags) 274{ 275 int error; 276 struct mbuf_vec *mv; 277 struct mvec_sg_cb_arg cb_arg; 278 279 M_ASSERTPKTHDR(m0); 280 281 flags |= BUS_DMA_NOWAIT; 282 *nsegs = 0; 283 error = 0; 284 if (m0->m_pkthdr.len <= 285 dmat->maxsize) { 286 struct mbuf *m; 287 288 for (m = m0; m != NULL && error == 0; m = m->m_next) { 289 int count, first, i; 290 if (!(m->m_len > 0)) 291 continue; 292 293 mv = mtomv(m); 294 count = mv->mv_count; 295 first = mv->mv_first; 296 for (i = first; i < count; i++) { 297 void *data = mv->mv_vec[i].mi_base; 298 int size = mv->mv_vec[i].mi_size; 299 300 cb_arg.seg = *segs; 301 error = bus_dmamap_load(dmat, map, 302 data, size, mvec_cb, &cb_arg, flags); 303 segs++; 304 *nsegs++; 305 if (error || cb_arg.error) 306 goto err_out; 307 } 308 } 309 } else { 310 error = EINVAL; 311 } 312 313 /* XXX FIXME: Having to increment nsegs is really annoying */ 314 ++*nsegs; 315 CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d", 316 __func__, dmat, dmat->flags, error, *nsegs); 317 return (error); 318 319err_out: 320 if (cb_arg.error) 321 return (cb_arg.error); 322 323 return (error); 324} 325