1 /* $NetBSD: ixgbe_netbsd.c,v 1.3 2015/02/04 09:05:53 msaitoh Exp $ */ 2 /* 3 * Copyright (c) 2011 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Coyote Point Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 #include <sys/param.h> 31 32 #include <sys/atomic.h> 33 #include <sys/bus.h> 34 #include <sys/condvar.h> 35 #include <sys/cpu.h> 36 #include <sys/kmem.h> 37 #include <sys/mbuf.h> 38 #include <sys/mutex.h> 39 #include <sys/queue.h> 40 #include <sys/workqueue.h> 41 42 #include "ixgbe_netbsd.h" 43 44 void 45 ixgbe_dma_tag_destroy(ixgbe_dma_tag_t *dt) 46 { 47 kmem_free(dt, sizeof(*dt)); 48 } 49 50 int 51 ixgbe_dma_tag_create(bus_dma_tag_t dmat, bus_size_t alignment, 52 bus_size_t boundary, bus_size_t maxsize, int nsegments, 53 bus_size_t maxsegsize, int flags, ixgbe_dma_tag_t **dtp) 54 { 55 ixgbe_dma_tag_t *dt; 56 57 *dtp = NULL; 58 59 if ((dt = kmem_zalloc(sizeof(*dt), KM_SLEEP)) == NULL) 60 return ENOMEM; 61 62 dt->dt_dmat = dmat; 63 dt->dt_alignment = alignment; 64 dt->dt_boundary = boundary; 65 dt->dt_maxsize = maxsize; 66 dt->dt_nsegments = nsegments; 67 dt->dt_maxsegsize = maxsegsize; 68 dt->dt_flags = flags; 69 *dtp = dt; 70 71 return 0; 72 } 73 74 void 75 ixgbe_dmamap_destroy(ixgbe_dma_tag_t *dt, bus_dmamap_t dmam) 76 { 77 bus_dmamap_destroy(dt->dt_dmat, dmam); 78 } 79 80 void 81 ixgbe_dmamap_sync(ixgbe_dma_tag_t *dt, bus_dmamap_t dmam, int ops) 82 { 83 bus_dmamap_sync(dt->dt_dmat, dmam, 0, dt->dt_maxsize, ops); 84 } 85 86 void 87 ixgbe_dmamap_unload(ixgbe_dma_tag_t *dt, bus_dmamap_t dmam) 88 { 89 bus_dmamap_unload(dt->dt_dmat, dmam); 90 } 91 92 int 93 ixgbe_dmamap_create(ixgbe_dma_tag_t *dt, int flags, bus_dmamap_t *dmamp) 94 { 95 return bus_dmamap_create(dt->dt_dmat, dt->dt_maxsize, dt->dt_nsegments, 96 dt->dt_maxsegsize, dt->dt_boundary, flags, dmamp); 97 } 98 99 static void 100 ixgbe_putext(ixgbe_extmem_t *em) 101 { 102 ixgbe_extmem_head_t *eh = em->em_head; 103 104 mutex_enter(&eh->eh_mtx); 105 106 TAILQ_INSERT_HEAD(&eh->eh_freelist, em, em_link); 107 108 mutex_exit(&eh->eh_mtx); 109 110 return; 111 } 112 113 static ixgbe_extmem_t * 114 ixgbe_getext(ixgbe_extmem_head_t *eh, size_t size) 115 { 116 ixgbe_extmem_t *em; 117 118 mutex_enter(&eh->eh_mtx); 119 120 TAILQ_FOREACH(em, &eh->eh_freelist, em_link) { 121 if (em->em_size >= size) 122 break; 123 } 124 125 if (em != NULL) 126 TAILQ_REMOVE(&eh->eh_freelist, em, em_link); 127 128 mutex_exit(&eh->eh_mtx); 129 130 return em; 131 } 132 133 static ixgbe_extmem_t * 134 ixgbe_newext(ixgbe_extmem_head_t *eh, bus_dma_tag_t dmat, size_t size) 135 { 136 ixgbe_extmem_t *em; 137 int nseg, rc; 138 139 em = kmem_zalloc(sizeof(*em), KM_SLEEP); 140 141 if (em == NULL) 142 return NULL; 143 144 rc = bus_dmamem_alloc(dmat, size, PAGE_SIZE, 0, &em->em_seg, 1, &nseg, 145 BUS_DMA_WAITOK); 146 147 if (rc != 0) 148 goto post_zalloc_err; 149 150 rc = bus_dmamem_map(dmat, &em->em_seg, 1, size, &em->em_vaddr, 151 BUS_DMA_WAITOK); 152 153 if (rc != 0) 154 goto post_dmamem_err; 155 156 em->em_dmat = dmat; 157 em->em_size = size; 158 em->em_head = eh; 159 160 return em; 161 post_dmamem_err: 162 bus_dmamem_free(dmat, &em->em_seg, 1); 163 post_zalloc_err: 164 kmem_free(em, sizeof(*em)); 165 return NULL; 166 } 167 168 void 169 ixgbe_jcl_reinit(ixgbe_extmem_head_t *eh, bus_dma_tag_t dmat, int nbuf, 170 size_t size) 171 { 172 int i; 173 ixgbe_extmem_t *em; 174 175 if (!eh->eh_initialized) { 176 TAILQ_INIT(&eh->eh_freelist); 177 mutex_init(&eh->eh_mtx, MUTEX_DEFAULT, IPL_NET); 178 eh->eh_initialized = true; 179 } 180 181 while ((em = ixgbe_getext(eh, 0)) != NULL) { 182 KASSERT(em->em_vaddr != NULL); 183 bus_dmamem_unmap(dmat, em->em_vaddr, em->em_size); 184 bus_dmamem_free(dmat, &em->em_seg, 1); 185 memset(em, 0, sizeof(*em)); 186 kmem_free(em, sizeof(*em)); 187 } 188 189 for (i = 0; i < nbuf; i++) { 190 if ((em = ixgbe_newext(eh, dmat, size)) == NULL) { 191 printf("%s: only %d of %d jumbo buffers allocated\n", 192 __func__, i, nbuf); 193 break; 194 } 195 ixgbe_putext(em); 196 } 197 } 198 199 static void 200 ixgbe_jcl_free(struct mbuf *m, void *buf, size_t size, void *arg) 201 { 202 ixgbe_extmem_t *em = arg; 203 204 KASSERT(em->em_size == size); 205 206 ixgbe_putext(em); 207 /* this is an abstraction violation, but it does not lead to a 208 * double-free 209 */ 210 if (__predict_true(m != NULL)) { 211 KASSERT(m->m_type != MT_FREE); 212 m->m_type = MT_FREE; 213 pool_cache_put(mb_cache, m); 214 } 215 } 216 217 /* XXX need to wait for the system to finish with each jumbo mbuf and 218 * free it before detaching the driver from the device. 219 */ 220 struct mbuf * 221 ixgbe_getjcl(ixgbe_extmem_head_t *eh, int nowait /* M_DONTWAIT */, 222 int type /* MT_DATA */, int flags /* M_PKTHDR */, size_t size) 223 { 224 ixgbe_extmem_t *em; 225 struct mbuf *m; 226 227 if ((flags & M_PKTHDR) != 0) 228 m = m_gethdr(nowait, type); 229 else 230 m = m_get(nowait, type); 231 232 if (m == NULL) 233 return NULL; 234 235 em = ixgbe_getext(eh, size); 236 if (em == NULL) { 237 m_freem(m); 238 return NULL; 239 } 240 241 MEXTADD(m, em->em_vaddr, em->em_size, M_DEVBUF, &ixgbe_jcl_free, em); 242 243 if ((m->m_flags & M_EXT) == 0) { 244 ixgbe_putext(em); 245 m_freem(m); 246 return NULL; 247 } 248 249 return m; 250 } 251