1 /* $NetBSD: ixgbe_netbsd.c,v 1.5 2016/12/01 06:56:28 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 #include <dev/pci/pcivar.h> 42 43 #include "ixgbe_netbsd.h" 44 45 void 46 ixgbe_dma_tag_destroy(ixgbe_dma_tag_t *dt) 47 { 48 kmem_free(dt, sizeof(*dt)); 49 } 50 51 int 52 ixgbe_dma_tag_create(bus_dma_tag_t dmat, bus_size_t alignment, 53 bus_size_t boundary, bus_size_t maxsize, int nsegments, 54 bus_size_t maxsegsize, int flags, ixgbe_dma_tag_t **dtp) 55 { 56 ixgbe_dma_tag_t *dt; 57 58 *dtp = NULL; 59 60 if ((dt = kmem_zalloc(sizeof(*dt), KM_SLEEP)) == NULL) 61 return ENOMEM; 62 63 dt->dt_dmat = dmat; 64 dt->dt_alignment = alignment; 65 dt->dt_boundary = boundary; 66 dt->dt_maxsize = maxsize; 67 dt->dt_nsegments = nsegments; 68 dt->dt_maxsegsize = maxsegsize; 69 dt->dt_flags = flags; 70 *dtp = dt; 71 72 return 0; 73 } 74 75 void 76 ixgbe_dmamap_destroy(ixgbe_dma_tag_t *dt, bus_dmamap_t dmam) 77 { 78 bus_dmamap_destroy(dt->dt_dmat, dmam); 79 } 80 81 void 82 ixgbe_dmamap_sync(ixgbe_dma_tag_t *dt, bus_dmamap_t dmam, int ops) 83 { 84 bus_dmamap_sync(dt->dt_dmat, dmam, 0, dt->dt_maxsize, ops); 85 } 86 87 void 88 ixgbe_dmamap_unload(ixgbe_dma_tag_t *dt, bus_dmamap_t dmam) 89 { 90 bus_dmamap_unload(dt->dt_dmat, dmam); 91 } 92 93 int 94 ixgbe_dmamap_create(ixgbe_dma_tag_t *dt, int flags, bus_dmamap_t *dmamp) 95 { 96 return bus_dmamap_create(dt->dt_dmat, dt->dt_maxsize, dt->dt_nsegments, 97 dt->dt_maxsegsize, dt->dt_boundary, flags, dmamp); 98 } 99 100 static void 101 ixgbe_putext(ixgbe_extmem_t *em) 102 { 103 ixgbe_extmem_head_t *eh = em->em_head; 104 105 mutex_enter(&eh->eh_mtx); 106 107 TAILQ_INSERT_HEAD(&eh->eh_freelist, em, em_link); 108 109 mutex_exit(&eh->eh_mtx); 110 111 return; 112 } 113 114 static ixgbe_extmem_t * 115 ixgbe_getext(ixgbe_extmem_head_t *eh, size_t size) 116 { 117 ixgbe_extmem_t *em; 118 119 mutex_enter(&eh->eh_mtx); 120 121 TAILQ_FOREACH(em, &eh->eh_freelist, em_link) { 122 if (em->em_size >= size) 123 break; 124 } 125 126 if (em != NULL) 127 TAILQ_REMOVE(&eh->eh_freelist, em, em_link); 128 129 mutex_exit(&eh->eh_mtx); 130 131 return em; 132 } 133 134 static ixgbe_extmem_t * 135 ixgbe_newext(ixgbe_extmem_head_t *eh, bus_dma_tag_t dmat, size_t size) 136 { 137 ixgbe_extmem_t *em; 138 int nseg, rc; 139 140 em = kmem_zalloc(sizeof(*em), KM_SLEEP); 141 142 if (em == NULL) 143 return NULL; 144 145 rc = bus_dmamem_alloc(dmat, size, PAGE_SIZE, 0, &em->em_seg, 1, &nseg, 146 BUS_DMA_WAITOK); 147 148 if (rc != 0) 149 goto post_zalloc_err; 150 151 rc = bus_dmamem_map(dmat, &em->em_seg, 1, size, &em->em_vaddr, 152 BUS_DMA_WAITOK); 153 154 if (rc != 0) 155 goto post_dmamem_err; 156 157 em->em_dmat = dmat; 158 em->em_size = size; 159 em->em_head = eh; 160 161 return em; 162 post_dmamem_err: 163 bus_dmamem_free(dmat, &em->em_seg, 1); 164 post_zalloc_err: 165 kmem_free(em, sizeof(*em)); 166 return NULL; 167 } 168 169 void 170 ixgbe_jcl_reinit(ixgbe_extmem_head_t *eh, bus_dma_tag_t dmat, int nbuf, 171 size_t size) 172 { 173 int i; 174 ixgbe_extmem_t *em; 175 176 if (!eh->eh_initialized) { 177 TAILQ_INIT(&eh->eh_freelist); 178 mutex_init(&eh->eh_mtx, MUTEX_DEFAULT, IPL_NET); 179 eh->eh_initialized = true; 180 } 181 182 while ((em = ixgbe_getext(eh, 0)) != NULL) { 183 KASSERT(em->em_vaddr != NULL); 184 bus_dmamem_unmap(dmat, em->em_vaddr, em->em_size); 185 bus_dmamem_free(dmat, &em->em_seg, 1); 186 memset(em, 0, sizeof(*em)); 187 kmem_free(em, sizeof(*em)); 188 } 189 190 for (i = 0; i < nbuf; i++) { 191 if ((em = ixgbe_newext(eh, dmat, size)) == NULL) { 192 printf("%s: only %d of %d jumbo buffers allocated\n", 193 __func__, i, nbuf); 194 break; 195 } 196 ixgbe_putext(em); 197 } 198 } 199 200 static void 201 ixgbe_jcl_free(struct mbuf *m, void *buf, size_t size, void *arg) 202 { 203 ixgbe_extmem_t *em = arg; 204 205 KASSERT(em->em_size == size); 206 207 ixgbe_putext(em); 208 /* this is an abstraction violation, but it does not lead to a 209 * double-free 210 */ 211 if (__predict_true(m != NULL)) { 212 KASSERT(m->m_type != MT_FREE); 213 m->m_type = MT_FREE; 214 pool_cache_put(mb_cache, m); 215 } 216 } 217 218 /* XXX need to wait for the system to finish with each jumbo mbuf and 219 * free it before detaching the driver from the device. 220 */ 221 struct mbuf * 222 ixgbe_getjcl(ixgbe_extmem_head_t *eh, int nowait /* M_DONTWAIT */, 223 int type /* MT_DATA */, int flags /* M_PKTHDR */, size_t size) 224 { 225 ixgbe_extmem_t *em; 226 struct mbuf *m; 227 228 if ((flags & M_PKTHDR) != 0) 229 m = m_gethdr(nowait, type); 230 else 231 m = m_get(nowait, type); 232 233 if (m == NULL) 234 return NULL; 235 236 em = ixgbe_getext(eh, size); 237 if (em == NULL) { 238 m_freem(m); 239 return NULL; 240 } 241 242 MEXTADD(m, em->em_vaddr, em->em_size, M_DEVBUF, &ixgbe_jcl_free, em); 243 244 if ((m->m_flags & M_EXT) == 0) { 245 ixgbe_putext(em); 246 m_freem(m); 247 return NULL; 248 } 249 250 return m; 251 } 252 253 void 254 ixgbe_pci_enable_busmaster(pci_chipset_tag_t pc, pcitag_t tag) 255 { 256 pcireg_t pci_cmd_word; 257 258 pci_cmd_word = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); 259 if (!(pci_cmd_word & PCI_COMMAND_MASTER_ENABLE)) { 260 pci_cmd_word |= PCI_COMMAND_MASTER_ENABLE; 261 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, pci_cmd_word); 262 } 263 } 264