if_hatm_intr.c revision 122111
1116491Sharti/* 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: head/sys/dev/hatm/if_hatm_intr.c 122111 2003-11-05 11:15:47Z harti $"); 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> 61116491Sharti#include <net/if_media.h> 62116491Sharti#include <net/if_atm.h> 63116491Sharti#include <net/route.h> 64116491Sharti#include <netinet/in.h> 65116491Sharti#include <netinet/if_atm.h> 66116491Sharti 67116491Sharti#include <machine/bus.h> 68116491Sharti#include <machine/resource.h> 69116491Sharti#include <sys/bus.h> 70116491Sharti#include <sys/rman.h> 71119280Simp#include <dev/pci/pcireg.h> 72119280Simp#include <dev/pci/pcivar.h> 73116491Sharti 74116491Sharti#include <dev/utopia/utopia.h> 75116491Sharti#include <dev/hatm/if_hatmconf.h> 76116491Sharti#include <dev/hatm/if_hatmreg.h> 77116491Sharti#include <dev/hatm/if_hatmvar.h> 78116491Sharti 79116491ShartiCTASSERT(sizeof(struct mbuf_page) == MBUF_ALLOC_SIZE); 80116491ShartiCTASSERT(sizeof(struct mbuf0_chunk) == MBUF0_CHUNK); 81116491ShartiCTASSERT(sizeof(struct mbuf1_chunk) == MBUF1_CHUNK); 82116491ShartiCTASSERT(sizeof(((struct mbuf0_chunk *)NULL)->storage) >= MBUF0_SIZE); 83116491ShartiCTASSERT(sizeof(((struct mbuf1_chunk *)NULL)->storage) >= MBUF1_SIZE); 84116491ShartiCTASSERT(sizeof(struct tpd) <= HE_TPD_SIZE); 85116491Sharti 86121729ShartiCTASSERT(MBUF0_PER_PAGE <= 256); 87121729ShartiCTASSERT(MBUF1_PER_PAGE <= 256); 88121729Sharti 89121675Shartistatic void hatm_mbuf_page_alloc(struct hatm_softc *sc, u_int group); 90121675Sharti 91116491Sharti/* 92121675Sharti * Free an external mbuf to a list. We use atomic functions so that 93121675Sharti * we don't need a mutex for the list. 94121744Sharti * 95121744Sharti * Note that in general this algorithm is not safe when multiple readers 96121744Sharti * and writers are present. To cite from a mail from David Schultz 97121744Sharti * <das@freebsd.org>: 98121744Sharti * 99121744Sharti * It looks like this is subject to the ABA problem. For instance, 100121744Sharti * suppose X, Y, and Z are the top things on the freelist and a 101121744Sharti * thread attempts to make an allocation. You set buf to X and load 102121744Sharti * buf->link (Y) into a register. Then the thread get preempted, and 103121744Sharti * another thread allocates both X and Y, then frees X. When the 104121744Sharti * original thread gets the CPU again, X is still on top of the 105121744Sharti * freelist, so the atomic operation succeeds. However, the atomic 106121744Sharti * op places Y on top of the freelist, even though Y is no longer 107121744Sharti * free. 108121744Sharti * 109121744Sharti * We are, however sure that we have only one thread that ever allocates 110121744Sharti * buffers because the only place we're call from is the interrupt handler. 111121744Sharti * Under these circumstances the code looks safe. 112121675Sharti */ 113121729Sharti__inline void 114121675Shartihatm_ext_free(struct mbufx_free **list, struct mbufx_free *buf) 115121675Sharti{ 116121675Sharti for (;;) { 117121675Sharti buf->link = *list; 118121675Sharti if (atomic_cmpset_ptr(list, buf->link, buf)) 119121675Sharti break; 120121675Sharti } 121121675Sharti} 122121675Sharti 123121675Shartistatic __inline struct mbufx_free * 124121675Shartihatm_ext_alloc(struct hatm_softc *sc, u_int g) 125121675Sharti{ 126121675Sharti struct mbufx_free *buf; 127121675Sharti 128121675Sharti for (;;) { 129121675Sharti if ((buf = sc->mbuf_list[g]) == NULL) 130121675Sharti break; 131121675Sharti if (atomic_cmpset_ptr(&sc->mbuf_list[g], buf, buf->link)) 132121675Sharti break; 133121675Sharti } 134121675Sharti if (buf == NULL) { 135121675Sharti hatm_mbuf_page_alloc(sc, g); 136121675Sharti for (;;) { 137121675Sharti if ((buf = sc->mbuf_list[g]) == NULL) 138121675Sharti break; 139121675Sharti if (atomic_cmpset_ptr(&sc->mbuf_list[g], buf, buf->link)) 140121675Sharti break; 141121675Sharti } 142121675Sharti } 143121675Sharti return (buf); 144121675Sharti} 145121675Sharti 146121675Sharti/* 147116491Sharti * Either the queue treshold was crossed or a TPD with the INTR bit set 148116491Sharti * was transmitted. 149116491Sharti */ 150116491Shartistatic void 151116491Shartihe_intr_tbrq(struct hatm_softc *sc, struct hetbrq *q, u_int group) 152116491Sharti{ 153116491Sharti uint32_t *tailp = &sc->hsp->group[group].tbrq_tail; 154116491Sharti u_int no; 155116491Sharti 156116491Sharti while (q->head != (*tailp >> 2)) { 157116491Sharti no = (q->tbrq[q->head].addr & HE_REGM_TBRQ_ADDR) >> 158116491Sharti HE_REGS_TPD_ADDR; 159116491Sharti hatm_tx_complete(sc, TPD_ADDR(sc, no), 160116491Sharti (q->tbrq[q->head].addr & HE_REGM_TBRQ_FLAGS)); 161116491Sharti 162116491Sharti if (++q->head == q->size) 163116491Sharti q->head = 0; 164116491Sharti } 165116491Sharti WRITE4(sc, HE_REGO_TBRQ_H(group), q->head << 2); 166116491Sharti} 167116491Sharti 168116491Sharti/* 169116491Sharti * DMA loader function for external mbuf page. 170116491Sharti */ 171116491Shartistatic void 172116491Shartihatm_extbuf_helper(void *arg, bus_dma_segment_t *segs, int nsegs, 173116491Sharti int error) 174116491Sharti{ 175116491Sharti if (error) { 176116491Sharti printf("%s: mapping error %d\n", __func__, error); 177116491Sharti return; 178116491Sharti } 179116491Sharti KASSERT(nsegs == 1, 180116491Sharti ("too many segments for DMA: %d", nsegs)); 181116491Sharti KASSERT(segs[0].ds_addr <= 0xffffffffLU, 182116491Sharti ("phys addr too large %lx", (u_long)segs[0].ds_addr)); 183116491Sharti 184116491Sharti *(uint32_t *)arg = segs[0].ds_addr; 185116491Sharti} 186116491Sharti 187116491Sharti/* 188116491Sharti * Allocate a page of external mbuf storage for the small pools. 189116491Sharti * Create a DMA map and load it. Put all the chunks onto the right 190116491Sharti * free list. 191116491Sharti */ 192116491Shartistatic void 193116491Shartihatm_mbuf_page_alloc(struct hatm_softc *sc, u_int group) 194116491Sharti{ 195116491Sharti struct mbuf_page *pg; 196116491Sharti int err; 197116491Sharti u_int i; 198116491Sharti 199121686Sharti if (sc->mbuf_npages == sc->mbuf_max_pages) 200116491Sharti return; 201116491Sharti if ((pg = malloc(MBUF_ALLOC_SIZE, M_DEVBUF, M_NOWAIT)) == NULL) 202116491Sharti return; 203116491Sharti 204116491Sharti err = bus_dmamap_create(sc->mbuf_tag, 0, &pg->hdr.map); 205116491Sharti if (err != 0) { 206116491Sharti if_printf(&sc->ifatm.ifnet, "%s -- bus_dmamap_create: %d\n", 207116491Sharti __func__, err); 208116491Sharti free(pg, M_DEVBUF); 209116491Sharti return; 210116491Sharti } 211116491Sharti err = bus_dmamap_load(sc->mbuf_tag, pg->hdr.map, pg, MBUF_ALLOC_SIZE, 212117382Sharti hatm_extbuf_helper, &pg->hdr.phys, BUS_DMA_NOWAIT); 213116491Sharti if (err != 0) { 214116491Sharti if_printf(&sc->ifatm.ifnet, "%s -- mbuf mapping failed %d\n", 215116491Sharti __func__, err); 216116491Sharti bus_dmamap_destroy(sc->mbuf_tag, pg->hdr.map); 217116491Sharti free(pg, M_DEVBUF); 218116491Sharti return; 219116491Sharti } 220116491Sharti 221116491Sharti sc->mbuf_pages[sc->mbuf_npages] = pg; 222116491Sharti 223116491Sharti if (group == 0) { 224116491Sharti struct mbuf0_chunk *c; 225116491Sharti 226121729Sharti pg->hdr.pool = 0; 227116491Sharti pg->hdr.nchunks = MBUF0_PER_PAGE; 228116491Sharti pg->hdr.chunksize = MBUF0_CHUNK; 229116491Sharti pg->hdr.hdroff = sizeof(c->storage); 230116491Sharti c = (struct mbuf0_chunk *)pg; 231116491Sharti for (i = 0; i < MBUF0_PER_PAGE; i++, c++) { 232116491Sharti c->hdr.pageno = sc->mbuf_npages; 233116491Sharti c->hdr.chunkno = i; 234122111Sharti c->hdr.flags = 0; 235121675Sharti hatm_ext_free(&sc->mbuf_list[0], 236121675Sharti (struct mbufx_free *)c); 237116491Sharti } 238116491Sharti } else { 239116491Sharti struct mbuf1_chunk *c; 240116491Sharti 241121729Sharti pg->hdr.pool = 1; 242116491Sharti pg->hdr.nchunks = MBUF1_PER_PAGE; 243116491Sharti pg->hdr.chunksize = MBUF1_CHUNK; 244116491Sharti pg->hdr.hdroff = sizeof(c->storage); 245116491Sharti c = (struct mbuf1_chunk *)pg; 246116491Sharti for (i = 0; i < MBUF1_PER_PAGE; i++, c++) { 247116491Sharti c->hdr.pageno = sc->mbuf_npages; 248116491Sharti c->hdr.chunkno = i; 249122111Sharti c->hdr.flags = 0; 250121675Sharti hatm_ext_free(&sc->mbuf_list[1], 251121675Sharti (struct mbufx_free *)c); 252116491Sharti } 253116491Sharti } 254116491Sharti sc->mbuf_npages++; 255116491Sharti} 256116491Sharti 257116491Sharti/* 258116491Sharti * Free an mbuf and put it onto the free list. 259116491Sharti */ 260116491Shartistatic void 261116491Shartihatm_mbuf0_free(void *buf, void *args) 262116491Sharti{ 263116491Sharti struct hatm_softc *sc = args; 264116491Sharti struct mbuf0_chunk *c = buf; 265116491Sharti 266121729Sharti KASSERT((c->hdr.flags & (MBUF_USED | MBUF_CARD)) == MBUF_USED, 267121729Sharti ("freeing unused mbuf %x", c->hdr.flags)); 268121729Sharti c->hdr.flags &= ~MBUF_USED; 269121675Sharti hatm_ext_free(&sc->mbuf_list[0], (struct mbufx_free *)c); 270116491Sharti} 271116491Shartistatic void 272116491Shartihatm_mbuf1_free(void *buf, void *args) 273116491Sharti{ 274116491Sharti struct hatm_softc *sc = args; 275116491Sharti struct mbuf1_chunk *c = buf; 276116491Sharti 277121729Sharti KASSERT((c->hdr.flags & (MBUF_USED | MBUF_CARD)) == MBUF_USED, 278121729Sharti ("freeing unused mbuf %x", c->hdr.flags)); 279121729Sharti c->hdr.flags &= ~MBUF_USED; 280121675Sharti hatm_ext_free(&sc->mbuf_list[1], (struct mbufx_free *)c); 281116491Sharti} 282116491Sharti 283116491Shartistatic void 284116491Shartihatm_mbuf_helper(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 285116491Sharti{ 286116491Sharti uint32_t *ptr = (uint32_t *)arg; 287116491Sharti 288116491Sharti if (nsegs == 0) { 289116491Sharti printf("%s: error=%d\n", __func__, error); 290116491Sharti return; 291116491Sharti } 292116491Sharti KASSERT(nsegs == 1, ("too many segments for mbuf: %d", nsegs)); 293116491Sharti KASSERT(segs[0].ds_addr <= 0xffffffffLU, 294116491Sharti ("phys addr too large %lx", (u_long)segs[0].ds_addr)); 295116491Sharti 296116491Sharti *ptr = segs[0].ds_addr; 297116491Sharti} 298116491Sharti 299116491Sharti/* 300116491Sharti * Receive buffer pool interrupt. This means the number of entries in the 301116491Sharti * queue has dropped below the threshold. Try to supply new buffers. 302116491Sharti */ 303116491Shartistatic void 304116491Shartihe_intr_rbp(struct hatm_softc *sc, struct herbp *rbp, u_int large, 305116491Sharti u_int group) 306116491Sharti{ 307121617Sharti u_int ntail; 308116491Sharti struct mbuf *m; 309116491Sharti int error; 310121680Sharti struct mbufx_free *cf; 311121680Sharti struct mbuf_page *pg; 312121680Sharti struct mbuf0_chunk *buf0; 313121680Sharti struct mbuf1_chunk *buf1; 314116491Sharti 315116491Sharti DBG(sc, INTR, ("%s buffer supply threshold crossed for group %u", 316116491Sharti large ? "large" : "small", group)); 317116491Sharti 318116491Sharti rbp->head = (READ4(sc, HE_REGO_RBP_S(large, group)) >> HE_REGS_RBP_HEAD) 319116491Sharti & (rbp->size - 1); 320116491Sharti 321116491Sharti for (;;) { 322116491Sharti if ((ntail = rbp->tail + 1) == rbp->size) 323116491Sharti ntail = 0; 324116491Sharti if (ntail == rbp->head) 325116491Sharti break; 326121680Sharti m = NULL; 327116491Sharti 328116491Sharti if (large) { 329121676Sharti /* allocate the MBUF */ 330116491Sharti if ((m = m_getcl(M_DONTWAIT, MT_DATA, 331116491Sharti M_PKTHDR)) == NULL) { 332116491Sharti if_printf(&sc->ifatm.ifnet, 333116491Sharti "no mbuf clusters\n"); 334116491Sharti break; 335116491Sharti } 336116491Sharti m->m_data += MBUFL_OFFSET; 337116491Sharti 338116491Sharti if (sc->lbufs[sc->lbufs_next] != NULL) 339116491Sharti panic("hatm: lbufs full %u", sc->lbufs_next); 340116491Sharti sc->lbufs[sc->lbufs_next] = m; 341116491Sharti 342116491Sharti if ((error = bus_dmamap_load(sc->mbuf_tag, 343116491Sharti sc->rmaps[sc->lbufs_next], 344116491Sharti m->m_data, rbp->bsize, hatm_mbuf_helper, 345117382Sharti &rbp->rbp[rbp->tail].phys, BUS_DMA_NOWAIT)) != NULL) 346116491Sharti panic("hatm: mbuf mapping failed %d", error); 347116491Sharti 348116491Sharti bus_dmamap_sync(sc->mbuf_tag, 349116491Sharti sc->rmaps[sc->lbufs_next], 350116491Sharti BUS_DMASYNC_PREREAD); 351116491Sharti 352121680Sharti rbp->rbp[rbp->tail].handle = 353121680Sharti MBUF_MAKE_LHANDLE(sc->lbufs_next); 354116491Sharti 355116491Sharti if (++sc->lbufs_next == sc->lbufs_size) 356116491Sharti sc->lbufs_next = 0; 357116491Sharti 358121680Sharti } else if (group == 0) { 359121680Sharti /* 360121680Sharti * Allocate small buffer in group 0 361121680Sharti */ 362121680Sharti if ((cf = hatm_ext_alloc(sc, 0)) == NULL) 363116491Sharti break; 364121680Sharti buf0 = (struct mbuf0_chunk *)cf; 365121680Sharti pg = sc->mbuf_pages[buf0->hdr.pageno]; 366121729Sharti buf0->hdr.flags |= MBUF_CARD; 367121680Sharti rbp->rbp[rbp->tail].phys = pg->hdr.phys + 368121680Sharti buf0->hdr.chunkno * MBUF0_CHUNK + MBUF0_OFFSET; 369121680Sharti rbp->rbp[rbp->tail].handle = 370121680Sharti MBUF_MAKE_HANDLE(buf0->hdr.pageno, 371121680Sharti buf0->hdr.chunkno); 372121680Sharti 373121680Sharti bus_dmamap_sync(sc->mbuf_tag, pg->hdr.map, 374121680Sharti BUS_DMASYNC_PREREAD); 375121680Sharti 376121680Sharti } else if (group == 1) { 377121680Sharti /* 378121680Sharti * Allocate small buffer in group 1 379121680Sharti */ 380121680Sharti if ((cf = hatm_ext_alloc(sc, 1)) == NULL) 381121680Sharti break; 382121680Sharti buf1 = (struct mbuf1_chunk *)cf; 383121680Sharti pg = sc->mbuf_pages[buf1->hdr.pageno]; 384121729Sharti buf1->hdr.flags |= MBUF_CARD; 385121680Sharti rbp->rbp[rbp->tail].phys = pg->hdr.phys + 386121680Sharti buf1->hdr.chunkno * MBUF1_CHUNK + MBUF1_OFFSET; 387121680Sharti rbp->rbp[rbp->tail].handle = 388121680Sharti MBUF_MAKE_HANDLE(buf1->hdr.pageno, 389121680Sharti buf1->hdr.chunkno); 390121680Sharti 391121680Sharti bus_dmamap_sync(sc->mbuf_tag, pg->hdr.map, 392121680Sharti BUS_DMASYNC_PREREAD); 393121680Sharti 394121680Sharti } else 395121680Sharti /* ups */ 396121680Sharti break; 397121680Sharti 398116491Sharti DBG(sc, DMA, ("MBUF loaded: handle=%x m=%p phys=%x", 399116491Sharti rbp->rbp[rbp->tail].handle, m, rbp->rbp[rbp->tail].phys)); 400116491Sharti 401116491Sharti rbp->tail = ntail; 402116491Sharti } 403121617Sharti WRITE4(sc, HE_REGO_RBP_T(large, group), 404121617Sharti (rbp->tail << HE_REGS_RBP_TAIL)); 405116491Sharti} 406116491Sharti 407116491Sharti/* 408116491Sharti * Extract the buffer and hand it to the receive routine 409116491Sharti */ 410116491Shartistatic struct mbuf * 411116491Shartihatm_rx_buffer(struct hatm_softc *sc, u_int group, u_int handle) 412116491Sharti{ 413116491Sharti u_int pageno; 414116491Sharti u_int chunkno; 415116491Sharti struct mbuf *m; 416116491Sharti 417116491Sharti if (handle & MBUF_LARGE_FLAG) { 418116491Sharti /* large buffer - sync and unload */ 419121680Sharti MBUF_PARSE_LHANDLE(handle, handle); 420116491Sharti DBG(sc, RX, ("RX large handle=%x", handle)); 421116491Sharti 422116491Sharti bus_dmamap_sync(sc->mbuf_tag, sc->rmaps[handle], 423116491Sharti BUS_DMASYNC_POSTREAD); 424116491Sharti bus_dmamap_unload(sc->mbuf_tag, sc->rmaps[handle]); 425116491Sharti 426116491Sharti m = sc->lbufs[handle]; 427116491Sharti sc->lbufs[handle] = NULL; 428116491Sharti 429116491Sharti return (m); 430116491Sharti } 431116491Sharti 432116491Sharti MBUF_PARSE_HANDLE(handle, pageno, chunkno); 433116491Sharti 434116491Sharti DBG(sc, RX, ("RX group=%u handle=%x page=%u chunk=%u", group, handle, 435116491Sharti pageno, chunkno)); 436116491Sharti 437121676Sharti MGETHDR(m, M_DONTWAIT, MT_DATA); 438121676Sharti 439116491Sharti if (group == 0) { 440116491Sharti struct mbuf0_chunk *c0; 441116491Sharti 442116491Sharti c0 = (struct mbuf0_chunk *)sc->mbuf_pages[pageno] + chunkno; 443116491Sharti KASSERT(c0->hdr.pageno == pageno, ("pageno = %u/%u", 444116491Sharti c0->hdr.pageno, pageno)); 445116491Sharti KASSERT(c0->hdr.chunkno == chunkno, ("chunkno = %u/%u", 446116491Sharti c0->hdr.chunkno, chunkno)); 447121729Sharti KASSERT(c0->hdr.flags & MBUF_CARD, ("mbuf not on card %u/%u", 448121729Sharti pageno, chunkno)); 449121729Sharti KASSERT(!(c0->hdr.flags & MBUF_USED), ("used mbuf %u/%u", 450121729Sharti pageno, chunkno)); 451116491Sharti 452121729Sharti c0->hdr.flags |= MBUF_USED; 453121729Sharti c0->hdr.flags &= ~MBUF_CARD; 454121729Sharti 455121676Sharti if (m != NULL) { 456121677Sharti m->m_ext.ref_cnt = &c0->hdr.ref_cnt; 457121676Sharti m_extadd(m, (void *)c0, MBUF0_SIZE, 458121677Sharti hatm_mbuf0_free, sc, M_PKTHDR, EXT_EXTREF); 459121676Sharti m->m_data += MBUF0_OFFSET; 460121676Sharti } else 461121676Sharti hatm_mbuf0_free(c0, sc); 462116491Sharti 463116491Sharti } else { 464116491Sharti struct mbuf1_chunk *c1; 465116491Sharti 466116491Sharti c1 = (struct mbuf1_chunk *)sc->mbuf_pages[pageno] + chunkno; 467116491Sharti KASSERT(c1->hdr.pageno == pageno, ("pageno = %u/%u", 468116491Sharti c1->hdr.pageno, pageno)); 469116491Sharti KASSERT(c1->hdr.chunkno == chunkno, ("chunkno = %u/%u", 470116491Sharti c1->hdr.chunkno, chunkno)); 471121729Sharti KASSERT(c1->hdr.flags & MBUF_CARD, ("mbuf not on card %u/%u", 472121729Sharti pageno, chunkno)); 473121729Sharti KASSERT(!(c1->hdr.flags & MBUF_USED), ("used mbuf %u/%u", 474121729Sharti pageno, chunkno)); 475116491Sharti 476121729Sharti c1->hdr.flags |= MBUF_USED; 477121729Sharti c1->hdr.flags &= ~MBUF_CARD; 478121729Sharti 479121676Sharti if (m != NULL) { 480121677Sharti m->m_ext.ref_cnt = &c1->hdr.ref_cnt; 481121676Sharti m_extadd(m, (void *)c1, MBUF1_SIZE, 482121677Sharti hatm_mbuf1_free, sc, M_PKTHDR, EXT_EXTREF); 483121676Sharti m->m_data += MBUF1_OFFSET; 484121676Sharti } else 485121676Sharti hatm_mbuf1_free(c1, sc); 486116491Sharti } 487116491Sharti 488116491Sharti return (m); 489116491Sharti} 490116491Sharti 491116491Sharti/* 492116491Sharti * Interrupt because of receive buffer returned. 493116491Sharti */ 494116491Shartistatic void 495116491Shartihe_intr_rbrq(struct hatm_softc *sc, struct herbrq *rq, u_int group) 496116491Sharti{ 497116491Sharti struct he_rbrqen *e; 498116491Sharti uint32_t flags, tail; 499116491Sharti u_int cid, len; 500116491Sharti struct mbuf *m; 501116491Sharti 502116491Sharti for (;;) { 503116491Sharti tail = sc->hsp->group[group].rbrq_tail >> 3; 504116491Sharti 505116491Sharti if (rq->head == tail) 506116491Sharti break; 507116491Sharti 508116491Sharti e = &rq->rbrq[rq->head]; 509116491Sharti 510116491Sharti flags = e->addr & HE_REGM_RBRQ_FLAGS; 511116491Sharti if (!(flags & HE_REGM_RBRQ_HBUF_ERROR)) 512121680Sharti m = hatm_rx_buffer(sc, group, e->addr); 513116491Sharti else 514116491Sharti m = NULL; 515116491Sharti 516116491Sharti cid = (e->len & HE_REGM_RBRQ_CID) >> HE_REGS_RBRQ_CID; 517116491Sharti len = 4 * (e->len & HE_REGM_RBRQ_LEN); 518116491Sharti 519116491Sharti hatm_rx(sc, cid, flags, m, len); 520116491Sharti 521116491Sharti if (++rq->head == rq->size) 522116491Sharti rq->head = 0; 523116491Sharti } 524116491Sharti WRITE4(sc, HE_REGO_RBRQ_H(group), rq->head << 3); 525116491Sharti} 526116491Sharti 527116491Shartivoid 528116491Shartihatm_intr(void *p) 529116491Sharti{ 530116491Sharti struct heirq *q = p; 531116491Sharti struct hatm_softc *sc = q->sc; 532116491Sharti u_int status; 533116491Sharti u_int tail; 534116491Sharti 535116491Sharti /* if we have a stray interrupt with a non-initialized card, 536116491Sharti * we cannot even lock before looking at the flag */ 537116491Sharti if (!(sc->ifatm.ifnet.if_flags & IFF_RUNNING)) 538116491Sharti return; 539116491Sharti 540116491Sharti mtx_lock(&sc->mtx); 541116491Sharti (void)READ4(sc, HE_REGO_INT_FIFO); 542116491Sharti 543116491Sharti tail = *q->tailp; 544116491Sharti if (q->head == tail) { 545116491Sharti /* workaround for tail pointer not updated bug (8.1.1) */ 546116491Sharti DBG(sc, INTR, ("hatm: intr tailq not updated bug triggered")); 547116491Sharti 548116491Sharti /* read the tail pointer from the card */ 549116491Sharti tail = READ4(sc, HE_REGO_IRQ_BASE(q->group)) & 550116491Sharti HE_REGM_IRQ_BASE_TAIL; 551116491Sharti BARRIER_R(sc); 552116491Sharti 553116491Sharti sc->istats.bug_no_irq_upd++; 554116491Sharti } 555116491Sharti 556116491Sharti /* clear the interrupt */ 557116491Sharti WRITE4(sc, HE_REGO_INT_FIFO, HE_REGM_INT_FIFO_CLRA); 558116491Sharti BARRIER_W(sc); 559116491Sharti 560116491Sharti while (q->head != tail) { 561116491Sharti status = q->irq[q->head]; 562116491Sharti q->irq[q->head] = HE_REGM_ITYPE_INVALID; 563116491Sharti if (++q->head == (q->size - 1)) 564116491Sharti q->head = 0; 565116491Sharti 566116491Sharti switch (status & HE_REGM_ITYPE) { 567116491Sharti 568116491Sharti case HE_REGM_ITYPE_TBRQ: 569116491Sharti DBG(sc, INTR, ("TBRQ treshold %u", status & HE_REGM_IGROUP)); 570116491Sharti sc->istats.itype_tbrq++; 571116491Sharti he_intr_tbrq(sc, &sc->tbrq, status & HE_REGM_IGROUP); 572116491Sharti break; 573116491Sharti 574116491Sharti case HE_REGM_ITYPE_TPD: 575116491Sharti DBG(sc, INTR, ("TPD ready %u", status & HE_REGM_IGROUP)); 576116491Sharti sc->istats.itype_tpd++; 577116491Sharti he_intr_tbrq(sc, &sc->tbrq, status & HE_REGM_IGROUP); 578116491Sharti break; 579116491Sharti 580116491Sharti case HE_REGM_ITYPE_RBPS: 581116491Sharti sc->istats.itype_rbps++; 582116491Sharti switch (status & HE_REGM_IGROUP) { 583116491Sharti 584116491Sharti case 0: 585116491Sharti he_intr_rbp(sc, &sc->rbp_s0, 0, 0); 586116491Sharti break; 587116491Sharti 588116491Sharti case 1: 589116491Sharti he_intr_rbp(sc, &sc->rbp_s1, 0, 1); 590116491Sharti break; 591116491Sharti 592116491Sharti default: 593116491Sharti if_printf(&sc->ifatm.ifnet, "bad INTR RBPS%u\n", 594116491Sharti status & HE_REGM_IGROUP); 595116491Sharti break; 596116491Sharti } 597116491Sharti break; 598116491Sharti 599116491Sharti case HE_REGM_ITYPE_RBPL: 600116491Sharti sc->istats.itype_rbpl++; 601116491Sharti switch (status & HE_REGM_IGROUP) { 602116491Sharti 603116491Sharti case 0: 604116491Sharti he_intr_rbp(sc, &sc->rbp_l0, 1, 0); 605116491Sharti break; 606116491Sharti 607116491Sharti default: 608116491Sharti if_printf(&sc->ifatm.ifnet, "bad INTR RBPL%u\n", 609116491Sharti status & HE_REGM_IGROUP); 610116491Sharti break; 611116491Sharti } 612116491Sharti break; 613116491Sharti 614116491Sharti case HE_REGM_ITYPE_RBRQ: 615116491Sharti DBG(sc, INTR, ("INTERRUPT RBRQ %u", status & HE_REGM_IGROUP)); 616116491Sharti sc->istats.itype_rbrq++; 617116491Sharti switch (status & HE_REGM_IGROUP) { 618116491Sharti 619116491Sharti case 0: 620116491Sharti he_intr_rbrq(sc, &sc->rbrq_0, 0); 621116491Sharti break; 622116491Sharti 623116491Sharti case 1: 624116491Sharti if (sc->rbrq_1.size > 0) { 625116491Sharti he_intr_rbrq(sc, &sc->rbrq_1, 1); 626116491Sharti break; 627116491Sharti } 628116491Sharti /* FALLTHRU */ 629116491Sharti 630116491Sharti default: 631116491Sharti if_printf(&sc->ifatm.ifnet, "bad INTR RBRQ%u\n", 632116491Sharti status & HE_REGM_IGROUP); 633116491Sharti break; 634116491Sharti } 635116491Sharti break; 636116491Sharti 637116491Sharti case HE_REGM_ITYPE_RBRQT: 638116491Sharti DBG(sc, INTR, ("INTERRUPT RBRQT %u", status & HE_REGM_IGROUP)); 639116491Sharti sc->istats.itype_rbrqt++; 640116491Sharti switch (status & HE_REGM_IGROUP) { 641116491Sharti 642116491Sharti case 0: 643116491Sharti he_intr_rbrq(sc, &sc->rbrq_0, 0); 644116491Sharti break; 645116491Sharti 646116491Sharti case 1: 647116491Sharti if (sc->rbrq_1.size > 0) { 648116491Sharti he_intr_rbrq(sc, &sc->rbrq_1, 1); 649116491Sharti break; 650116491Sharti } 651116491Sharti /* FALLTHRU */ 652116491Sharti 653116491Sharti default: 654116491Sharti if_printf(&sc->ifatm.ifnet, "bad INTR RBRQT%u\n", 655116491Sharti status & HE_REGM_IGROUP); 656116491Sharti break; 657116491Sharti } 658116491Sharti break; 659116491Sharti 660116491Sharti case HE_REGM_ITYPE_PHYS: 661116491Sharti sc->istats.itype_phys++; 662116491Sharti utopia_intr(&sc->utopia); 663116491Sharti break; 664116491Sharti 665116491Sharti#if HE_REGM_ITYPE_UNKNOWN != HE_REGM_ITYPE_INVALID 666116491Sharti case HE_REGM_ITYPE_UNKNOWN: 667116491Sharti sc->istats.itype_unknown++; 668116491Sharti if_printf(&sc->ifatm.ifnet, "bad interrupt\n"); 669116491Sharti break; 670116491Sharti#endif 671116491Sharti 672116491Sharti case HE_REGM_ITYPE_ERR: 673116491Sharti sc->istats.itype_err++; 674116491Sharti switch (status) { 675116491Sharti 676116491Sharti case HE_REGM_ITYPE_PERR: 677116491Sharti if_printf(&sc->ifatm.ifnet, "parity error\n"); 678116491Sharti break; 679116491Sharti 680116491Sharti case HE_REGM_ITYPE_ABORT: 681116491Sharti if_printf(&sc->ifatm.ifnet, "abort interrupt " 682116491Sharti "addr=0x%08x\n", 683116491Sharti READ4(sc, HE_REGO_ABORT_ADDR)); 684116491Sharti break; 685116491Sharti 686116491Sharti default: 687116491Sharti if_printf(&sc->ifatm.ifnet, 688116491Sharti "bad interrupt type %08x\n", status); 689116491Sharti break; 690116491Sharti } 691116491Sharti break; 692116491Sharti 693116491Sharti case HE_REGM_ITYPE_INVALID: 694116491Sharti /* this is the documented fix for the ISW bug 8.1.1 695116491Sharti * Note, that the documented fix is partly wrong: 696116491Sharti * the ISWs should be intialized to 0xf8 not 0xff */ 697116491Sharti sc->istats.bug_bad_isw++; 698116491Sharti DBG(sc, INTR, ("hatm: invalid ISW bug triggered")); 699116491Sharti he_intr_tbrq(sc, &sc->tbrq, 0); 700116491Sharti he_intr_rbp(sc, &sc->rbp_s0, 0, 0); 701116491Sharti he_intr_rbp(sc, &sc->rbp_l0, 1, 0); 702116491Sharti he_intr_rbp(sc, &sc->rbp_s1, 0, 1); 703116491Sharti he_intr_rbrq(sc, &sc->rbrq_0, 0); 704116491Sharti he_intr_rbrq(sc, &sc->rbrq_1, 1); 705116491Sharti utopia_intr(&sc->utopia); 706116491Sharti break; 707116491Sharti 708116491Sharti default: 709116491Sharti if_printf(&sc->ifatm.ifnet, "bad interrupt type %08x\n", 710116491Sharti status); 711116491Sharti break; 712116491Sharti } 713116491Sharti } 714116491Sharti 715116491Sharti /* write back head to clear queue */ 716116491Sharti WRITE4(sc, HE_REGO_IRQ_HEAD(0), 717116491Sharti ((q->size - 1) << HE_REGS_IRQ_HEAD_SIZE) | 718116491Sharti (q->thresh << HE_REGS_IRQ_HEAD_THRESH) | 719116491Sharti (q->head << HE_REGS_IRQ_HEAD_HEAD)); 720116491Sharti BARRIER_W(sc); 721116491Sharti 722116491Sharti /* workaround the back-to-back irq access problem (8.1.2) */ 723116491Sharti (void)READ4(sc, HE_REGO_INT_FIFO); 724116491Sharti BARRIER_R(sc); 725116491Sharti 726116491Sharti mtx_unlock(&sc->mtx); 727116491Sharti} 728