1/* $NetBSD$ */ 2 3/* 4 * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)if_uba.c 7.16 (Berkeley) 12/16/90 32 */ 33 34#include <sys/cdefs.h> 35__KERNEL_RCSID(0, "$NetBSD$"); 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/malloc.h> 40#include <sys/mbuf.h> 41#include <sys/socket.h> 42#include <sys/device.h> 43 44#include <net/if.h> 45 46#include <sys/bus.h> 47 48#include <dev/qbus/if_uba.h> 49#include <dev/qbus/ubareg.h> 50#include <dev/qbus/ubavar.h> 51 52static struct mbuf *getmcl(void); 53 54/* 55 * Routines supporting UNIBUS network interfaces. 56 * 57 * TODO: 58 * Support interfaces using only one BDP statically. 59 */ 60 61/* 62 * Init UNIBUS for interface whose headers of size hlen are to 63 * end on a page boundary. We allocate a UNIBUS map register for the page 64 * with the header, and nmr more UNIBUS map registers for i/o on the adapter, 65 * doing this once for each read and once for each write buffer. We also 66 * allocate page frames in the mbuffer pool for these pages. 67 * 68 * Recent changes: 69 * No special "header pages" anymore. 70 * Recv packets are always put in clusters. 71 * "size" is the maximum buffer size, may not be bigger than MCLBYTES. 72 */ 73int 74if_ubaminit(struct ifubinfo *ifu, struct uba_softc *uh, int size, 75 struct ifrw *ifr, int nr, struct ifxmt *ifw, int nw) 76{ 77 struct mbuf *m; 78 int totsz, i, error, rseg, nm = nr; 79 bus_dma_segment_t seg; 80 void *vaddr; 81 82#ifdef DIAGNOSTIC 83 if (size > MCLBYTES) 84 panic("if_ubaminit: size > MCLBYTES"); 85#endif 86 ifu->iff_softc = uh; 87 /* 88 * Get DMA memory for transmit buffers. 89 * Buffer size are rounded up to a multiple of the uba page size, 90 * then allocated contiguous. 91 */ 92 size = (size + UBA_PGOFSET) & ~UBA_PGOFSET; 93 totsz = size * nw; 94 if ((error = bus_dmamem_alloc(uh->uh_dmat, totsz, PAGE_SIZE, 0, 95 &seg, 1, &rseg, BUS_DMA_NOWAIT))) 96 return error; 97 if ((error = bus_dmamem_map(uh->uh_dmat, &seg, rseg, totsz, &vaddr, 98 BUS_DMA_NOWAIT|BUS_DMA_COHERENT))) { 99 bus_dmamem_free(uh->uh_dmat, &seg, rseg); 100 return error; 101 } 102 103 /* 104 * Create receive and transmit maps. 105 * Alloc all resources now so we won't fail in the future. 106 */ 107 108 for (i = 0; i < nr; i++) { 109 if ((error = bus_dmamap_create(uh->uh_dmat, size, 1, 110 size, 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, 111 &ifr[i].ifrw_map))) { 112 nr = i; 113 nm = nw = 0; 114 goto bad; 115 } 116 } 117 for (i = 0; i < nw; i++) { 118 if ((error = bus_dmamap_create(uh->uh_dmat, size, 1, 119 size, 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, 120 &ifw[i].ifw_map))) { 121 nw = i; 122 nm = 0; 123 goto bad; 124 } 125 } 126 /* 127 * Preload the rx maps with mbuf clusters. 128 */ 129 for (i = 0; i < nm; i++) { 130 if ((m = getmcl()) == NULL) { 131 nm = i; 132 goto bad; 133 } 134 ifr[i].ifrw_mbuf = m; 135 bus_dmamap_load(uh->uh_dmat, ifr[i].ifrw_map, 136 m->m_ext.ext_buf, m->m_ext.ext_size, NULL, BUS_DMA_NOWAIT); 137 138 } 139 /* 140 * Load the tx maps with DMA memory (common case). 141 */ 142 for (i = 0; i < nw; i++) { 143 ifw[i].ifw_vaddr = (char *)vaddr + size * i; 144 ifw[i].ifw_size = size; 145 bus_dmamap_load(uh->uh_dmat, ifw[i].ifw_map, 146 ifw[i].ifw_vaddr, ifw[i].ifw_size, NULL, BUS_DMA_NOWAIT); 147 } 148 return 0; 149bad: 150 while (--nm >= 0) { 151 bus_dmamap_unload(uh->uh_dmat, ifr[nw].ifrw_map); 152 m_freem(ifr[nm].ifrw_mbuf); 153 } 154 while (--nw >= 0) 155 bus_dmamap_destroy(uh->uh_dmat, ifw[nw].ifw_map); 156 while (--nr >= 0) 157 bus_dmamap_destroy(uh->uh_dmat, ifr[nw].ifrw_map); 158 return (0); 159} 160 161struct mbuf * 162getmcl(void) 163{ 164 struct mbuf *m; 165 166 MGETHDR(m, M_DONTWAIT, MT_DATA); 167 if (m == NULL) 168 return 0; 169 MCLGET(m, M_DONTWAIT); 170 if ((m->m_flags & M_EXT) == 0) { 171 m_freem(m); 172 return 0; 173 } 174 return m; 175} 176 177/* 178 * Pull read data off a interface. 179 * Totlen is length of data, with local net header stripped. 180 * When full cluster sized units are present 181 * on the interface on cluster boundaries we can get them more 182 * easily by remapping, and take advantage of this here. 183 * Save a pointer to the interface structure and the total length, 184 * so that protocols can determine where incoming packets arrived. 185 * Note: we may be called to receive from a transmit buffer by some 186 * devices. In that case, we must force normal mapping of the buffer, 187 * so that the correct data will appear (only unibus maps are 188 * changed when remapping the transmit buffers). 189 */ 190struct mbuf * 191if_ubaget(struct ifubinfo *ifu, struct ifrw *ifr, struct ifnet *ifp, int len) 192{ 193 struct uba_softc *uh = ifu->iff_softc; 194 struct mbuf *m, *mn; 195 196 if ((mn = getmcl()) == NULL) 197 return NULL; /* Leave the old */ 198 199 bus_dmamap_unload(uh->uh_dmat, ifr->ifrw_map); 200 m = ifr->ifrw_mbuf; 201 ifr->ifrw_mbuf = mn; 202 if ((bus_dmamap_load(uh->uh_dmat, ifr->ifrw_map, 203 mn->m_ext.ext_buf, mn->m_ext.ext_size, NULL, BUS_DMA_NOWAIT))) 204 panic("if_ubaget"); /* Cannot happen */ 205 m->m_pkthdr.rcvif = ifp; 206 m->m_len = m->m_pkthdr.len = len; 207 return m; 208} 209 210/* 211 * Called after a packet is sent. Releases hold resources. 212 */ 213void 214if_ubaend(struct ifubinfo *ifu, struct ifxmt *ifw) 215{ 216 struct uba_softc *uh = ifu->iff_softc; 217 218 if (ifw->ifw_flags & IFRW_MBUF) { 219 bus_dmamap_unload(uh->uh_dmat, ifw->ifw_map); 220 m_freem(ifw->ifw_mbuf); 221 ifw->ifw_mbuf = NULL; 222 } 223} 224 225/* 226 * Map a chain of mbufs onto a network interface 227 * in preparation for an i/o operation. 228 * The argument chain of mbufs includes the local network 229 * header which is copied to be in the mapped, aligned 230 * i/o space. 231 */ 232int 233if_ubaput(struct ifubinfo *ifu, struct ifxmt *ifw, struct mbuf *m) 234{ 235 struct uba_softc *uh = ifu->iff_softc; 236 int len; 237 238 if (/* m->m_next ==*/ 0) { 239 /* 240 * Map the outgoing packet directly. 241 */ 242 if ((ifw->ifw_flags & IFRW_MBUF) == 0) { 243 bus_dmamap_unload(uh->uh_dmat, ifw->ifw_map); 244 ifw->ifw_flags |= IFRW_MBUF; 245 } 246 bus_dmamap_load(uh->uh_dmat, ifw->ifw_map, mtod(m, void *), 247 m->m_len, NULL, BUS_DMA_NOWAIT); 248 ifw->ifw_mbuf = m; 249 len = m->m_len; 250 } else { 251 if (ifw->ifw_flags & IFRW_MBUF) { 252 bus_dmamap_load(uh->uh_dmat, ifw->ifw_map, 253 ifw->ifw_vaddr, ifw->ifw_size,NULL,BUS_DMA_NOWAIT); 254 ifw->ifw_flags &= ~IFRW_MBUF; 255 } 256 len = m->m_pkthdr.len; 257 m_copydata(m, 0, m->m_pkthdr.len, ifw->ifw_vaddr); 258 m_freem(m); 259 } 260 return len; 261} 262