1 /**************************************************************************
3 * Copyright (c) 2007, Kip Macy kmacy@freebsd.org
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
12 * 2. The name of Kip Macy nor the names of other
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
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.
29 ***************************************************************************/
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
38 #include <sys/malloc.h>
41 #include <sys/sf_buf.h>
46 #include <machine/bus.h>
51 #include <cxgb_include.h>
54 #include <dev/cxgb/cxgb_include.h>
55 #include <dev/cxgb/sys/mvec.h>
61 #include <vm/vm_page.h>
65 #define M_SANITY m_sanity
67 #define M_SANITY(a, b)
73 extern uint32_t collapse_free;
74 extern uint32_t mb_free_vec_free;
76 uma_zone_t zone_miovec;
77 static int mi_inited = 0;
78 int cxgb_mbufs_outstanding = 0;
79 int cxgb_pack_outstanding = 0;
89 zone_miovec = uma_zcreate("MBUF IOVEC", MIOVBYTES,
90 NULL, NULL, NULL, NULL,
91 UMA_ALIGN_PTR, UMA_ZONE_MAXBUCKET);
99 uma_zdestroy(zone_miovec);
103 dump_mi(struct mbuf_iovec *mi)
108 printf("mi_flags=0x%08x mi_base=%p mi_data=%p mi_len=%d mi_type=%d\n",
109 mi->mi_flags, mi->mi_base, mi->mi_data, mi->mi_len, mi->mi_type);
111 if (mi->mi_type == EXT_CLIOVEC ||
112 mi->mi_type == EXT_IOVEC) {
113 mv = mtomv((struct mbuf *)mi->mi_base);
115 for (i = 0; i < mv->mv_count; i++, mi++)
121 static __inline struct mbuf *
122 _mcl_collapse_mbuf(struct mbuf_iovec *mi, struct mbuf *m)
124 struct mbuf *n = m->m_next;
128 mi->mi_flags = m->m_flags;
129 mi->mi_len = m->m_len;
132 if (m->m_flags & M_PKTHDR) {
133 mi->mi_ether_vtag = m->m_pkthdr.ether_vtag;
134 mi->mi_tso_segsz = m->m_pkthdr.tso_segsz;
136 mi->mi_rss_hash = m->m_pkthdr.rss_hash;
139 if (m->m_type != MT_DATA) {
141 mi->mi_base = (caddr_t)m;
145 mi->mi_size = (m->m_type == EXT_CLIOVEC) ? MCLBYTES : MIOVBYTES;
146 mi->mi_type = m->m_type;
147 mi->mi_len = m->m_pkthdr.len;
148 KASSERT(mi->mi_len, ("empty packet"));
149 mi->mi_refcnt = NULL;
150 } else if (m->m_flags & M_EXT) {
151 memcpy(&mi->mi_ext, &m->m_ext, sizeof(struct m_ext_));
152 mi->mi_data = m->m_data;
153 mi->mi_base = m->m_ext.ext_buf;
154 mi->mi_type = m->m_ext.ext_type;
155 mi->mi_size = m->m_ext.ext_size;
156 mi->mi_refcnt = m->m_ext.ref_cnt;
159 mi->mi_base = (caddr_t)m;
160 mi->mi_data = m->m_data;
162 mi->mi_type = EXT_MBUF;
163 mi->mi_refcnt = NULL;
165 KASSERT(mi->mi_len != 0, ("miov has len 0"));
166 KASSERT(mi->mi_type > 0, ("mi_type is invalid"));
167 KASSERT(mi->mi_base, ("mi_base is invalid"));
172 mi_collapse_mbuf(struct mbuf_iovec *mi, struct mbuf *m)
174 return _mcl_collapse_mbuf(mi, m);
178 mcl_alloc(int seg_count, int *type)
182 if (seg_count > MAX_CL_IOV) {
184 *type = EXT_JMPIOVEC;
185 } else if (seg_count > MAX_MIOVEC_IOV) {
192 return uma_zalloc_arg(zone, NULL, M_NOWAIT);
196 busdma_map_sg_collapse(struct mbuf **m, bus_dma_segment_t *segs, int *nsegs)
198 struct mbuf *m0, *mhead, *n = *m;
199 struct mbuf_iovec *mi;
200 struct mbuf *marray[TX_MAX_SEGS];
201 int i, type, seg_count, defragged = 0, err = 0;
203 int skipped, freed, outstanding, pack_outstanding, mbuf_outstanding;
207 KASSERT(n->m_pkthdr.len, ("packet has zero header len"));
209 if (n->m_flags & M_PKTHDR && !SLIST_EMPTY(&n->m_pkthdr.tags))
210 m_tag_delete_chain(n, NULL);
212 if (n->m_pkthdr.len <= PIO_LEN)
216 if (n->m_next == NULL) {
217 busdma_map_mbuf_fast(n, segs);
219 if ((n->m_flags & M_EXT) &&
220 (n->m_ext.ext_type == EXT_PACKET))
221 cxgb_pack_outstanding++;
222 else if ((n->m_flags & M_NOFREE) == 0)
223 cxgb_mbufs_outstanding++;
226 skipped = freed = outstanding = pack_outstanding = mbuf_outstanding = 0;
227 while (n && seg_count < TX_MAX_SEGS) {
228 marray[seg_count] = n;
231 * firmware doesn't like empty segments
233 if (__predict_true(n->m_len != 0))
240 if (seg_count == 0) {
242 printf("empty segment chain\n");
245 } else if (seg_count >= TX_MAX_SEGS) {
247 printf("mbuf chain too long: %d max allowed %d\n",
248 seg_count, TX_MAX_SEGS);
250 n = m_defrag(*m, M_DONTWAIT);
263 if ((m0 = mcl_alloc(seg_count, &type)) == NULL) {
268 memcpy(m0, *m, sizeof(struct m_hdr) + sizeof(struct pkthdr));
270 KASSERT(m0->m_pkthdr.len, ("empty packet being marshalled"));
272 mv->mv_count = seg_count;
274 for (i = 0, mi = mv->mv_vec; i < seg_count; mi++, segs++, i++) {
276 busdma_map_mbuf_fast(n, segs);
277 _mcl_collapse_mbuf(mi, n);
282 /* do nothing - free if mbuf or cluster */;
283 else if ((n->m_flags & M_EXT) == 0) {
286 } else if ((n->m_flags & M_EXT) &&
287 (n->m_ext.ext_type == EXT_PACKET)) {
290 } else if (n->m_flags & M_NOFREE)
292 else if ((n->m_flags & (M_EXT|M_NOFREE)) == M_EXT)
293 n->m_flags &= ~M_EXT;
301 * is an immediate mbuf or is from the packet zone
307 DPRINTF("pktlen=%d m0=%p *m=%p m=%p\n", m0->m_pkthdr.len, m0, *m, m);
308 cxgb_mbufs_outstanding += mbuf_outstanding;
309 cxgb_pack_outstanding += pack_outstanding;
318 busdma_map_sg_vec(struct mbuf **m, struct mbuf **mret, bus_dma_segment_t *segs, int count)
320 struct mbuf *m0, **mp;
321 struct mbuf_iovec *mi;
325 if (count > MAX_MIOVEC_IOV) {
326 if ((m0 = uma_zalloc_arg(zone_clust, NULL, M_NOWAIT)) == NULL)
328 m0->m_type = EXT_CLIOVEC;
330 if ((m0 = uma_zalloc_arg(zone_miovec, NULL, M_NOWAIT)) == NULL)
332 m0->m_type = EXT_IOVEC;
336 m0->m_pkthdr.len = m0->m_len = (*m)->m_len; /* not the real length but needs to be non-zero */
338 mv->mv_count = count;
340 for (mp = m, i = 0, mi = mv->mv_vec; i < count; mp++, segs++, mi++, i++) {
341 if ((*mp)->m_flags & M_PKTHDR && !SLIST_EMPTY(&(*mp)->m_pkthdr.tags))
342 m_tag_delete_chain(*mp, NULL);
343 busdma_map_mbuf_fast(*mp, segs);
344 _mcl_collapse_mbuf(mi, *mp);
345 KASSERT(mi->mi_len, ("empty packet"));
348 for (mp = m, i = 0; i < count; i++, mp++) {
349 (*mp)->m_next = (*mp)->m_nextpkt = NULL;
350 if (((*mp)->m_flags & (M_EXT|M_NOFREE)) == M_EXT) {
351 (*mp)->m_flags &= ~M_EXT;
352 cxgb_mbufs_outstanding--;
362 mb_free_ext_fast(struct mbuf_iovec *mi, int type, int idx)
367 if (type == EXT_PACKET) {
368 cxgb_pack_outstanding--;
373 /* Account for lazy ref count assign. */
374 dofree = (mi->mi_refcnt == NULL);
376 KASSERT(mi->mi_type != EXT_MBUF,
377 ("refcnt must be null for mbuf"));
378 if (*(mi->mi_refcnt) == 1 ||
379 atomic_fetchadd_int(mi->mi_refcnt, -1) == 1)
388 KASSERT((mi->mi_flags & M_NOFREE) == 0, ("no free set on mbuf"));
389 cxgb_mbufs_outstanding--;
390 m_free_fast((struct mbuf *)cl);
393 cxgb_cache_put(zone_clust, cl);
396 cxgb_cache_put(zone_jumbop, cl);
399 cxgb_cache_put(zone_jumbo9, cl);
402 cxgb_cache_put(zone_jumbo16, cl);
408 *(mi->mi_refcnt) = 0;
409 uma_zfree(zone_ext_refcnt, __DEVOLATILE(u_int *,
410 mi->mi_ext.ref_cnt));
413 KASSERT(mi->mi_ext.ext_free != NULL,
414 ("%s: ext_free not set", __func__));
415 #if __FreeBSD_version >= 800016
416 (*(mi->mi_ext.ext_free))(mi->mi_ext.ext_arg1,
417 mi->mi_ext.ext_arg2);
419 (*(mi->mi_ext.ext_free))(mi->mi_ext.ext_buf,
420 mi->mi_ext.ext_args);
425 panic("unknown mv type in m_free_vec type=%d idx=%d", type, idx);
431 _m_explode(struct mbuf *m)
433 panic("IMPLEMENT ME!!!");