1/* $NetBSD$ */ 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 44void 45ixgbe_dma_tag_destroy(ixgbe_dma_tag_t *dt) 46{ 47 kmem_free(dt, sizeof(*dt)); 48} 49 50int 51ixgbe_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 74void 75ixgbe_dmamap_destroy(ixgbe_dma_tag_t *dt, bus_dmamap_t dmam) 76{ 77 bus_dmamap_destroy(dt->dt_dmat, dmam); 78} 79 80void 81ixgbe_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 86void 87ixgbe_dmamap_unload(ixgbe_dma_tag_t *dt, bus_dmamap_t dmam) 88{ 89 bus_dmamap_unload(dt->dt_dmat, dmam); 90} 91 92int 93ixgbe_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 99static void 100ixgbe_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 113static ixgbe_extmem_t * 114ixgbe_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 133static ixgbe_extmem_t * 134ixgbe_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; 161post_dmamem_err: 162 bus_dmamem_free(dmat, &em->em_seg, 1); 163post_zalloc_err: 164 kmem_free(em, sizeof(*em)); 165 return NULL; 166} 167 168void 169ixgbe_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 199static void 200ixgbe_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 */ 220struct mbuf * 221ixgbe_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