1 /* $NetBSD: ixgbe_netbsd.c,v 1.7 2018/04/25 08:46:19 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.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(struct adapter *adapter, bus_dma_tag_t dmat, int nbuf, 166 size_t size) 167 { 168 ixgbe_extmem_head_t *eh = &adapter->jcl_head; 169 ixgbe_extmem_t *em; 170 int i; 171 172 if (!eh->eh_initialized) { 173 TAILQ_INIT(&eh->eh_freelist); 174 mutex_init(&eh->eh_mtx, MUTEX_DEFAULT, IPL_NET); 175 eh->eh_initialized = true; 176 } 177 178 /* 179 * Check previous parameters. If it's not required to reinit, just 180 * return. 181 * 182 * Note that the num_rx_desc is currently fixed value. It's never 183 * changed after device is attached. 184 */ 185 if ((adapter->osdep.last_rx_mbuf_sz == adapter->rx_mbuf_sz) 186 && (adapter->osdep.last_num_rx_desc == adapter->num_rx_desc)) 187 return; 188 189 /* Free all dmamem */ 190 while ((em = ixgbe_getext(eh, 0)) != NULL) { 191 KASSERT(em->em_vaddr != NULL); 192 bus_dmamem_unmap(dmat, em->em_vaddr, em->em_size); 193 bus_dmamem_free(dmat, &em->em_seg, 1); 194 memset(em, 0, sizeof(*em)); 195 kmem_free(em, sizeof(*em)); 196 } 197 198 for (i = 0; i < nbuf; i++) { 199 if ((em = ixgbe_newext(eh, dmat, size)) == NULL) { 200 printf("%s: only %d of %d jumbo buffers allocated\n", 201 __func__, i, nbuf); 202 break; 203 } 204 ixgbe_putext(em); 205 } 206 207 /* Keep current parameters */ 208 adapter->osdep.last_rx_mbuf_sz = adapter->rx_mbuf_sz; 209 adapter->osdep.last_num_rx_desc = adapter->num_rx_desc; 210 } 211 212 static void 213 ixgbe_jcl_free(struct mbuf *m, void *buf, size_t size, void *arg) 214 { 215 ixgbe_extmem_t *em = arg; 216 217 KASSERT(em->em_size == size); 218 219 ixgbe_putext(em); 220 /* this is an abstraction violation, but it does not lead to a 221 * double-free 222 */ 223 if (__predict_true(m != NULL)) { 224 KASSERT(m->m_type != MT_FREE); 225 m->m_type = MT_FREE; 226 pool_cache_put(mb_cache, m); 227 } 228 } 229 230 /* XXX need to wait for the system to finish with each jumbo mbuf and 231 * free it before detaching the driver from the device. 232 */ 233 struct mbuf * 234 ixgbe_getjcl(ixgbe_extmem_head_t *eh, int nowait /* M_DONTWAIT */, 235 int type /* MT_DATA */, int flags /* M_PKTHDR */, size_t size) 236 { 237 ixgbe_extmem_t *em; 238 struct mbuf *m; 239 240 if ((flags & M_PKTHDR) != 0) 241 m = m_gethdr(nowait, type); 242 else 243 m = m_get(nowait, type); 244 245 if (m == NULL) 246 return NULL; 247 248 em = ixgbe_getext(eh, size); 249 if (em == NULL) { 250 m_freem(m); 251 return NULL; 252 } 253 254 MEXTADD(m, em->em_vaddr, em->em_size, M_DEVBUF, &ixgbe_jcl_free, em); 255 256 if ((m->m_flags & M_EXT) == 0) { 257 ixgbe_putext(em); 258 m_freem(m); 259 return NULL; 260 } 261 262 return m; 263 } 264 265 void 266 ixgbe_pci_enable_busmaster(pci_chipset_tag_t pc, pcitag_t tag) 267 { 268 pcireg_t pci_cmd_word; 269 270 pci_cmd_word = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); 271 if (!(pci_cmd_word & PCI_COMMAND_MASTER_ENABLE)) { 272 pci_cmd_word |= PCI_COMMAND_MASTER_ENABLE; 273 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, pci_cmd_word); 274 } 275 } 276