1139749Simp/*- 2116491Sharti * Copyright (c) 2001-2003 3116491Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4116491Sharti * All rights reserved. 5119418Sobrien * Author: Hartmut Brandt <harti@freebsd.org> 6116491Sharti * 7116491Sharti * Redistribution and use in source and binary forms, with or without 8116491Sharti * modification, are permitted provided that the following conditions 9116491Sharti * are met: 10116491Sharti * 1. Redistributions of source code must retain the above copyright 11116491Sharti * notice, this list of conditions and the following disclaimer. 12116491Sharti * 2. Redistributions in binary form must reproduce the above copyright 13116491Sharti * notice, this list of conditions and the following disclaimer in the 14116491Sharti * documentation and/or other materials provided with the distribution. 15116491Sharti * 16116491Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17116491Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18116491Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19116491Sharti * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20116491Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21116491Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22116491Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23116491Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24116491Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25116491Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26116491Sharti * SUCH DAMAGE. 27119418Sobrien */ 28119418Sobrien 29119418Sobrien#include <sys/cdefs.h> 30119418Sobrien__FBSDID("$FreeBSD$"); 31119418Sobrien 32119418Sobrien/* 33116491Sharti * ForeHE driver. 34116491Sharti * 35116491Sharti * Interrupt handler. 36116491Sharti */ 37116491Sharti 38116491Sharti#include "opt_inet.h" 39116491Sharti#include "opt_natm.h" 40116491Sharti 41116491Sharti#include <sys/types.h> 42116491Sharti#include <sys/param.h> 43116491Sharti#include <sys/systm.h> 44116491Sharti#include <sys/malloc.h> 45116491Sharti#include <sys/kernel.h> 46116491Sharti#include <sys/bus.h> 47116491Sharti#include <sys/errno.h> 48116491Sharti#include <sys/conf.h> 49116491Sharti#include <sys/module.h> 50116491Sharti#include <sys/queue.h> 51116491Sharti#include <sys/syslog.h> 52116491Sharti#include <sys/condvar.h> 53116491Sharti#include <sys/sysctl.h> 54116491Sharti#include <vm/uma.h> 55116491Sharti 56116491Sharti#include <sys/sockio.h> 57116491Sharti#include <sys/mbuf.h> 58116491Sharti#include <sys/socket.h> 59116491Sharti 60116491Sharti#include <net/if.h> 61257176Sglebius#include <net/if_var.h> 62116491Sharti#include <net/if_media.h> 63116491Sharti#include <net/if_atm.h> 64116491Sharti#include <net/route.h> 65116491Sharti#include <netinet/in.h> 66116491Sharti#include <netinet/if_atm.h> 67116491Sharti 68116491Sharti#include <machine/bus.h> 69116491Sharti#include <machine/resource.h> 70116491Sharti#include <sys/bus.h> 71116491Sharti#include <sys/rman.h> 72119280Simp#include <dev/pci/pcireg.h> 73119280Simp#include <dev/pci/pcivar.h> 74116491Sharti 75116491Sharti#include <dev/utopia/utopia.h> 76116491Sharti#include <dev/hatm/if_hatmconf.h> 77116491Sharti#include <dev/hatm/if_hatmreg.h> 78116491Sharti#include <dev/hatm/if_hatmvar.h> 79116491Sharti 80116491ShartiCTASSERT(sizeof(struct mbuf_page) == MBUF_ALLOC_SIZE); 81116491ShartiCTASSERT(sizeof(struct mbuf0_chunk) == MBUF0_CHUNK); 82116491ShartiCTASSERT(sizeof(struct mbuf1_chunk) == MBUF1_CHUNK); 83116491ShartiCTASSERT(sizeof(((struct mbuf0_chunk *)NULL)->storage) >= MBUF0_SIZE); 84116491ShartiCTASSERT(sizeof(((struct mbuf1_chunk *)NULL)->storage) >= MBUF1_SIZE); 85116491ShartiCTASSERT(sizeof(struct tpd) <= HE_TPD_SIZE); 86116491Sharti 87121729ShartiCTASSERT(MBUF0_PER_PAGE <= 256); 88121729ShartiCTASSERT(MBUF1_PER_PAGE <= 256); 89121729Sharti 90121675Shartistatic void hatm_mbuf_page_alloc(struct hatm_softc *sc, u_int group); 91121675Sharti 92116491Sharti/* 93121675Sharti * Free an external mbuf to a list. We use atomic functions so that 94121675Sharti * we don't need a mutex for the list. 95121744Sharti * 96121744Sharti * Note that in general this algorithm is not safe when multiple readers 97121744Sharti * and writers are present. To cite from a mail from David Schultz 98121744Sharti * <das@freebsd.org>: 99121744Sharti * 100121744Sharti * It looks like this is subject to the ABA problem. For instance, 101121744Sharti * suppose X, Y, and Z are the top things on the freelist and a 102121744Sharti * thread attempts to make an allocation. You set buf to X and load 103121744Sharti * buf->link (Y) into a register. Then the thread get preempted, and 104121744Sharti * another thread allocates both X and Y, then frees X. When the 105121744Sharti * original thread gets the CPU again, X is still on top of the 106121744Sharti * freelist, so the atomic operation succeeds. However, the atomic 107121744Sharti * op places Y on top of the freelist, even though Y is no longer 108121744Sharti * free. 109121744Sharti * 110121744Sharti * We are, however sure that we have only one thread that ever allocates 111121744Sharti * buffers because the only place we're call from is the interrupt handler. 112121744Sharti * Under these circumstances the code looks safe. 113121675Sharti */ 114170411Smjacobvoid 115121675Shartihatm_ext_free(struct mbufx_free **list, struct mbufx_free *buf) 116121675Sharti{ 117121675Sharti for (;;) { 118121675Sharti buf->link = *list; 119148067Sjhb if (atomic_cmpset_ptr((uintptr_t *)list, (uintptr_t)buf->link, 120148067Sjhb (uintptr_t)buf)) 121121675Sharti break; 122121675Sharti } 123121675Sharti} 124121675Sharti 125121675Shartistatic __inline struct mbufx_free * 126121675Shartihatm_ext_alloc(struct hatm_softc *sc, u_int g) 127121675Sharti{ 128121675Sharti struct mbufx_free *buf; 129121675Sharti 130121675Sharti for (;;) { 131121675Sharti if ((buf = sc->mbuf_list[g]) == NULL) 132121675Sharti break; 133148067Sjhb if (atomic_cmpset_ptr((uintptr_t *)&sc->mbuf_list[g], 134148067Sjhb (uintptr_t)buf, (uintptr_t)buf->link)) 135121675Sharti break; 136121675Sharti } 137121675Sharti if (buf == NULL) { 138121675Sharti hatm_mbuf_page_alloc(sc, g); 139121675Sharti for (;;) { 140121675Sharti if ((buf = sc->mbuf_list[g]) == NULL) 141121675Sharti break; 142148067Sjhb if (atomic_cmpset_ptr((uintptr_t *)&sc->mbuf_list[g], 143148067Sjhb (uintptr_t)buf, (uintptr_t)buf->link)) 144121675Sharti break; 145121675Sharti } 146121675Sharti } 147121675Sharti return (buf); 148121675Sharti} 149121675Sharti 150121675Sharti/* 151116491Sharti * Either the queue treshold was crossed or a TPD with the INTR bit set 152116491Sharti * was transmitted. 153116491Sharti */ 154116491Shartistatic void 155116491Shartihe_intr_tbrq(struct hatm_softc *sc, struct hetbrq *q, u_int group) 156116491Sharti{ 157116491Sharti uint32_t *tailp = &sc->hsp->group[group].tbrq_tail; 158116491Sharti u_int no; 159116491Sharti 160116491Sharti while (q->head != (*tailp >> 2)) { 161116491Sharti no = (q->tbrq[q->head].addr & HE_REGM_TBRQ_ADDR) >> 162116491Sharti HE_REGS_TPD_ADDR; 163116491Sharti hatm_tx_complete(sc, TPD_ADDR(sc, no), 164116491Sharti (q->tbrq[q->head].addr & HE_REGM_TBRQ_FLAGS)); 165116491Sharti 166116491Sharti if (++q->head == q->size) 167116491Sharti q->head = 0; 168116491Sharti } 169116491Sharti WRITE4(sc, HE_REGO_TBRQ_H(group), q->head << 2); 170116491Sharti} 171116491Sharti 172116491Sharti/* 173116491Sharti * DMA loader function for external mbuf page. 174116491Sharti */ 175116491Shartistatic void 176116491Shartihatm_extbuf_helper(void *arg, bus_dma_segment_t *segs, int nsegs, 177116491Sharti int error) 178116491Sharti{ 179116491Sharti if (error) { 180116491Sharti printf("%s: mapping error %d\n", __func__, error); 181116491Sharti return; 182116491Sharti } 183116491Sharti KASSERT(nsegs == 1, 184116491Sharti ("too many segments for DMA: %d", nsegs)); 185116491Sharti KASSERT(segs[0].ds_addr <= 0xffffffffLU, 186116491Sharti ("phys addr too large %lx", (u_long)segs[0].ds_addr)); 187116491Sharti 188116491Sharti *(uint32_t *)arg = segs[0].ds_addr; 189116491Sharti} 190116491Sharti 191116491Sharti/* 192116491Sharti * Allocate a page of external mbuf storage for the small pools. 193116491Sharti * Create a DMA map and load it. Put all the chunks onto the right 194116491Sharti * free list. 195116491Sharti */ 196116491Shartistatic void 197116491Shartihatm_mbuf_page_alloc(struct hatm_softc *sc, u_int group) 198116491Sharti{ 199116491Sharti struct mbuf_page *pg; 200116491Sharti int err; 201116491Sharti u_int i; 202116491Sharti 203121686Sharti if (sc->mbuf_npages == sc->mbuf_max_pages) 204116491Sharti return; 205116491Sharti if ((pg = malloc(MBUF_ALLOC_SIZE, M_DEVBUF, M_NOWAIT)) == NULL) 206116491Sharti return; 207116491Sharti 208116491Sharti err = bus_dmamap_create(sc->mbuf_tag, 0, &pg->hdr.map); 209116491Sharti if (err != 0) { 210147256Sbrooks if_printf(sc->ifp, "%s -- bus_dmamap_create: %d\n", 211116491Sharti __func__, err); 212116491Sharti free(pg, M_DEVBUF); 213116491Sharti return; 214116491Sharti } 215116491Sharti err = bus_dmamap_load(sc->mbuf_tag, pg->hdr.map, pg, MBUF_ALLOC_SIZE, 216117382Sharti hatm_extbuf_helper, &pg->hdr.phys, BUS_DMA_NOWAIT); 217116491Sharti if (err != 0) { 218147256Sbrooks if_printf(sc->ifp, "%s -- mbuf mapping failed %d\n", 219116491Sharti __func__, err); 220116491Sharti bus_dmamap_destroy(sc->mbuf_tag, pg->hdr.map); 221116491Sharti free(pg, M_DEVBUF); 222116491Sharti return; 223116491Sharti } 224116491Sharti 225116491Sharti sc->mbuf_pages[sc->mbuf_npages] = pg; 226116491Sharti 227116491Sharti if (group == 0) { 228116491Sharti struct mbuf0_chunk *c; 229116491Sharti 230121729Sharti pg->hdr.pool = 0; 231116491Sharti pg->hdr.nchunks = MBUF0_PER_PAGE; 232116491Sharti pg->hdr.chunksize = MBUF0_CHUNK; 233116491Sharti pg->hdr.hdroff = sizeof(c->storage); 234116491Sharti c = (struct mbuf0_chunk *)pg; 235116491Sharti for (i = 0; i < MBUF0_PER_PAGE; i++, c++) { 236116491Sharti c->hdr.pageno = sc->mbuf_npages; 237116491Sharti c->hdr.chunkno = i; 238122111Sharti c->hdr.flags = 0; 239121675Sharti hatm_ext_free(&sc->mbuf_list[0], 240121675Sharti (struct mbufx_free *)c); 241116491Sharti } 242116491Sharti } else { 243116491Sharti struct mbuf1_chunk *c; 244116491Sharti 245121729Sharti pg->hdr.pool = 1; 246116491Sharti pg->hdr.nchunks = MBUF1_PER_PAGE; 247116491Sharti pg->hdr.chunksize = MBUF1_CHUNK; 248116491Sharti pg->hdr.hdroff = sizeof(c->storage); 249116491Sharti c = (struct mbuf1_chunk *)pg; 250116491Sharti for (i = 0; i < MBUF1_PER_PAGE; i++, c++) { 251116491Sharti c->hdr.pageno = sc->mbuf_npages; 252116491Sharti c->hdr.chunkno = i; 253122111Sharti c->hdr.flags = 0; 254121675Sharti hatm_ext_free(&sc->mbuf_list[1], 255121675Sharti (struct mbufx_free *)c); 256116491Sharti } 257116491Sharti } 258116491Sharti sc->mbuf_npages++; 259116491Sharti} 260116491Sharti 261116491Sharti/* 262116491Sharti * Free an mbuf and put it onto the free list. 263116491Sharti */ 264268529Sglebiusstatic void 265254799Sandrehatm_mbuf0_free(struct mbuf *m, void *buf, void *args) 266116491Sharti{ 267116491Sharti struct hatm_softc *sc = args; 268116491Sharti struct mbuf0_chunk *c = buf; 269116491Sharti 270121729Sharti KASSERT((c->hdr.flags & (MBUF_USED | MBUF_CARD)) == MBUF_USED, 271121729Sharti ("freeing unused mbuf %x", c->hdr.flags)); 272121729Sharti c->hdr.flags &= ~MBUF_USED; 273121675Sharti hatm_ext_free(&sc->mbuf_list[0], (struct mbufx_free *)c); 274116491Sharti} 275268529Sglebiusstatic void 276254799Sandrehatm_mbuf1_free(struct mbuf *m, void *buf, void *args) 277116491Sharti{ 278116491Sharti struct hatm_softc *sc = args; 279116491Sharti struct mbuf1_chunk *c = buf; 280116491Sharti 281121729Sharti KASSERT((c->hdr.flags & (MBUF_USED | MBUF_CARD)) == MBUF_USED, 282121729Sharti ("freeing unused mbuf %x", c->hdr.flags)); 283121729Sharti c->hdr.flags &= ~MBUF_USED; 284121675Sharti hatm_ext_free(&sc->mbuf_list[1], (struct mbufx_free *)c); 285116491Sharti} 286116491Sharti 287116491Shartistatic void 288116491Shartihatm_mbuf_helper(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 289116491Sharti{ 290116491Sharti uint32_t *ptr = (uint32_t *)arg; 291116491Sharti 292116491Sharti if (nsegs == 0) { 293116491Sharti printf("%s: error=%d\n", __func__, error); 294116491Sharti return; 295116491Sharti } 296116491Sharti KASSERT(nsegs == 1, ("too many segments for mbuf: %d", nsegs)); 297116491Sharti KASSERT(segs[0].ds_addr <= 0xffffffffLU, 298116491Sharti ("phys addr too large %lx", (u_long)segs[0].ds_addr)); 299116491Sharti 300116491Sharti *ptr = segs[0].ds_addr; 301116491Sharti} 302116491Sharti 303116491Sharti/* 304116491Sharti * Receive buffer pool interrupt. This means the number of entries in the 305116491Sharti * queue has dropped below the threshold. Try to supply new buffers. 306116491Sharti */ 307116491Shartistatic void 308116491Shartihe_intr_rbp(struct hatm_softc *sc, struct herbp *rbp, u_int large, 309116491Sharti u_int group) 310116491Sharti{ 311121617Sharti u_int ntail; 312116491Sharti struct mbuf *m; 313116491Sharti int error; 314121680Sharti struct mbufx_free *cf; 315121680Sharti struct mbuf_page *pg; 316121680Sharti struct mbuf0_chunk *buf0; 317121680Sharti struct mbuf1_chunk *buf1; 318116491Sharti 319116491Sharti DBG(sc, INTR, ("%s buffer supply threshold crossed for group %u", 320116491Sharti large ? "large" : "small", group)); 321116491Sharti 322116491Sharti rbp->head = (READ4(sc, HE_REGO_RBP_S(large, group)) >> HE_REGS_RBP_HEAD) 323116491Sharti & (rbp->size - 1); 324116491Sharti 325116491Sharti for (;;) { 326116491Sharti if ((ntail = rbp->tail + 1) == rbp->size) 327116491Sharti ntail = 0; 328116491Sharti if (ntail == rbp->head) 329116491Sharti break; 330121680Sharti m = NULL; 331116491Sharti 332116491Sharti if (large) { 333121676Sharti /* allocate the MBUF */ 334243857Sglebius if ((m = m_getcl(M_NOWAIT, MT_DATA, 335116491Sharti M_PKTHDR)) == NULL) { 336147256Sbrooks if_printf(sc->ifp, 337116491Sharti "no mbuf clusters\n"); 338116491Sharti break; 339116491Sharti } 340116491Sharti m->m_data += MBUFL_OFFSET; 341116491Sharti 342116491Sharti if (sc->lbufs[sc->lbufs_next] != NULL) 343116491Sharti panic("hatm: lbufs full %u", sc->lbufs_next); 344116491Sharti sc->lbufs[sc->lbufs_next] = m; 345116491Sharti 346116491Sharti if ((error = bus_dmamap_load(sc->mbuf_tag, 347116491Sharti sc->rmaps[sc->lbufs_next], 348116491Sharti m->m_data, rbp->bsize, hatm_mbuf_helper, 349123810Salfred &rbp->rbp[rbp->tail].phys, BUS_DMA_NOWAIT)) != 0) 350116491Sharti panic("hatm: mbuf mapping failed %d", error); 351116491Sharti 352116491Sharti bus_dmamap_sync(sc->mbuf_tag, 353116491Sharti sc->rmaps[sc->lbufs_next], 354116491Sharti BUS_DMASYNC_PREREAD); 355116491Sharti 356121680Sharti rbp->rbp[rbp->tail].handle = 357121680Sharti MBUF_MAKE_LHANDLE(sc->lbufs_next); 358116491Sharti 359116491Sharti if (++sc->lbufs_next == sc->lbufs_size) 360116491Sharti sc->lbufs_next = 0; 361116491Sharti 362121680Sharti } else if (group == 0) { 363121680Sharti /* 364121680Sharti * Allocate small buffer in group 0 365121680Sharti */ 366121680Sharti if ((cf = hatm_ext_alloc(sc, 0)) == NULL) 367116491Sharti break; 368121680Sharti buf0 = (struct mbuf0_chunk *)cf; 369121680Sharti pg = sc->mbuf_pages[buf0->hdr.pageno]; 370121729Sharti buf0->hdr.flags |= MBUF_CARD; 371121680Sharti rbp->rbp[rbp->tail].phys = pg->hdr.phys + 372121680Sharti buf0->hdr.chunkno * MBUF0_CHUNK + MBUF0_OFFSET; 373121680Sharti rbp->rbp[rbp->tail].handle = 374121680Sharti MBUF_MAKE_HANDLE(buf0->hdr.pageno, 375121680Sharti buf0->hdr.chunkno); 376121680Sharti 377121680Sharti bus_dmamap_sync(sc->mbuf_tag, pg->hdr.map, 378121680Sharti BUS_DMASYNC_PREREAD); 379121680Sharti 380121680Sharti } else if (group == 1) { 381121680Sharti /* 382121680Sharti * Allocate small buffer in group 1 383121680Sharti */ 384121680Sharti if ((cf = hatm_ext_alloc(sc, 1)) == NULL) 385121680Sharti break; 386121680Sharti buf1 = (struct mbuf1_chunk *)cf; 387121680Sharti pg = sc->mbuf_pages[buf1->hdr.pageno]; 388121729Sharti buf1->hdr.flags |= MBUF_CARD; 389121680Sharti rbp->rbp[rbp->tail].phys = pg->hdr.phys + 390121680Sharti buf1->hdr.chunkno * MBUF1_CHUNK + MBUF1_OFFSET; 391121680Sharti rbp->rbp[rbp->tail].handle = 392121680Sharti MBUF_MAKE_HANDLE(buf1->hdr.pageno, 393121680Sharti buf1->hdr.chunkno); 394121680Sharti 395121680Sharti bus_dmamap_sync(sc->mbuf_tag, pg->hdr.map, 396121680Sharti BUS_DMASYNC_PREREAD); 397121680Sharti 398121680Sharti } else 399121680Sharti /* ups */ 400121680Sharti break; 401121680Sharti 402116491Sharti DBG(sc, DMA, ("MBUF loaded: handle=%x m=%p phys=%x", 403116491Sharti rbp->rbp[rbp->tail].handle, m, rbp->rbp[rbp->tail].phys)); 404116491Sharti 405116491Sharti rbp->tail = ntail; 406116491Sharti } 407121617Sharti WRITE4(sc, HE_REGO_RBP_T(large, group), 408121617Sharti (rbp->tail << HE_REGS_RBP_TAIL)); 409116491Sharti} 410116491Sharti 411116491Sharti/* 412116491Sharti * Extract the buffer and hand it to the receive routine 413116491Sharti */ 414116491Shartistatic struct mbuf * 415116491Shartihatm_rx_buffer(struct hatm_softc *sc, u_int group, u_int handle) 416116491Sharti{ 417116491Sharti u_int pageno; 418116491Sharti u_int chunkno; 419116491Sharti struct mbuf *m; 420116491Sharti 421116491Sharti if (handle & MBUF_LARGE_FLAG) { 422116491Sharti /* large buffer - sync and unload */ 423121680Sharti MBUF_PARSE_LHANDLE(handle, handle); 424116491Sharti DBG(sc, RX, ("RX large handle=%x", handle)); 425116491Sharti 426116491Sharti bus_dmamap_sync(sc->mbuf_tag, sc->rmaps[handle], 427116491Sharti BUS_DMASYNC_POSTREAD); 428116491Sharti bus_dmamap_unload(sc->mbuf_tag, sc->rmaps[handle]); 429116491Sharti 430116491Sharti m = sc->lbufs[handle]; 431116491Sharti sc->lbufs[handle] = NULL; 432116491Sharti 433116491Sharti return (m); 434116491Sharti } 435116491Sharti 436116491Sharti MBUF_PARSE_HANDLE(handle, pageno, chunkno); 437116491Sharti 438116491Sharti DBG(sc, RX, ("RX group=%u handle=%x page=%u chunk=%u", group, handle, 439116491Sharti pageno, chunkno)); 440116491Sharti 441243857Sglebius MGETHDR(m, M_NOWAIT, MT_DATA); 442121676Sharti 443116491Sharti if (group == 0) { 444116491Sharti struct mbuf0_chunk *c0; 445116491Sharti 446116491Sharti c0 = (struct mbuf0_chunk *)sc->mbuf_pages[pageno] + chunkno; 447116491Sharti KASSERT(c0->hdr.pageno == pageno, ("pageno = %u/%u", 448116491Sharti c0->hdr.pageno, pageno)); 449116491Sharti KASSERT(c0->hdr.chunkno == chunkno, ("chunkno = %u/%u", 450116491Sharti c0->hdr.chunkno, chunkno)); 451121729Sharti KASSERT(c0->hdr.flags & MBUF_CARD, ("mbuf not on card %u/%u", 452121729Sharti pageno, chunkno)); 453121729Sharti KASSERT(!(c0->hdr.flags & MBUF_USED), ("used mbuf %u/%u", 454121729Sharti pageno, chunkno)); 455116491Sharti 456121729Sharti c0->hdr.flags |= MBUF_USED; 457121729Sharti c0->hdr.flags &= ~MBUF_CARD; 458121729Sharti 459121676Sharti if (m != NULL) { 460268530Sglebius m->m_ext.ext_cnt = &c0->hdr.ref_cnt; 461150347Sandre MEXTADD(m, (void *)c0, MBUF0_SIZE, 462175872Sphk hatm_mbuf0_free, c0, sc, M_PKTHDR, EXT_EXTREF); 463121676Sharti m->m_data += MBUF0_OFFSET; 464121676Sharti } else 465254842Sandre (void)hatm_mbuf0_free(NULL, c0, sc); 466116491Sharti 467116491Sharti } else { 468116491Sharti struct mbuf1_chunk *c1; 469116491Sharti 470116491Sharti c1 = (struct mbuf1_chunk *)sc->mbuf_pages[pageno] + chunkno; 471116491Sharti KASSERT(c1->hdr.pageno == pageno, ("pageno = %u/%u", 472116491Sharti c1->hdr.pageno, pageno)); 473116491Sharti KASSERT(c1->hdr.chunkno == chunkno, ("chunkno = %u/%u", 474116491Sharti c1->hdr.chunkno, chunkno)); 475121729Sharti KASSERT(c1->hdr.flags & MBUF_CARD, ("mbuf not on card %u/%u", 476121729Sharti pageno, chunkno)); 477121729Sharti KASSERT(!(c1->hdr.flags & MBUF_USED), ("used mbuf %u/%u", 478121729Sharti pageno, chunkno)); 479116491Sharti 480121729Sharti c1->hdr.flags |= MBUF_USED; 481121729Sharti c1->hdr.flags &= ~MBUF_CARD; 482121729Sharti 483121676Sharti if (m != NULL) { 484268530Sglebius m->m_ext.ext_cnt = &c1->hdr.ref_cnt; 485150347Sandre MEXTADD(m, (void *)c1, MBUF1_SIZE, 486175872Sphk hatm_mbuf1_free, c1, sc, M_PKTHDR, EXT_EXTREF); 487121676Sharti m->m_data += MBUF1_OFFSET; 488121676Sharti } else 489254842Sandre (void)hatm_mbuf1_free(NULL, c1, sc); 490116491Sharti } 491116491Sharti 492116491Sharti return (m); 493116491Sharti} 494116491Sharti 495116491Sharti/* 496116491Sharti * Interrupt because of receive buffer returned. 497116491Sharti */ 498116491Shartistatic void 499116491Shartihe_intr_rbrq(struct hatm_softc *sc, struct herbrq *rq, u_int group) 500116491Sharti{ 501116491Sharti struct he_rbrqen *e; 502116491Sharti uint32_t flags, tail; 503116491Sharti u_int cid, len; 504116491Sharti struct mbuf *m; 505116491Sharti 506116491Sharti for (;;) { 507116491Sharti tail = sc->hsp->group[group].rbrq_tail >> 3; 508116491Sharti 509116491Sharti if (rq->head == tail) 510116491Sharti break; 511116491Sharti 512116491Sharti e = &rq->rbrq[rq->head]; 513116491Sharti 514116491Sharti flags = e->addr & HE_REGM_RBRQ_FLAGS; 515116491Sharti if (!(flags & HE_REGM_RBRQ_HBUF_ERROR)) 516121680Sharti m = hatm_rx_buffer(sc, group, e->addr); 517116491Sharti else 518116491Sharti m = NULL; 519116491Sharti 520116491Sharti cid = (e->len & HE_REGM_RBRQ_CID) >> HE_REGS_RBRQ_CID; 521116491Sharti len = 4 * (e->len & HE_REGM_RBRQ_LEN); 522116491Sharti 523116491Sharti hatm_rx(sc, cid, flags, m, len); 524116491Sharti 525116491Sharti if (++rq->head == rq->size) 526116491Sharti rq->head = 0; 527116491Sharti } 528116491Sharti WRITE4(sc, HE_REGO_RBRQ_H(group), rq->head << 3); 529116491Sharti} 530116491Sharti 531116491Shartivoid 532116491Shartihatm_intr(void *p) 533116491Sharti{ 534116491Sharti struct heirq *q = p; 535116491Sharti struct hatm_softc *sc = q->sc; 536116491Sharti u_int status; 537116491Sharti u_int tail; 538116491Sharti 539116491Sharti /* if we have a stray interrupt with a non-initialized card, 540116491Sharti * we cannot even lock before looking at the flag */ 541148887Srwatson if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) 542116491Sharti return; 543116491Sharti 544116491Sharti mtx_lock(&sc->mtx); 545116491Sharti (void)READ4(sc, HE_REGO_INT_FIFO); 546116491Sharti 547116491Sharti tail = *q->tailp; 548116491Sharti if (q->head == tail) { 549116491Sharti /* workaround for tail pointer not updated bug (8.1.1) */ 550116491Sharti DBG(sc, INTR, ("hatm: intr tailq not updated bug triggered")); 551116491Sharti 552116491Sharti /* read the tail pointer from the card */ 553116491Sharti tail = READ4(sc, HE_REGO_IRQ_BASE(q->group)) & 554116491Sharti HE_REGM_IRQ_BASE_TAIL; 555116491Sharti BARRIER_R(sc); 556116491Sharti 557116491Sharti sc->istats.bug_no_irq_upd++; 558116491Sharti } 559116491Sharti 560116491Sharti /* clear the interrupt */ 561116491Sharti WRITE4(sc, HE_REGO_INT_FIFO, HE_REGM_INT_FIFO_CLRA); 562116491Sharti BARRIER_W(sc); 563116491Sharti 564116491Sharti while (q->head != tail) { 565116491Sharti status = q->irq[q->head]; 566116491Sharti q->irq[q->head] = HE_REGM_ITYPE_INVALID; 567116491Sharti if (++q->head == (q->size - 1)) 568116491Sharti q->head = 0; 569116491Sharti 570116491Sharti switch (status & HE_REGM_ITYPE) { 571116491Sharti 572116491Sharti case HE_REGM_ITYPE_TBRQ: 573116491Sharti DBG(sc, INTR, ("TBRQ treshold %u", status & HE_REGM_IGROUP)); 574116491Sharti sc->istats.itype_tbrq++; 575116491Sharti he_intr_tbrq(sc, &sc->tbrq, status & HE_REGM_IGROUP); 576116491Sharti break; 577116491Sharti 578116491Sharti case HE_REGM_ITYPE_TPD: 579116491Sharti DBG(sc, INTR, ("TPD ready %u", status & HE_REGM_IGROUP)); 580116491Sharti sc->istats.itype_tpd++; 581116491Sharti he_intr_tbrq(sc, &sc->tbrq, status & HE_REGM_IGROUP); 582116491Sharti break; 583116491Sharti 584116491Sharti case HE_REGM_ITYPE_RBPS: 585116491Sharti sc->istats.itype_rbps++; 586116491Sharti switch (status & HE_REGM_IGROUP) { 587116491Sharti 588116491Sharti case 0: 589116491Sharti he_intr_rbp(sc, &sc->rbp_s0, 0, 0); 590116491Sharti break; 591116491Sharti 592116491Sharti case 1: 593116491Sharti he_intr_rbp(sc, &sc->rbp_s1, 0, 1); 594116491Sharti break; 595116491Sharti 596116491Sharti default: 597147256Sbrooks if_printf(sc->ifp, "bad INTR RBPS%u\n", 598116491Sharti status & HE_REGM_IGROUP); 599116491Sharti break; 600116491Sharti } 601116491Sharti break; 602116491Sharti 603116491Sharti case HE_REGM_ITYPE_RBPL: 604116491Sharti sc->istats.itype_rbpl++; 605116491Sharti switch (status & HE_REGM_IGROUP) { 606116491Sharti 607116491Sharti case 0: 608116491Sharti he_intr_rbp(sc, &sc->rbp_l0, 1, 0); 609116491Sharti break; 610116491Sharti 611116491Sharti default: 612147256Sbrooks if_printf(sc->ifp, "bad INTR RBPL%u\n", 613116491Sharti status & HE_REGM_IGROUP); 614116491Sharti break; 615116491Sharti } 616116491Sharti break; 617116491Sharti 618116491Sharti case HE_REGM_ITYPE_RBRQ: 619116491Sharti DBG(sc, INTR, ("INTERRUPT RBRQ %u", status & HE_REGM_IGROUP)); 620116491Sharti sc->istats.itype_rbrq++; 621116491Sharti switch (status & HE_REGM_IGROUP) { 622116491Sharti 623116491Sharti case 0: 624116491Sharti he_intr_rbrq(sc, &sc->rbrq_0, 0); 625116491Sharti break; 626116491Sharti 627116491Sharti case 1: 628116491Sharti if (sc->rbrq_1.size > 0) { 629116491Sharti he_intr_rbrq(sc, &sc->rbrq_1, 1); 630116491Sharti break; 631116491Sharti } 632116491Sharti /* FALLTHRU */ 633116491Sharti 634116491Sharti default: 635147256Sbrooks if_printf(sc->ifp, "bad INTR RBRQ%u\n", 636116491Sharti status & HE_REGM_IGROUP); 637116491Sharti break; 638116491Sharti } 639116491Sharti break; 640116491Sharti 641116491Sharti case HE_REGM_ITYPE_RBRQT: 642116491Sharti DBG(sc, INTR, ("INTERRUPT RBRQT %u", status & HE_REGM_IGROUP)); 643116491Sharti sc->istats.itype_rbrqt++; 644116491Sharti switch (status & HE_REGM_IGROUP) { 645116491Sharti 646116491Sharti case 0: 647116491Sharti he_intr_rbrq(sc, &sc->rbrq_0, 0); 648116491Sharti break; 649116491Sharti 650116491Sharti case 1: 651116491Sharti if (sc->rbrq_1.size > 0) { 652116491Sharti he_intr_rbrq(sc, &sc->rbrq_1, 1); 653116491Sharti break; 654116491Sharti } 655116491Sharti /* FALLTHRU */ 656116491Sharti 657116491Sharti default: 658147256Sbrooks if_printf(sc->ifp, "bad INTR RBRQT%u\n", 659116491Sharti status & HE_REGM_IGROUP); 660116491Sharti break; 661116491Sharti } 662116491Sharti break; 663116491Sharti 664116491Sharti case HE_REGM_ITYPE_PHYS: 665116491Sharti sc->istats.itype_phys++; 666116491Sharti utopia_intr(&sc->utopia); 667116491Sharti break; 668116491Sharti 669116491Sharti#if HE_REGM_ITYPE_UNKNOWN != HE_REGM_ITYPE_INVALID 670116491Sharti case HE_REGM_ITYPE_UNKNOWN: 671116491Sharti sc->istats.itype_unknown++; 672147256Sbrooks if_printf(sc->ifp, "bad interrupt\n"); 673116491Sharti break; 674116491Sharti#endif 675116491Sharti 676116491Sharti case HE_REGM_ITYPE_ERR: 677116491Sharti sc->istats.itype_err++; 678116491Sharti switch (status) { 679116491Sharti 680116491Sharti case HE_REGM_ITYPE_PERR: 681147256Sbrooks if_printf(sc->ifp, "parity error\n"); 682116491Sharti break; 683116491Sharti 684116491Sharti case HE_REGM_ITYPE_ABORT: 685147256Sbrooks if_printf(sc->ifp, "abort interrupt " 686116491Sharti "addr=0x%08x\n", 687116491Sharti READ4(sc, HE_REGO_ABORT_ADDR)); 688116491Sharti break; 689116491Sharti 690116491Sharti default: 691147256Sbrooks if_printf(sc->ifp, 692116491Sharti "bad interrupt type %08x\n", status); 693116491Sharti break; 694116491Sharti } 695116491Sharti break; 696116491Sharti 697116491Sharti case HE_REGM_ITYPE_INVALID: 698116491Sharti /* this is the documented fix for the ISW bug 8.1.1 699116491Sharti * Note, that the documented fix is partly wrong: 700116491Sharti * the ISWs should be intialized to 0xf8 not 0xff */ 701116491Sharti sc->istats.bug_bad_isw++; 702116491Sharti DBG(sc, INTR, ("hatm: invalid ISW bug triggered")); 703116491Sharti he_intr_tbrq(sc, &sc->tbrq, 0); 704116491Sharti he_intr_rbp(sc, &sc->rbp_s0, 0, 0); 705116491Sharti he_intr_rbp(sc, &sc->rbp_l0, 1, 0); 706116491Sharti he_intr_rbp(sc, &sc->rbp_s1, 0, 1); 707116491Sharti he_intr_rbrq(sc, &sc->rbrq_0, 0); 708116491Sharti he_intr_rbrq(sc, &sc->rbrq_1, 1); 709116491Sharti utopia_intr(&sc->utopia); 710116491Sharti break; 711116491Sharti 712116491Sharti default: 713147256Sbrooks if_printf(sc->ifp, "bad interrupt type %08x\n", 714116491Sharti status); 715116491Sharti break; 716116491Sharti } 717116491Sharti } 718116491Sharti 719116491Sharti /* write back head to clear queue */ 720116491Sharti WRITE4(sc, HE_REGO_IRQ_HEAD(0), 721116491Sharti ((q->size - 1) << HE_REGS_IRQ_HEAD_SIZE) | 722116491Sharti (q->thresh << HE_REGS_IRQ_HEAD_THRESH) | 723116491Sharti (q->head << HE_REGS_IRQ_HEAD_HEAD)); 724116491Sharti BARRIER_W(sc); 725116491Sharti 726116491Sharti /* workaround the back-to-back irq access problem (8.1.2) */ 727116491Sharti (void)READ4(sc, HE_REGO_INT_FIFO); 728116491Sharti BARRIER_R(sc); 729116491Sharti 730116491Sharti mtx_unlock(&sc->mtx); 731116491Sharti} 732