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