1139749Simp/*- 2116491Sharti * Copyright (c) 2001-2003 3116491Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4116491Sharti * All rights reserved. 5116491Sharti * 6116491Sharti * Redistribution and use in source and binary forms, with or without 7116491Sharti * modification, are permitted provided that the following conditions 8116491Sharti * are met: 9116491Sharti * 1. Redistributions of source code must retain the above copyright 10116491Sharti * notice, this list of conditions and the following disclaimer. 11116491Sharti * 2. Redistributions in binary form must reproduce the above copyright 12116491Sharti * notice, this list of conditions and the following disclaimer in the 13116491Sharti * documentation and/or other materials provided with the distribution. 14116491Sharti * 15116491Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16116491Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17116491Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18116491Sharti * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19116491Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20116491Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21116491Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22116491Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23116491Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24116491Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25116491Sharti * SUCH DAMAGE. 26116491Sharti * 27116491Sharti * Author: Hartmut Brandt <harti@freebsd.org> 28116491Sharti * 29116491Sharti * ForeHE driver. 30116491Sharti * 31116491Sharti * Transmission. 32116491Sharti */ 33116491Sharti 34116519Sharti#include <sys/cdefs.h> 35116519Sharti__FBSDID("$FreeBSD: releng/11.0/sys/dev/hatm/if_hatm_tx.c 298955 2016-05-03 03:41:25Z pfg $"); 36116519Sharti 37116491Sharti#include "opt_inet.h" 38116491Sharti#include "opt_natm.h" 39116491Sharti 40116491Sharti#include <sys/types.h> 41116491Sharti#include <sys/param.h> 42116491Sharti#include <sys/systm.h> 43116491Sharti#include <sys/kernel.h> 44116491Sharti#include <sys/malloc.h> 45116491Sharti#include <sys/bus.h> 46116491Sharti#include <sys/errno.h> 47116491Sharti#include <sys/conf.h> 48116491Sharti#include <sys/module.h> 49116491Sharti#include <sys/queue.h> 50116491Sharti#include <sys/syslog.h> 51116491Sharti#include <sys/condvar.h> 52116491Sharti#include <sys/sysctl.h> 53116491Sharti#include <vm/uma.h> 54116491Sharti 55116491Sharti#include <sys/sockio.h> 56116491Sharti#include <sys/mbuf.h> 57116491Sharti#include <sys/socket.h> 58116491Sharti 59116491Sharti#include <net/if.h> 60257176Sglebius#include <net/if_var.h> 61116491Sharti#include <net/if_media.h> 62116491Sharti#include <net/if_atm.h> 63116491Sharti#include <net/route.h> 64116491Sharti#ifdef ENABLE_BPF 65116491Sharti#include <net/bpf.h> 66116491Sharti#endif 67116491Sharti#include <netinet/in.h> 68116491Sharti#include <netinet/if_atm.h> 69116491Sharti 70116491Sharti#include <machine/bus.h> 71116491Sharti#include <machine/resource.h> 72116491Sharti#include <sys/bus.h> 73116491Sharti#include <sys/rman.h> 74119280Simp#include <dev/pci/pcireg.h> 75119280Simp#include <dev/pci/pcivar.h> 76116491Sharti 77116491Sharti#include <dev/utopia/utopia.h> 78116491Sharti#include <dev/hatm/if_hatmconf.h> 79116491Sharti#include <dev/hatm/if_hatmreg.h> 80116491Sharti#include <dev/hatm/if_hatmvar.h> 81116491Sharti 82122112Sharti 83116491Sharti/* 84122112Sharti * These macros are used to trace the flow of transmit mbufs and to 85122112Sharti * detect transmit mbuf leaks in the driver. 86122112Sharti */ 87122112Sharti#ifdef HATM_DEBUG 88122112Sharti#define hatm_free_txmbuf(SC) \ 89122112Sharti do { \ 90122112Sharti if (--sc->txmbuf < 0) \ 91122112Sharti DBG(sc, TX, ("txmbuf below 0!")); \ 92122112Sharti else if (sc->txmbuf == 0) \ 93122112Sharti DBG(sc, TX, ("txmbuf now 0")); \ 94122112Sharti } while (0) 95122112Sharti#define hatm_get_txmbuf(SC) \ 96122112Sharti do { \ 97122112Sharti if (++sc->txmbuf > 20000) \ 98146617Sharti DBG(sc, TX, ("txmbuf %u", sc->txmbuf)); \ 99122112Sharti else if (sc->txmbuf == 1) \ 100122112Sharti DBG(sc, TX, ("txmbuf leaves 0")); \ 101122112Sharti } while (0) 102122112Sharti#else 103122112Sharti#define hatm_free_txmbuf(SC) do { } while (0) 104122112Sharti#define hatm_get_txmbuf(SC) do { } while (0) 105122112Sharti#endif 106122112Sharti 107122112Sharti/* 108116491Sharti * Allocate a new TPD, zero the TPD part. Cannot return NULL if 109116491Sharti * flag is 0. The TPD is removed from the free list and its used 110116491Sharti * bit is set. 111116491Sharti */ 112116491Shartistatic struct tpd * 113116491Shartihatm_alloc_tpd(struct hatm_softc *sc, u_int flags) 114116491Sharti{ 115116491Sharti struct tpd *t; 116116491Sharti 117116491Sharti /* if we allocate a transmit TPD check for the reserve */ 118116491Sharti if (flags & M_NOWAIT) { 119116491Sharti if (sc->tpd_nfree <= HE_CONFIG_TPD_RESERVE) 120116491Sharti return (NULL); 121116491Sharti } else { 122116491Sharti if (sc->tpd_nfree == 0) 123116491Sharti return (NULL); 124116491Sharti } 125116491Sharti 126298955Spfg /* make it being used */ 127116491Sharti t = SLIST_FIRST(&sc->tpd_free); 128116491Sharti KASSERT(t != NULL, ("tpd botch")); 129116491Sharti SLIST_REMOVE_HEAD(&sc->tpd_free, link); 130116491Sharti TPD_SET_USED(sc, t->no); 131116491Sharti sc->tpd_nfree--; 132116491Sharti 133116491Sharti /* initialize */ 134116491Sharti t->mbuf = NULL; 135116491Sharti t->cid = 0; 136116491Sharti bzero(&t->tpd, sizeof(t->tpd)); 137116491Sharti t->tpd.addr = t->no << HE_REGS_TPD_ADDR; 138116491Sharti 139116491Sharti return (t); 140116491Sharti} 141116491Sharti 142116491Sharti/* 143116491Sharti * Free a TPD. If the mbuf pointer in that TPD is not zero, it is assumed, that 144116491Sharti * the DMA map of this TPD was used to load this mbuf. The map is unloaded 145116491Sharti * and the mbuf is freed. The TPD is put back onto the free list and 146116491Sharti * its used bit is cleared. 147116491Sharti */ 148116491Shartistatic void 149116491Shartihatm_free_tpd(struct hatm_softc *sc, struct tpd *tpd) 150116491Sharti{ 151116491Sharti if (tpd->mbuf != NULL) { 152116491Sharti bus_dmamap_unload(sc->tx_tag, tpd->map); 153122112Sharti hatm_free_txmbuf(sc); 154116491Sharti m_freem(tpd->mbuf); 155116491Sharti tpd->mbuf = NULL; 156116491Sharti } 157116491Sharti 158116491Sharti /* insert TPD into free list */ 159116491Sharti SLIST_INSERT_HEAD(&sc->tpd_free, tpd, link); 160116491Sharti TPD_CLR_USED(sc, tpd->no); 161116491Sharti sc->tpd_nfree++; 162116491Sharti} 163116491Sharti 164116491Sharti/* 165116491Sharti * Queue a number of TPD. If there is not enough space none of the TPDs 166116491Sharti * is queued and an error code is returned. 167116491Sharti */ 168116491Shartistatic int 169116491Shartihatm_queue_tpds(struct hatm_softc *sc, u_int count, struct tpd **list, 170116491Sharti u_int cid) 171116491Sharti{ 172116491Sharti u_int space; 173116491Sharti u_int i; 174116491Sharti 175116491Sharti if (count >= sc->tpdrq.size) { 176116491Sharti sc->istats.tdprq_full++; 177116491Sharti return (EBUSY); 178116491Sharti } 179116491Sharti 180116491Sharti if (sc->tpdrq.tail < sc->tpdrq.head) 181116491Sharti space = sc->tpdrq.head - sc->tpdrq.tail; 182116491Sharti else 183116491Sharti space = sc->tpdrq.head - sc->tpdrq.tail + sc->tpdrq.size; 184116491Sharti 185116491Sharti if (space <= count) { 186116491Sharti sc->tpdrq.head = 187116491Sharti (READ4(sc, HE_REGO_TPDRQ_H) >> HE_REGS_TPDRQ_H_H) & 188116491Sharti (sc->tpdrq.size - 1); 189116491Sharti 190116491Sharti if (sc->tpdrq.tail < sc->tpdrq.head) 191116491Sharti space = sc->tpdrq.head - sc->tpdrq.tail; 192116491Sharti else 193116491Sharti space = sc->tpdrq.head - sc->tpdrq.tail + 194116491Sharti sc->tpdrq.size; 195116491Sharti 196116491Sharti if (space <= count) { 197147256Sbrooks if_printf(sc->ifp, "TPDRQ full\n"); 198116491Sharti sc->istats.tdprq_full++; 199116491Sharti return (EBUSY); 200116491Sharti } 201116491Sharti } 202116491Sharti 203116491Sharti /* we are going to write to the TPD queue space */ 204116491Sharti bus_dmamap_sync(sc->tpdrq.mem.tag, sc->tpdrq.mem.map, 205116491Sharti BUS_DMASYNC_PREWRITE); 206116491Sharti 207116491Sharti /* put the entries into the TPD space */ 208116491Sharti for (i = 0; i < count; i++) { 209116491Sharti /* we are going to 'write' the TPD to the device */ 210116491Sharti bus_dmamap_sync(sc->tpds.tag, sc->tpds.map, 211116491Sharti BUS_DMASYNC_PREWRITE); 212116491Sharti 213116491Sharti sc->tpdrq.tpdrq[sc->tpdrq.tail].tpd = 214116491Sharti sc->tpds.paddr + HE_TPD_SIZE * list[i]->no; 215116491Sharti sc->tpdrq.tpdrq[sc->tpdrq.tail].cid = cid; 216116491Sharti 217116491Sharti if (++sc->tpdrq.tail == sc->tpdrq.size) 218116491Sharti sc->tpdrq.tail = 0; 219116491Sharti } 220116491Sharti 221116491Sharti /* update tail pointer */ 222116491Sharti WRITE4(sc, HE_REGO_TPDRQ_T, (sc->tpdrq.tail << HE_REGS_TPDRQ_T_T)); 223116491Sharti 224116491Sharti return (0); 225116491Sharti} 226116491Sharti 227116491Sharti/* 228116491Sharti * Helper struct for communication with the DMA load helper. 229116491Sharti */ 230116491Shartistruct load_txbuf_arg { 231116491Sharti struct hatm_softc *sc; 232116491Sharti struct tpd *first; 233116491Sharti struct mbuf *mbuf; 234116491Sharti struct hevcc *vcc; 235116491Sharti int error; 236116491Sharti u_int pti; 237116491Sharti u_int vpi, vci; 238116491Sharti}; 239116491Sharti 240116491Sharti/* 241116491Sharti * Loader callback for the mbuf. This function allocates the TPDs and 242116491Sharti * fills them. It puts the dmamap and and the mbuf pointer into the last 243116491Sharti * TPD and then tries to queue all the TPDs. If anything fails, all TPDs 244116491Sharti * allocated by this function are freed and the error flag is set in the 245116491Sharti * argument structure. The first TPD must then be freed by the caller. 246116491Sharti */ 247116491Shartistatic void 248116491Shartihatm_load_txbuf(void *uarg, bus_dma_segment_t *segs, int nseg, 249116491Sharti bus_size_t mapsize, int error) 250116491Sharti{ 251116491Sharti struct load_txbuf_arg *arg = uarg; 252116491Sharti u_int tpds_needed, i, n, tpd_cnt; 253116491Sharti int need_intr; 254116491Sharti struct tpd *tpd; 255116491Sharti struct tpd *tpd_list[HE_CONFIG_MAX_TPD_PER_PACKET]; 256116491Sharti 257116491Sharti if (error != 0) { 258116491Sharti DBG(arg->sc, DMA, ("%s -- error=%d plen=%d\n", 259116491Sharti __func__, error, arg->mbuf->m_pkthdr.len)); 260116491Sharti return; 261116491Sharti } 262116491Sharti 263116491Sharti /* ensure, we have enough TPDs (remember, we already have one) */ 264116491Sharti tpds_needed = (nseg + 2) / 3; 265116491Sharti if (HE_CONFIG_TPD_RESERVE + tpds_needed - 1 > arg->sc->tpd_nfree) { 266147256Sbrooks if_printf(arg->sc->ifp, "%s -- out of TPDs (need %d, " 267116491Sharti "have %u)\n", __func__, tpds_needed - 1, 268116491Sharti arg->sc->tpd_nfree + 1); 269116491Sharti arg->error = 1; 270116491Sharti return; 271116491Sharti } 272116491Sharti 273116491Sharti /* 274116491Sharti * Check for the maximum number of TPDs on the connection. 275116491Sharti */ 276116491Sharti need_intr = 0; 277116491Sharti if (arg->sc->max_tpd > 0) { 278116491Sharti if (arg->vcc->ntpds + tpds_needed > arg->sc->max_tpd) { 279116491Sharti arg->sc->istats.flow_closed++; 280116491Sharti arg->vcc->vflags |= HE_VCC_FLOW_CTRL; 281147256Sbrooks ATMEV_SEND_FLOW_CONTROL(IFP2IFATM(arg->sc->ifp), 282118170Sharti arg->vpi, arg->vci, 1); 283116491Sharti arg->error = 1; 284116491Sharti return; 285116491Sharti } 286116491Sharti if (arg->vcc->ntpds + tpds_needed > 287116491Sharti (9 * arg->sc->max_tpd) / 10) 288116491Sharti need_intr = 1; 289116491Sharti } 290116491Sharti 291116491Sharti tpd = arg->first; 292116491Sharti tpd_cnt = 0; 293116491Sharti tpd_list[tpd_cnt++] = tpd; 294116491Sharti for (i = n = 0; i < nseg; i++, n++) { 295116491Sharti if (n == 3) { 296116491Sharti if ((tpd = hatm_alloc_tpd(arg->sc, M_NOWAIT)) == NULL) 297116491Sharti /* may not fail (see check above) */ 298116491Sharti panic("%s: out of TPDs", __func__); 299116491Sharti tpd->cid = arg->first->cid; 300116491Sharti tpd->tpd.addr |= arg->pti; 301116491Sharti tpd_list[tpd_cnt++] = tpd; 302116491Sharti n = 0; 303116491Sharti } 304116491Sharti KASSERT(segs[i].ds_addr <= 0xffffffffLU, 305116491Sharti ("phys addr too large %lx", (u_long)segs[i].ds_addr)); 306116491Sharti 307116491Sharti DBG(arg->sc, DMA, ("DMA loaded: %lx/%lu", 308116491Sharti (u_long)segs[i].ds_addr, (u_long)segs[i].ds_len)); 309116491Sharti 310116491Sharti tpd->tpd.bufs[n].addr = segs[i].ds_addr; 311116491Sharti tpd->tpd.bufs[n].len = segs[i].ds_len; 312116491Sharti 313116491Sharti DBG(arg->sc, TX, ("seg[%u]=tpd[%u,%u]=%x/%u", i, 314116491Sharti tpd_cnt, n, tpd->tpd.bufs[n].addr, tpd->tpd.bufs[n].len)); 315116491Sharti 316116491Sharti if (i == nseg - 1) 317116491Sharti tpd->tpd.bufs[n].len |= HE_REGM_TPD_LST; 318116491Sharti } 319116491Sharti 320116491Sharti /* 321116491Sharti * Swap the MAP in the first and the last TPD and set the mbuf 322116491Sharti * pointer into the last TPD. We use the map in the last TPD, because 323116491Sharti * the map must stay valid until the last TPD is processed by the card. 324116491Sharti */ 325116491Sharti if (tpd_cnt > 1) { 326116491Sharti bus_dmamap_t tmp; 327116491Sharti 328116491Sharti tmp = arg->first->map; 329116491Sharti arg->first->map = tpd_list[tpd_cnt - 1]->map; 330116491Sharti tpd_list[tpd_cnt - 1]->map = tmp; 331116491Sharti } 332116491Sharti tpd_list[tpd_cnt - 1]->mbuf = arg->mbuf; 333116491Sharti 334116491Sharti if (need_intr) 335116491Sharti tpd_list[tpd_cnt - 1]->tpd.addr |= HE_REGM_TPD_INTR; 336116491Sharti 337116491Sharti /* queue the TPDs */ 338116491Sharti if (hatm_queue_tpds(arg->sc, tpd_cnt, tpd_list, arg->first->cid)) { 339116491Sharti /* free all, except the first TPD */ 340116491Sharti for (i = 1; i < tpd_cnt; i++) 341116491Sharti hatm_free_tpd(arg->sc, tpd_list[i]); 342116491Sharti arg->error = 1; 343116491Sharti return; 344116491Sharti } 345116491Sharti arg->vcc->ntpds += tpd_cnt; 346116491Sharti} 347116491Sharti 348116491Sharti 349116491Sharti/* 350116491Sharti * Start output on the interface 351116491Sharti */ 352116491Shartivoid 353116491Shartihatm_start(struct ifnet *ifp) 354116491Sharti{ 355147721Sharti struct hatm_softc *sc = ifp->if_softc; 356116491Sharti struct mbuf *m; 357116491Sharti struct atm_pseudohdr *aph; 358116491Sharti u_int cid; 359116491Sharti struct tpd *tpd; 360116491Sharti struct load_txbuf_arg arg; 361116491Sharti u_int len; 362116491Sharti int error; 363116491Sharti 364148887Srwatson if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 365116491Sharti return; 366116491Sharti mtx_lock(&sc->mtx); 367116491Sharti arg.sc = sc; 368116491Sharti 369116491Sharti while (1) { 370116491Sharti IF_DEQUEUE(&ifp->if_snd, m); 371116491Sharti if (m == NULL) 372116491Sharti break; 373116491Sharti 374122112Sharti hatm_get_txmbuf(sc); 375122112Sharti 376116491Sharti if (m->m_len < sizeof(*aph)) 377122112Sharti if ((m = m_pullup(m, sizeof(*aph))) == NULL) { 378122112Sharti hatm_free_txmbuf(sc); 379116491Sharti continue; 380122112Sharti } 381116491Sharti 382116491Sharti aph = mtod(m, struct atm_pseudohdr *); 383116491Sharti arg.vci = ATM_PH_VCI(aph); 384116491Sharti arg.vpi = ATM_PH_VPI(aph); 385116491Sharti m_adj(m, sizeof(*aph)); 386116491Sharti 387116491Sharti if ((len = m->m_pkthdr.len) == 0) { 388122112Sharti hatm_free_txmbuf(sc); 389116491Sharti m_freem(m); 390116491Sharti continue; 391116491Sharti } 392116491Sharti 393116491Sharti if ((arg.vpi & ~HE_VPI_MASK) || (arg.vci & ~HE_VCI_MASK) || 394116491Sharti (arg.vci == 0)) { 395122112Sharti hatm_free_txmbuf(sc); 396116491Sharti m_freem(m); 397116491Sharti continue; 398116491Sharti } 399116491Sharti cid = HE_CID(arg.vpi, arg.vci); 400116491Sharti arg.vcc = sc->vccs[cid]; 401116491Sharti 402116491Sharti if (arg.vcc == NULL || !(arg.vcc->vflags & HE_VCC_OPEN)) { 403122112Sharti hatm_free_txmbuf(sc); 404116491Sharti m_freem(m); 405116491Sharti continue; 406116491Sharti } 407116491Sharti if (arg.vcc->vflags & HE_VCC_FLOW_CTRL) { 408122112Sharti hatm_free_txmbuf(sc); 409116491Sharti m_freem(m); 410116491Sharti sc->istats.flow_drop++; 411116491Sharti continue; 412116491Sharti } 413116491Sharti 414116491Sharti arg.pti = 0; 415116491Sharti if (arg.vcc->param.aal == ATMIO_AAL_RAW) { 416116491Sharti if (len < 52) { 417121687Sharti /* too short */ 418122112Sharti hatm_free_txmbuf(sc); 419116491Sharti m_freem(m); 420116491Sharti continue; 421116491Sharti } 422121687Sharti 423121687Sharti /* 424121687Sharti * Get the header and ignore except 425121687Sharti * payload type and CLP. 426121687Sharti */ 427122112Sharti if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL) { 428122112Sharti hatm_free_txmbuf(sc); 429116491Sharti continue; 430122112Sharti } 431116491Sharti arg.pti = mtod(m, u_char *)[3] & 0xf; 432116491Sharti arg.pti = ((arg.pti & 0xe) << 2) | ((arg.pti & 1) << 1); 433116491Sharti m_adj(m, 4); 434116491Sharti len -= 4; 435121687Sharti 436121687Sharti if (len % 48 != 0) { 437121687Sharti m_adj(m, -((int)(len % 48))); 438121687Sharti len -= len % 48; 439121687Sharti } 440116491Sharti } 441116491Sharti 442116491Sharti#ifdef ENABLE_BPF 443116491Sharti if (!(arg.vcc->param.flags & ATMIO_FLAG_NG) && 444118540Sharti (arg.vcc->param.aal == ATMIO_AAL_5) && 445116491Sharti (arg.vcc->param.flags & ATM_PH_LLCSNAP)) 446116491Sharti BPF_MTAP(ifp, m); 447116491Sharti#endif 448116491Sharti 449116491Sharti /* Now load a DMA map with the packet. Allocate the first 450116491Sharti * TPD to get a map. Additional TPDs may be allocated by the 451116491Sharti * callback. */ 452116491Sharti if ((tpd = hatm_alloc_tpd(sc, M_NOWAIT)) == NULL) { 453122112Sharti hatm_free_txmbuf(sc); 454116491Sharti m_freem(m); 455271849Sglebius if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1); 456116491Sharti continue; 457116491Sharti } 458116491Sharti tpd->cid = cid; 459116491Sharti tpd->tpd.addr |= arg.pti; 460116491Sharti arg.first = tpd; 461116491Sharti arg.error = 0; 462116491Sharti arg.mbuf = m; 463116491Sharti 464116491Sharti error = bus_dmamap_load_mbuf(sc->tx_tag, tpd->map, m, 465117382Sharti hatm_load_txbuf, &arg, BUS_DMA_NOWAIT); 466116491Sharti 467116491Sharti if (error == EFBIG) { 468116491Sharti /* try to defragment the packet */ 469116491Sharti sc->istats.defrag++; 470243857Sglebius m = m_defrag(m, M_NOWAIT); 471116491Sharti if (m == NULL) { 472122112Sharti tpd->mbuf = NULL; 473122112Sharti hatm_free_txmbuf(sc); 474122112Sharti hatm_free_tpd(sc, tpd); 475271849Sglebius if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1); 476116491Sharti continue; 477116491Sharti } 478116491Sharti arg.mbuf = m; 479116491Sharti error = bus_dmamap_load_mbuf(sc->tx_tag, tpd->map, m, 480117382Sharti hatm_load_txbuf, &arg, BUS_DMA_NOWAIT); 481116491Sharti } 482116491Sharti 483116491Sharti if (error != 0) { 484147256Sbrooks if_printf(sc->ifp, "mbuf loaded error=%d\n", 485116491Sharti error); 486116491Sharti hatm_free_tpd(sc, tpd); 487271849Sglebius if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1); 488116491Sharti continue; 489116491Sharti } 490116491Sharti if (arg.error) { 491116491Sharti hatm_free_tpd(sc, tpd); 492271849Sglebius if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1); 493116491Sharti continue; 494116491Sharti } 495116491Sharti arg.vcc->opackets++; 496116491Sharti arg.vcc->obytes += len; 497271849Sglebius if_inc_counter(sc->ifp, IFCOUNTER_OPACKETS, 1); 498116491Sharti } 499116491Sharti mtx_unlock(&sc->mtx); 500116491Sharti} 501116491Sharti 502116491Shartivoid 503116491Shartihatm_tx_complete(struct hatm_softc *sc, struct tpd *tpd, uint32_t flags) 504116491Sharti{ 505116491Sharti struct hevcc *vcc = sc->vccs[tpd->cid]; 506116491Sharti 507116491Sharti DBG(sc, TX, ("tx_complete cid=%#x flags=%#x", tpd->cid, flags)); 508116491Sharti 509116491Sharti if (vcc == NULL) 510116491Sharti return; 511116491Sharti if ((flags & HE_REGM_TBRQ_EOS) && (vcc->vflags & HE_VCC_TX_CLOSING)) { 512116491Sharti vcc->vflags &= ~HE_VCC_TX_CLOSING; 513118540Sharti if (vcc->param.flags & ATMIO_FLAG_ASYNC) { 514116491Sharti hatm_tx_vcc_closed(sc, tpd->cid); 515116491Sharti if (!(vcc->vflags & HE_VCC_OPEN)) { 516116491Sharti hatm_vcc_closed(sc, tpd->cid); 517116491Sharti vcc = NULL; 518116491Sharti } 519116491Sharti } else 520116491Sharti cv_signal(&sc->vcc_cv); 521116491Sharti } 522116491Sharti hatm_free_tpd(sc, tpd); 523116491Sharti 524116491Sharti if (vcc == NULL) 525116491Sharti return; 526116491Sharti 527116491Sharti vcc->ntpds--; 528116491Sharti 529116491Sharti if ((vcc->vflags & HE_VCC_FLOW_CTRL) && 530116491Sharti vcc->ntpds <= HE_CONFIG_TPD_FLOW_ENB) { 531116491Sharti vcc->vflags &= ~HE_VCC_FLOW_CTRL; 532147256Sbrooks ATMEV_SEND_FLOW_CONTROL(IFP2IFATM(sc->ifp), 533118170Sharti HE_VPI(tpd->cid), HE_VCI(tpd->cid), 0); 534116491Sharti } 535116491Sharti} 536116491Sharti 537116491Sharti/* 538116491Sharti * Convert CPS to Rate for a rate group 539116491Sharti */ 540116491Shartistatic u_int 541116491Sharticps_to_rate(struct hatm_softc *sc, uint32_t cps) 542116491Sharti{ 543116491Sharti u_int clk = sc->he622 ? HE_622_CLOCK : HE_155_CLOCK; 544116491Sharti u_int period, rate; 545116491Sharti 546116491Sharti /* how many double ticks between two cells */ 547116491Sharti period = (clk + 2 * cps - 1) / (2 * cps); 548116491Sharti rate = hatm_cps2atmf(period); 549116491Sharti if (hatm_atmf2cps(rate) < period) 550116491Sharti rate++; 551116491Sharti 552116491Sharti return (rate); 553116491Sharti} 554116491Sharti 555116491Sharti/* 556116491Sharti * Check whether the VCC is really closed on the hardware and available for 557116491Sharti * open. Check that we have enough resources. If this function returns ok, 558116491Sharti * a later actual open must succeed. Assume, that we are locked between this 559116491Sharti * function and the next one, so that nothing does change. For CBR this 560116491Sharti * assigns the rate group and set the rate group's parameter. 561116491Sharti */ 562116491Shartiint 563116491Shartihatm_tx_vcc_can_open(struct hatm_softc *sc, u_int cid, struct hevcc *vcc) 564116491Sharti{ 565116491Sharti uint32_t v, line_rate; 566116491Sharti u_int rc, idx, free_idx; 567116491Sharti struct atmio_tparam *t = &vcc->param.tparam; 568116491Sharti 569116491Sharti /* verify that connection is closed */ 570116491Sharti#if 0 571116491Sharti v = READ_TSR(sc, cid, 4); 572116491Sharti if(!(v & HE_REGM_TSR4_SESS_END)) { 573147256Sbrooks if_printf(sc->ifp, "cid=%#x not closed (TSR4)\n", cid); 574116491Sharti return (EBUSY); 575116491Sharti } 576116491Sharti#endif 577116491Sharti v = READ_TSR(sc, cid, 0); 578116491Sharti if((v & HE_REGM_TSR0_CONN_STATE) != 0) { 579147256Sbrooks if_printf(sc->ifp, "cid=%#x not closed (TSR0=%#x)\n", 580116491Sharti cid, v); 581116491Sharti return (EBUSY); 582116491Sharti } 583116491Sharti 584116491Sharti /* check traffic parameters */ 585116491Sharti line_rate = sc->he622 ? ATM_RATE_622M : ATM_RATE_155M; 586116491Sharti switch (vcc->param.traffic) { 587116491Sharti 588116491Sharti case ATMIO_TRAFFIC_UBR: 589116491Sharti if (t->pcr == 0 || t->pcr > line_rate) 590116491Sharti t->pcr = line_rate; 591116491Sharti if (t->mcr != 0 || t->icr != 0 || t->tbe != 0 || t->nrm != 0 || 592116491Sharti t->trm != 0 || t->adtf != 0 || t->rif != 0 || t->rdf != 0 || 593116491Sharti t->cdf != 0) 594116491Sharti return (EINVAL); 595116491Sharti break; 596116491Sharti 597116491Sharti case ATMIO_TRAFFIC_CBR: 598116491Sharti /* 599116491Sharti * Compute rate group index 600116491Sharti */ 601116491Sharti if (t->pcr < 10) 602116491Sharti t->pcr = 10; 603116491Sharti if (sc->cbr_bw + t->pcr > line_rate) 604116491Sharti return (EINVAL); 605116491Sharti if (t->mcr != 0 || t->icr != 0 || t->tbe != 0 || t->nrm != 0 || 606116491Sharti t->trm != 0 || t->adtf != 0 || t->rif != 0 || t->rdf != 0 || 607116491Sharti t->cdf != 0) 608116491Sharti return (EINVAL); 609116491Sharti 610116491Sharti rc = cps_to_rate(sc, t->pcr); 611116491Sharti free_idx = HE_REGN_CS_STPER; 612116491Sharti for (idx = 0; idx < HE_REGN_CS_STPER; idx++) { 613116491Sharti if (sc->rate_ctrl[idx].refcnt == 0) { 614116491Sharti if (free_idx == HE_REGN_CS_STPER) 615116491Sharti free_idx = idx; 616116491Sharti } else { 617116491Sharti if (sc->rate_ctrl[idx].rate == rc) 618116491Sharti break; 619116491Sharti } 620116491Sharti } 621116491Sharti if (idx == HE_REGN_CS_STPER) { 622116491Sharti if ((idx = free_idx) == HE_REGN_CS_STPER) 623116491Sharti return (EBUSY); 624116491Sharti sc->rate_ctrl[idx].rate = rc; 625116491Sharti } 626116491Sharti vcc->rc = idx; 627118598Sharti 628118598Sharti /* commit */ 629118598Sharti sc->rate_ctrl[idx].refcnt++; 630118598Sharti sc->cbr_bw += t->pcr; 631116491Sharti break; 632116491Sharti 633116491Sharti case ATMIO_TRAFFIC_ABR: 634116491Sharti if (t->pcr > line_rate) 635116491Sharti t->pcr = line_rate; 636116491Sharti if (t->mcr > line_rate) 637116491Sharti t->mcr = line_rate; 638116491Sharti if (t->icr > line_rate) 639116491Sharti t->icr = line_rate; 640116491Sharti if (t->tbe == 0 || t->tbe >= 1 << 24 || t->nrm > 7 || 641116491Sharti t->trm > 7 || t->adtf >= 1 << 10 || t->rif > 15 || 642116491Sharti t->rdf > 15 || t->cdf > 7) 643116491Sharti return (EINVAL); 644116491Sharti break; 645116491Sharti 646116491Sharti default: 647116491Sharti return (EINVAL); 648116491Sharti } 649116491Sharti return (0); 650116491Sharti} 651116491Sharti 652116491Sharti#define NRM_CODE2VAL(CODE) (2 * (1 << (CODE))) 653116491Sharti 654116491Sharti/* 655116491Sharti * Actually open the transmit VCC 656116491Sharti */ 657116491Shartivoid 658116491Shartihatm_tx_vcc_open(struct hatm_softc *sc, u_int cid) 659116491Sharti{ 660116491Sharti struct hevcc *vcc = sc->vccs[cid]; 661116491Sharti uint32_t tsr0, tsr4, atmf, crm; 662116491Sharti const struct atmio_tparam *t = &vcc->param.tparam; 663116491Sharti 664116491Sharti if (vcc->param.aal == ATMIO_AAL_5) { 665116491Sharti tsr0 = HE_REGM_TSR0_AAL_5 << HE_REGS_TSR0_AAL; 666116491Sharti tsr4 = HE_REGM_TSR4_AAL_5 << HE_REGS_TSR4_AAL; 667116491Sharti } else { 668116491Sharti tsr0 = HE_REGM_TSR0_AAL_0 << HE_REGS_TSR0_AAL; 669116491Sharti tsr4 = HE_REGM_TSR4_AAL_0 << HE_REGS_TSR4_AAL; 670116491Sharti } 671116491Sharti tsr4 |= 1; 672116491Sharti 673116491Sharti switch (vcc->param.traffic) { 674116491Sharti 675116491Sharti case ATMIO_TRAFFIC_UBR: 676116491Sharti atmf = hatm_cps2atmf(t->pcr); 677116491Sharti 678116491Sharti tsr0 |= HE_REGM_TSR0_TRAFFIC_UBR << HE_REGS_TSR0_TRAFFIC; 679116491Sharti tsr0 |= HE_REGM_TSR0_USE_WMIN | HE_REGM_TSR0_UPDATE_GER; 680116491Sharti 681116491Sharti WRITE_TSR(sc, cid, 0, 0xf, tsr0); 682116491Sharti WRITE_TSR(sc, cid, 4, 0xf, tsr4); 683116491Sharti WRITE_TSR(sc, cid, 1, 0xf, (atmf << HE_REGS_TSR1_PCR)); 684116491Sharti WRITE_TSR(sc, cid, 2, 0xf, (atmf << HE_REGS_TSR2_ACR)); 685116491Sharti WRITE_TSR(sc, cid, 9, 0xf, HE_REGM_TSR9_INIT); 686116491Sharti WRITE_TSR(sc, cid, 3, 0xf, 0); 687116491Sharti WRITE_TSR(sc, cid, 5, 0xf, 0); 688116491Sharti WRITE_TSR(sc, cid, 6, 0xf, 0); 689116491Sharti WRITE_TSR(sc, cid, 7, 0xf, 0); 690116491Sharti WRITE_TSR(sc, cid, 8, 0xf, 0); 691116491Sharti WRITE_TSR(sc, cid, 10, 0xf, 0); 692116491Sharti WRITE_TSR(sc, cid, 11, 0xf, 0); 693116491Sharti WRITE_TSR(sc, cid, 12, 0xf, 0); 694116491Sharti WRITE_TSR(sc, cid, 13, 0xf, 0); 695116491Sharti WRITE_TSR(sc, cid, 14, 0xf, 0); 696116491Sharti break; 697116491Sharti 698116491Sharti case ATMIO_TRAFFIC_CBR: 699116491Sharti atmf = hatm_cps2atmf(t->pcr); 700116491Sharti 701118598Sharti if (sc->rate_ctrl[vcc->rc].refcnt == 1) 702118598Sharti WRITE_MBOX4(sc, HE_REGO_CS_STPER(vcc->rc), 703118598Sharti sc->rate_ctrl[vcc->rc].rate); 704118598Sharti 705116491Sharti tsr0 |= HE_REGM_TSR0_TRAFFIC_CBR << HE_REGS_TSR0_TRAFFIC; 706116491Sharti tsr0 |= vcc->rc; 707116491Sharti 708116491Sharti WRITE_TSR(sc, cid, 1, 0xf, (atmf << HE_REGS_TSR1_PCR)); 709116491Sharti WRITE_TSR(sc, cid, 2, 0xf, (atmf << HE_REGS_TSR2_ACR)); 710116491Sharti WRITE_TSR(sc, cid, 3, 0xf, 0); 711116491Sharti WRITE_TSR(sc, cid, 5, 0xf, 0); 712116491Sharti WRITE_TSR(sc, cid, 6, 0xf, 0); 713116491Sharti WRITE_TSR(sc, cid, 7, 0xf, 0); 714116491Sharti WRITE_TSR(sc, cid, 8, 0xf, 0); 715116491Sharti WRITE_TSR(sc, cid, 10, 0xf, 0); 716116491Sharti WRITE_TSR(sc, cid, 11, 0xf, 0); 717116491Sharti WRITE_TSR(sc, cid, 12, 0xf, 0); 718116491Sharti WRITE_TSR(sc, cid, 13, 0xf, 0); 719116491Sharti WRITE_TSR(sc, cid, 14, 0xf, 0); 720116491Sharti WRITE_TSR(sc, cid, 4, 0xf, tsr4); 721116491Sharti WRITE_TSR(sc, cid, 9, 0xf, HE_REGM_TSR9_INIT); 722116491Sharti WRITE_TSR(sc, cid, 0, 0xf, tsr0); 723116491Sharti 724116491Sharti break; 725116491Sharti 726116491Sharti case ATMIO_TRAFFIC_ABR: 727116491Sharti if ((crm = t->tbe / NRM_CODE2VAL(t->nrm)) > 0xffff) 728116491Sharti crm = 0xffff; 729116491Sharti 730116491Sharti tsr0 |= HE_REGM_TSR0_TRAFFIC_ABR << HE_REGS_TSR0_TRAFFIC; 731116491Sharti tsr0 |= HE_REGM_TSR0_USE_WMIN | HE_REGM_TSR0_UPDATE_GER; 732116491Sharti 733116491Sharti WRITE_TSR(sc, cid, 0, 0xf, tsr0); 734116491Sharti WRITE_TSR(sc, cid, 4, 0xf, tsr4); 735116491Sharti 736116491Sharti WRITE_TSR(sc, cid, 1, 0xf, 737116491Sharti ((hatm_cps2atmf(t->pcr) << HE_REGS_TSR1_PCR) | 738116491Sharti (hatm_cps2atmf(t->mcr) << HE_REGS_TSR1_MCR))); 739116491Sharti WRITE_TSR(sc, cid, 2, 0xf, 740116491Sharti (hatm_cps2atmf(t->icr) << HE_REGS_TSR2_ACR)); 741116491Sharti WRITE_TSR(sc, cid, 3, 0xf, 742116491Sharti ((NRM_CODE2VAL(t->nrm) - 1) << HE_REGS_TSR3_NRM) | 743116491Sharti (crm << HE_REGS_TSR3_CRM)); 744116491Sharti 745116491Sharti WRITE_TSR(sc, cid, 5, 0xf, 0); 746116491Sharti WRITE_TSR(sc, cid, 6, 0xf, 0); 747116491Sharti WRITE_TSR(sc, cid, 7, 0xf, 0); 748116491Sharti WRITE_TSR(sc, cid, 8, 0xf, 0); 749116491Sharti WRITE_TSR(sc, cid, 10, 0xf, 0); 750116491Sharti WRITE_TSR(sc, cid, 12, 0xf, 0); 751116491Sharti WRITE_TSR(sc, cid, 14, 0xf, 0); 752116491Sharti WRITE_TSR(sc, cid, 9, 0xf, HE_REGM_TSR9_INIT); 753116491Sharti 754116491Sharti WRITE_TSR(sc, cid, 11, 0xf, 755116491Sharti (hatm_cps2atmf(t->icr) << HE_REGS_TSR11_ICR) | 756116491Sharti (t->trm << HE_REGS_TSR11_TRM) | 757116491Sharti (t->nrm << HE_REGS_TSR11_NRM) | 758116491Sharti (t->adtf << HE_REGS_TSR11_ADTF)); 759116491Sharti 760116491Sharti WRITE_TSR(sc, cid, 13, 0xf, 761116491Sharti (t->rdf << HE_REGS_TSR13_RDF) | 762116491Sharti (t->rif << HE_REGS_TSR13_RIF) | 763116491Sharti (t->cdf << HE_REGS_TSR13_CDF) | 764116491Sharti (crm << HE_REGS_TSR13_CRM)); 765116491Sharti 766116491Sharti break; 767116491Sharti 768116491Sharti default: 769116491Sharti return; 770116491Sharti } 771116491Sharti 772116491Sharti vcc->vflags |= HE_VCC_TX_OPEN; 773116491Sharti} 774116491Sharti 775116491Sharti/* 776116491Sharti * Close the TX side of a VCC. Set the CLOSING flag. 777116491Sharti */ 778116491Shartivoid 779116491Shartihatm_tx_vcc_close(struct hatm_softc *sc, u_int cid) 780116491Sharti{ 781116491Sharti struct hevcc *vcc = sc->vccs[cid]; 782116491Sharti struct tpd *tpd_list[1]; 783116491Sharti u_int i, pcr = 0; 784116491Sharti 785116491Sharti WRITE_TSR(sc, cid, 4, 0x8, HE_REGM_TSR4_FLUSH); 786116491Sharti 787116491Sharti switch (vcc->param.traffic) { 788116491Sharti 789116491Sharti case ATMIO_TRAFFIC_CBR: 790116491Sharti WRITE_TSR(sc, cid, 14, 0x8, HE_REGM_TSR14_CBR_DELETE); 791116491Sharti break; 792116491Sharti 793116491Sharti case ATMIO_TRAFFIC_ABR: 794116491Sharti WRITE_TSR(sc, cid, 14, 0x4, HE_REGM_TSR14_ABR_CLOSE); 795116491Sharti pcr = vcc->param.tparam.pcr; 796116491Sharti /* FALL THROUGH */ 797116491Sharti 798116491Sharti case ATMIO_TRAFFIC_UBR: 799116491Sharti WRITE_TSR(sc, cid, 1, 0xf, 800116491Sharti hatm_cps2atmf(HE_CONFIG_FLUSH_RATE) << HE_REGS_TSR1_MCR | 801116491Sharti hatm_cps2atmf(pcr) << HE_REGS_TSR1_PCR); 802116491Sharti break; 803116491Sharti } 804116491Sharti 805116491Sharti tpd_list[0] = hatm_alloc_tpd(sc, 0); 806116491Sharti tpd_list[0]->tpd.addr |= HE_REGM_TPD_EOS | HE_REGM_TPD_INTR; 807116491Sharti tpd_list[0]->cid = cid; 808116491Sharti 809116491Sharti vcc->vflags |= HE_VCC_TX_CLOSING; 810116491Sharti vcc->vflags &= ~HE_VCC_TX_OPEN; 811116491Sharti 812116491Sharti i = 0; 813116491Sharti while (hatm_queue_tpds(sc, 1, tpd_list, cid) != 0) { 814116491Sharti if (++i == 1000) 815116491Sharti panic("TPDRQ permanently full"); 816116491Sharti DELAY(1000); 817116491Sharti } 818116491Sharti} 819116491Sharti 820116491Shartivoid 821116491Shartihatm_tx_vcc_closed(struct hatm_softc *sc, u_int cid) 822116491Sharti{ 823116491Sharti if (sc->vccs[cid]->param.traffic == ATMIO_TRAFFIC_CBR) { 824116491Sharti sc->cbr_bw -= sc->vccs[cid]->param.tparam.pcr; 825116491Sharti sc->rate_ctrl[sc->vccs[cid]->rc].refcnt--; 826116491Sharti } 827116491Sharti} 828