if_hatm_intr.c revision 119280
1116491Sharti/* 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 * Interrupt handler. 32116491Sharti */ 33116491Sharti 34116519Sharti#include <sys/cdefs.h> 35116519Sharti__FBSDID("$FreeBSD: head/sys/dev/hatm/if_hatm_intr.c 119280 2003-08-22 06:00:27Z imp $"); 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/malloc.h> 44116491Sharti#include <sys/kernel.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> 60116491Sharti#include <net/if_media.h> 61116491Sharti#include <net/if_atm.h> 62116491Sharti#include <net/route.h> 63116491Sharti#include <netinet/in.h> 64116491Sharti#include <netinet/if_atm.h> 65116491Sharti 66116491Sharti#include <machine/bus.h> 67116491Sharti#include <machine/resource.h> 68116491Sharti#include <sys/bus.h> 69116491Sharti#include <sys/rman.h> 70119280Simp#include <dev/pci/pcireg.h> 71119280Simp#include <dev/pci/pcivar.h> 72116491Sharti 73116491Sharti#include <dev/utopia/utopia.h> 74116491Sharti#include <dev/hatm/if_hatmconf.h> 75116491Sharti#include <dev/hatm/if_hatmreg.h> 76116491Sharti#include <dev/hatm/if_hatmvar.h> 77116491Sharti 78116491ShartiCTASSERT(sizeof(struct mbuf_page) == MBUF_ALLOC_SIZE); 79116491ShartiCTASSERT(sizeof(struct mbuf0_chunk) == MBUF0_CHUNK); 80116491ShartiCTASSERT(sizeof(struct mbuf1_chunk) == MBUF1_CHUNK); 81116491ShartiCTASSERT(sizeof(((struct mbuf0_chunk *)NULL)->storage) >= MBUF0_SIZE); 82116491ShartiCTASSERT(sizeof(((struct mbuf1_chunk *)NULL)->storage) >= MBUF1_SIZE); 83116491ShartiCTASSERT(sizeof(struct tpd) <= HE_TPD_SIZE); 84116491Sharti 85116491Sharti/* 86116491Sharti * Either the queue treshold was crossed or a TPD with the INTR bit set 87116491Sharti * was transmitted. 88116491Sharti */ 89116491Shartistatic void 90116491Shartihe_intr_tbrq(struct hatm_softc *sc, struct hetbrq *q, u_int group) 91116491Sharti{ 92116491Sharti uint32_t *tailp = &sc->hsp->group[group].tbrq_tail; 93116491Sharti u_int no; 94116491Sharti 95116491Sharti while (q->head != (*tailp >> 2)) { 96116491Sharti no = (q->tbrq[q->head].addr & HE_REGM_TBRQ_ADDR) >> 97116491Sharti HE_REGS_TPD_ADDR; 98116491Sharti hatm_tx_complete(sc, TPD_ADDR(sc, no), 99116491Sharti (q->tbrq[q->head].addr & HE_REGM_TBRQ_FLAGS)); 100116491Sharti 101116491Sharti if (++q->head == q->size) 102116491Sharti q->head = 0; 103116491Sharti } 104116491Sharti WRITE4(sc, HE_REGO_TBRQ_H(group), q->head << 2); 105116491Sharti} 106116491Sharti 107116491Sharti/* 108116491Sharti * DMA loader function for external mbuf page. 109116491Sharti */ 110116491Shartistatic void 111116491Shartihatm_extbuf_helper(void *arg, bus_dma_segment_t *segs, int nsegs, 112116491Sharti int error) 113116491Sharti{ 114116491Sharti if (error) { 115116491Sharti printf("%s: mapping error %d\n", __func__, error); 116116491Sharti return; 117116491Sharti } 118116491Sharti KASSERT(nsegs == 1, 119116491Sharti ("too many segments for DMA: %d", nsegs)); 120116491Sharti KASSERT(segs[0].ds_addr <= 0xffffffffLU, 121116491Sharti ("phys addr too large %lx", (u_long)segs[0].ds_addr)); 122116491Sharti 123116491Sharti *(uint32_t *)arg = segs[0].ds_addr; 124116491Sharti} 125116491Sharti 126116491Sharti/* 127116491Sharti * Allocate a page of external mbuf storage for the small pools. 128116491Sharti * Create a DMA map and load it. Put all the chunks onto the right 129116491Sharti * free list. 130116491Sharti */ 131116491Shartistatic void 132116491Shartihatm_mbuf_page_alloc(struct hatm_softc *sc, u_int group) 133116491Sharti{ 134116491Sharti struct mbuf_page *pg; 135116491Sharti int err; 136116491Sharti u_int i; 137116491Sharti 138116491Sharti if (sc->mbuf_npages == HE_CONFIG_MAX_MBUF_PAGES) 139116491Sharti return; 140116491Sharti if ((pg = malloc(MBUF_ALLOC_SIZE, M_DEVBUF, M_NOWAIT)) == NULL) 141116491Sharti return; 142116491Sharti bzero(pg->hdr.card, sizeof(pg->hdr.card)); 143116491Sharti bzero(pg->hdr.used, sizeof(pg->hdr.used)); 144116491Sharti 145116491Sharti err = bus_dmamap_create(sc->mbuf_tag, 0, &pg->hdr.map); 146116491Sharti if (err != 0) { 147116491Sharti if_printf(&sc->ifatm.ifnet, "%s -- bus_dmamap_create: %d\n", 148116491Sharti __func__, err); 149116491Sharti free(pg, M_DEVBUF); 150116491Sharti return; 151116491Sharti } 152116491Sharti err = bus_dmamap_load(sc->mbuf_tag, pg->hdr.map, pg, MBUF_ALLOC_SIZE, 153117382Sharti hatm_extbuf_helper, &pg->hdr.phys, BUS_DMA_NOWAIT); 154116491Sharti if (err != 0) { 155116491Sharti if_printf(&sc->ifatm.ifnet, "%s -- mbuf mapping failed %d\n", 156116491Sharti __func__, err); 157116491Sharti bus_dmamap_destroy(sc->mbuf_tag, pg->hdr.map); 158116491Sharti free(pg, M_DEVBUF); 159116491Sharti return; 160116491Sharti } 161116491Sharti 162116491Sharti sc->mbuf_pages[sc->mbuf_npages] = pg; 163116491Sharti 164116491Sharti if (group == 0) { 165116491Sharti struct mbuf0_chunk *c; 166116491Sharti 167116491Sharti pg->hdr.nchunks = MBUF0_PER_PAGE; 168116491Sharti pg->hdr.chunksize = MBUF0_CHUNK; 169116491Sharti pg->hdr.hdroff = sizeof(c->storage); 170116491Sharti c = (struct mbuf0_chunk *)pg; 171116491Sharti for (i = 0; i < MBUF0_PER_PAGE; i++, c++) { 172116491Sharti c->hdr.pageno = sc->mbuf_npages; 173116491Sharti c->hdr.chunkno = i; 174116491Sharti SLIST_INSERT_HEAD(&sc->mbuf0_list, 175116491Sharti (struct mbufx_free *)c, link); 176116491Sharti } 177116491Sharti } else { 178116491Sharti struct mbuf1_chunk *c; 179116491Sharti 180116491Sharti pg->hdr.nchunks = MBUF1_PER_PAGE; 181116491Sharti pg->hdr.chunksize = MBUF1_CHUNK; 182116491Sharti pg->hdr.hdroff = sizeof(c->storage); 183116491Sharti c = (struct mbuf1_chunk *)pg; 184116491Sharti for (i = 0; i < MBUF1_PER_PAGE; i++, c++) { 185116491Sharti c->hdr.pageno = sc->mbuf_npages; 186116491Sharti c->hdr.chunkno = i; 187116491Sharti SLIST_INSERT_HEAD(&sc->mbuf1_list, 188116491Sharti (struct mbufx_free *)c, link); 189116491Sharti } 190116491Sharti } 191116491Sharti sc->mbuf_npages++; 192116491Sharti} 193116491Sharti 194116491Sharti/* 195116491Sharti * Free an mbuf and put it onto the free list. 196116491Sharti */ 197116491Shartistatic void 198116491Shartihatm_mbuf0_free(void *buf, void *args) 199116491Sharti{ 200116491Sharti struct hatm_softc *sc = args; 201116491Sharti struct mbuf0_chunk *c = buf; 202116491Sharti 203116491Sharti mtx_lock(&sc->mbuf0_mtx); 204116491Sharti SLIST_INSERT_HEAD(&sc->mbuf0_list, (struct mbufx_free *)c, link); 205116491Sharti MBUF_CLR_BIT(sc->mbuf_pages[c->hdr.pageno]->hdr.used, c->hdr.chunkno); 206116491Sharti mtx_unlock(&sc->mbuf0_mtx); 207116491Sharti} 208116491Shartistatic void 209116491Shartihatm_mbuf1_free(void *buf, void *args) 210116491Sharti{ 211116491Sharti struct hatm_softc *sc = args; 212116491Sharti struct mbuf1_chunk *c = buf; 213116491Sharti 214116491Sharti mtx_lock(&sc->mbuf1_mtx); 215116491Sharti SLIST_INSERT_HEAD(&sc->mbuf1_list, (struct mbufx_free *)c, link); 216116491Sharti MBUF_CLR_BIT(sc->mbuf_pages[c->hdr.pageno]->hdr.used, c->hdr.chunkno); 217116491Sharti mtx_unlock(&sc->mbuf1_mtx); 218116491Sharti} 219116491Sharti 220116491Sharti/* 221116491Sharti * Allocate an external mbuf storage 222116491Sharti */ 223116491Shartistatic int 224116491Shartihatm_mbuf_alloc(struct hatm_softc *sc, u_int group, struct mbuf *m, 225116491Sharti uint32_t *phys, uint32_t *handle) 226116491Sharti{ 227116491Sharti struct mbufx_free *cf; 228116491Sharti struct mbuf_page *pg; 229116491Sharti 230116491Sharti if (group == 0) { 231116491Sharti struct mbuf0_chunk *buf0; 232116491Sharti 233116491Sharti mtx_lock(&sc->mbuf0_mtx); 234116491Sharti if ((cf = SLIST_FIRST(&sc->mbuf0_list)) == NULL) { 235116491Sharti hatm_mbuf_page_alloc(sc, group); 236116491Sharti if ((cf = SLIST_FIRST(&sc->mbuf0_list)) == NULL) { 237116491Sharti mtx_unlock(&sc->mbuf0_mtx); 238116491Sharti return (0); 239116491Sharti } 240116491Sharti } 241116491Sharti SLIST_REMOVE_HEAD(&sc->mbuf0_list, link); 242116491Sharti buf0 = (struct mbuf0_chunk *)cf; 243116491Sharti pg = sc->mbuf_pages[buf0->hdr.pageno]; 244116491Sharti MBUF_SET_BIT(pg->hdr.card, buf0->hdr.chunkno); 245116491Sharti mtx_unlock(&sc->mbuf0_mtx); 246116491Sharti 247116491Sharti m_extadd(m, (caddr_t)buf0, MBUF0_SIZE, hatm_mbuf0_free, sc, 248116491Sharti M_PKTHDR, EXT_NET_DRV); 249116491Sharti m->m_data += MBUF0_OFFSET; 250116491Sharti buf0->hdr.mbuf = m; 251116491Sharti 252116491Sharti *handle = MBUF_MAKE_HANDLE(buf0->hdr.pageno, buf0->hdr.chunkno); 253116491Sharti 254116491Sharti } else if (group == 1) { 255116491Sharti struct mbuf1_chunk *buf1; 256116491Sharti 257116491Sharti mtx_lock(&sc->mbuf1_mtx); 258116491Sharti if ((cf = SLIST_FIRST(&sc->mbuf1_list)) == NULL) { 259116491Sharti hatm_mbuf_page_alloc(sc, group); 260116491Sharti if ((cf = SLIST_FIRST(&sc->mbuf1_list)) == NULL) { 261116491Sharti mtx_unlock(&sc->mbuf1_mtx); 262116491Sharti return (0); 263116491Sharti } 264116491Sharti } 265116491Sharti SLIST_REMOVE_HEAD(&sc->mbuf1_list, link); 266116491Sharti buf1 = (struct mbuf1_chunk *)cf; 267116491Sharti pg = sc->mbuf_pages[buf1->hdr.pageno]; 268116491Sharti MBUF_SET_BIT(pg->hdr.card, buf1->hdr.chunkno); 269116491Sharti mtx_unlock(&sc->mbuf1_mtx); 270116491Sharti 271116491Sharti m_extadd(m, (caddr_t)buf1, MBUF1_SIZE, hatm_mbuf1_free, sc, 272116491Sharti M_PKTHDR, EXT_NET_DRV); 273116491Sharti m->m_data += MBUF1_OFFSET; 274116491Sharti buf1->hdr.mbuf = m; 275116491Sharti 276116491Sharti *handle = MBUF_MAKE_HANDLE(buf1->hdr.pageno, buf1->hdr.chunkno); 277116491Sharti 278116491Sharti } else 279116491Sharti return (-1); 280116491Sharti 281116491Sharti *phys = pg->hdr.phys + (mtod(m, char *) - (char *)pg); 282116491Sharti bus_dmamap_sync(sc->mbuf_tag, pg->hdr.map, BUS_DMASYNC_PREREAD); 283116491Sharti 284116491Sharti return (0); 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{ 311116491Sharti u_int ntail, upd; 312116491Sharti struct mbuf *m; 313116491Sharti int error; 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 upd = 0; 322116491Sharti for (;;) { 323116491Sharti if ((ntail = rbp->tail + 1) == rbp->size) 324116491Sharti ntail = 0; 325116491Sharti if (ntail == rbp->head) 326116491Sharti break; 327116491Sharti 328116491Sharti /* allocate the MBUF */ 329116491Sharti if (large) { 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 352116491Sharti rbp->rbp[rbp->tail].handle = sc->lbufs_next | 353116491Sharti MBUF_LARGE_FLAG; 354116491Sharti 355116491Sharti if (++sc->lbufs_next == sc->lbufs_size) 356116491Sharti sc->lbufs_next = 0; 357116491Sharti 358116491Sharti } else { 359116491Sharti MGETHDR(m, M_DONTWAIT, MT_DATA); 360116491Sharti if (m == NULL) { 361116491Sharti if_printf(&sc->ifatm.ifnet, "no mbufs\n"); 362116491Sharti break; 363116491Sharti } 364116491Sharti if (hatm_mbuf_alloc(sc, group, m, 365116491Sharti &rbp->rbp[rbp->tail].phys, 366116491Sharti &rbp->rbp[rbp->tail].handle)) { 367116491Sharti m_freem(m); 368116491Sharti break; 369116491Sharti } 370116491Sharti } 371116491Sharti DBG(sc, DMA, ("MBUF loaded: handle=%x m=%p phys=%x", 372116491Sharti rbp->rbp[rbp->tail].handle, m, rbp->rbp[rbp->tail].phys)); 373116491Sharti rbp->rbp[rbp->tail].handle <<= HE_REGS_RBRQ_ADDR; 374116491Sharti 375116491Sharti rbp->tail = ntail; 376116491Sharti upd++; 377116491Sharti } 378116491Sharti if (upd) { 379116491Sharti WRITE4(sc, HE_REGO_RBP_T(large, group), 380116491Sharti (rbp->tail << HE_REGS_RBP_TAIL)); 381116491Sharti } 382116491Sharti} 383116491Sharti 384116491Sharti/* 385116491Sharti * Extract the buffer and hand it to the receive routine 386116491Sharti */ 387116491Shartistatic struct mbuf * 388116491Shartihatm_rx_buffer(struct hatm_softc *sc, u_int group, u_int handle) 389116491Sharti{ 390116491Sharti u_int pageno; 391116491Sharti u_int chunkno; 392116491Sharti struct mbuf *m; 393116491Sharti 394116491Sharti if (handle & MBUF_LARGE_FLAG) { 395116491Sharti /* large buffer - sync and unload */ 396116491Sharti handle &= ~MBUF_LARGE_FLAG; 397116491Sharti DBG(sc, RX, ("RX large handle=%x", handle)); 398116491Sharti 399116491Sharti bus_dmamap_sync(sc->mbuf_tag, sc->rmaps[handle], 400116491Sharti BUS_DMASYNC_POSTREAD); 401116491Sharti bus_dmamap_unload(sc->mbuf_tag, sc->rmaps[handle]); 402116491Sharti 403116491Sharti m = sc->lbufs[handle]; 404116491Sharti sc->lbufs[handle] = NULL; 405116491Sharti 406116491Sharti return (m); 407116491Sharti } 408116491Sharti 409116491Sharti MBUF_PARSE_HANDLE(handle, pageno, chunkno); 410116491Sharti 411116491Sharti DBG(sc, RX, ("RX group=%u handle=%x page=%u chunk=%u", group, handle, 412116491Sharti pageno, chunkno)); 413116491Sharti 414116491Sharti if (group == 0) { 415116491Sharti struct mbuf0_chunk *c0; 416116491Sharti 417116491Sharti c0 = (struct mbuf0_chunk *)sc->mbuf_pages[pageno] + chunkno; 418116491Sharti KASSERT(c0->hdr.pageno == pageno, ("pageno = %u/%u", 419116491Sharti c0->hdr.pageno, pageno)); 420116491Sharti KASSERT(c0->hdr.chunkno == chunkno, ("chunkno = %u/%u", 421116491Sharti c0->hdr.chunkno, chunkno)); 422116491Sharti 423116491Sharti m = c0->hdr.mbuf; 424116491Sharti 425116491Sharti } else { 426116491Sharti struct mbuf1_chunk *c1; 427116491Sharti 428116491Sharti c1 = (struct mbuf1_chunk *)sc->mbuf_pages[pageno] + chunkno; 429116491Sharti KASSERT(c1->hdr.pageno == pageno, ("pageno = %u/%u", 430116491Sharti c1->hdr.pageno, pageno)); 431116491Sharti KASSERT(c1->hdr.chunkno == chunkno, ("chunkno = %u/%u", 432116491Sharti c1->hdr.chunkno, chunkno)); 433116491Sharti 434116491Sharti m = c1->hdr.mbuf; 435116491Sharti } 436116491Sharti MBUF_CLR_BIT(sc->mbuf_pages[pageno]->hdr.card, chunkno); 437116491Sharti MBUF_SET_BIT(sc->mbuf_pages[pageno]->hdr.used, chunkno); 438116491Sharti 439116491Sharti bus_dmamap_sync(sc->mbuf_tag, sc->mbuf_pages[pageno]->hdr.map, 440116491Sharti BUS_DMASYNC_POSTREAD); 441116491Sharti 442116491Sharti return (m); 443116491Sharti} 444116491Sharti 445116491Sharti/* 446116491Sharti * Interrupt because of receive buffer returned. 447116491Sharti */ 448116491Shartistatic void 449116491Shartihe_intr_rbrq(struct hatm_softc *sc, struct herbrq *rq, u_int group) 450116491Sharti{ 451116491Sharti struct he_rbrqen *e; 452116491Sharti uint32_t flags, tail; 453116491Sharti u_int cid, len; 454116491Sharti struct mbuf *m; 455116491Sharti 456116491Sharti for (;;) { 457116491Sharti tail = sc->hsp->group[group].rbrq_tail >> 3; 458116491Sharti 459116491Sharti if (rq->head == tail) 460116491Sharti break; 461116491Sharti 462116491Sharti e = &rq->rbrq[rq->head]; 463116491Sharti 464116491Sharti flags = e->addr & HE_REGM_RBRQ_FLAGS; 465116491Sharti if (!(flags & HE_REGM_RBRQ_HBUF_ERROR)) 466116491Sharti m = hatm_rx_buffer(sc, group, 467116491Sharti (e->addr & HE_REGM_RBRQ_ADDR) >> HE_REGS_RBRQ_ADDR); 468116491Sharti else 469116491Sharti m = NULL; 470116491Sharti 471116491Sharti cid = (e->len & HE_REGM_RBRQ_CID) >> HE_REGS_RBRQ_CID; 472116491Sharti len = 4 * (e->len & HE_REGM_RBRQ_LEN); 473116491Sharti 474116491Sharti hatm_rx(sc, cid, flags, m, len); 475116491Sharti 476116491Sharti if (++rq->head == rq->size) 477116491Sharti rq->head = 0; 478116491Sharti } 479116491Sharti WRITE4(sc, HE_REGO_RBRQ_H(group), rq->head << 3); 480116491Sharti} 481116491Sharti 482116491Shartivoid 483116491Shartihatm_intr(void *p) 484116491Sharti{ 485116491Sharti struct heirq *q = p; 486116491Sharti struct hatm_softc *sc = q->sc; 487116491Sharti u_int status; 488116491Sharti u_int tail; 489116491Sharti 490116491Sharti /* if we have a stray interrupt with a non-initialized card, 491116491Sharti * we cannot even lock before looking at the flag */ 492116491Sharti if (!(sc->ifatm.ifnet.if_flags & IFF_RUNNING)) 493116491Sharti return; 494116491Sharti 495116491Sharti mtx_lock(&sc->mtx); 496116491Sharti (void)READ4(sc, HE_REGO_INT_FIFO); 497116491Sharti 498116491Sharti tail = *q->tailp; 499116491Sharti if (q->head == tail) { 500116491Sharti /* workaround for tail pointer not updated bug (8.1.1) */ 501116491Sharti DBG(sc, INTR, ("hatm: intr tailq not updated bug triggered")); 502116491Sharti 503116491Sharti /* read the tail pointer from the card */ 504116491Sharti tail = READ4(sc, HE_REGO_IRQ_BASE(q->group)) & 505116491Sharti HE_REGM_IRQ_BASE_TAIL; 506116491Sharti BARRIER_R(sc); 507116491Sharti 508116491Sharti sc->istats.bug_no_irq_upd++; 509116491Sharti } 510116491Sharti 511116491Sharti /* clear the interrupt */ 512116491Sharti WRITE4(sc, HE_REGO_INT_FIFO, HE_REGM_INT_FIFO_CLRA); 513116491Sharti BARRIER_W(sc); 514116491Sharti 515116491Sharti while (q->head != tail) { 516116491Sharti status = q->irq[q->head]; 517116491Sharti q->irq[q->head] = HE_REGM_ITYPE_INVALID; 518116491Sharti if (++q->head == (q->size - 1)) 519116491Sharti q->head = 0; 520116491Sharti 521116491Sharti switch (status & HE_REGM_ITYPE) { 522116491Sharti 523116491Sharti case HE_REGM_ITYPE_TBRQ: 524116491Sharti DBG(sc, INTR, ("TBRQ treshold %u", status & HE_REGM_IGROUP)); 525116491Sharti sc->istats.itype_tbrq++; 526116491Sharti he_intr_tbrq(sc, &sc->tbrq, status & HE_REGM_IGROUP); 527116491Sharti break; 528116491Sharti 529116491Sharti case HE_REGM_ITYPE_TPD: 530116491Sharti DBG(sc, INTR, ("TPD ready %u", status & HE_REGM_IGROUP)); 531116491Sharti sc->istats.itype_tpd++; 532116491Sharti he_intr_tbrq(sc, &sc->tbrq, status & HE_REGM_IGROUP); 533116491Sharti break; 534116491Sharti 535116491Sharti case HE_REGM_ITYPE_RBPS: 536116491Sharti sc->istats.itype_rbps++; 537116491Sharti switch (status & HE_REGM_IGROUP) { 538116491Sharti 539116491Sharti case 0: 540116491Sharti he_intr_rbp(sc, &sc->rbp_s0, 0, 0); 541116491Sharti break; 542116491Sharti 543116491Sharti case 1: 544116491Sharti he_intr_rbp(sc, &sc->rbp_s1, 0, 1); 545116491Sharti break; 546116491Sharti 547116491Sharti default: 548116491Sharti if_printf(&sc->ifatm.ifnet, "bad INTR RBPS%u\n", 549116491Sharti status & HE_REGM_IGROUP); 550116491Sharti break; 551116491Sharti } 552116491Sharti break; 553116491Sharti 554116491Sharti case HE_REGM_ITYPE_RBPL: 555116491Sharti sc->istats.itype_rbpl++; 556116491Sharti switch (status & HE_REGM_IGROUP) { 557116491Sharti 558116491Sharti case 0: 559116491Sharti he_intr_rbp(sc, &sc->rbp_l0, 1, 0); 560116491Sharti break; 561116491Sharti 562116491Sharti default: 563116491Sharti if_printf(&sc->ifatm.ifnet, "bad INTR RBPL%u\n", 564116491Sharti status & HE_REGM_IGROUP); 565116491Sharti break; 566116491Sharti } 567116491Sharti break; 568116491Sharti 569116491Sharti case HE_REGM_ITYPE_RBRQ: 570116491Sharti DBG(sc, INTR, ("INTERRUPT RBRQ %u", status & HE_REGM_IGROUP)); 571116491Sharti sc->istats.itype_rbrq++; 572116491Sharti switch (status & HE_REGM_IGROUP) { 573116491Sharti 574116491Sharti case 0: 575116491Sharti he_intr_rbrq(sc, &sc->rbrq_0, 0); 576116491Sharti break; 577116491Sharti 578116491Sharti case 1: 579116491Sharti if (sc->rbrq_1.size > 0) { 580116491Sharti he_intr_rbrq(sc, &sc->rbrq_1, 1); 581116491Sharti break; 582116491Sharti } 583116491Sharti /* FALLTHRU */ 584116491Sharti 585116491Sharti default: 586116491Sharti if_printf(&sc->ifatm.ifnet, "bad INTR RBRQ%u\n", 587116491Sharti status & HE_REGM_IGROUP); 588116491Sharti break; 589116491Sharti } 590116491Sharti break; 591116491Sharti 592116491Sharti case HE_REGM_ITYPE_RBRQT: 593116491Sharti DBG(sc, INTR, ("INTERRUPT RBRQT %u", status & HE_REGM_IGROUP)); 594116491Sharti sc->istats.itype_rbrqt++; 595116491Sharti switch (status & HE_REGM_IGROUP) { 596116491Sharti 597116491Sharti case 0: 598116491Sharti he_intr_rbrq(sc, &sc->rbrq_0, 0); 599116491Sharti break; 600116491Sharti 601116491Sharti case 1: 602116491Sharti if (sc->rbrq_1.size > 0) { 603116491Sharti he_intr_rbrq(sc, &sc->rbrq_1, 1); 604116491Sharti break; 605116491Sharti } 606116491Sharti /* FALLTHRU */ 607116491Sharti 608116491Sharti default: 609116491Sharti if_printf(&sc->ifatm.ifnet, "bad INTR RBRQT%u\n", 610116491Sharti status & HE_REGM_IGROUP); 611116491Sharti break; 612116491Sharti } 613116491Sharti break; 614116491Sharti 615116491Sharti case HE_REGM_ITYPE_PHYS: 616116491Sharti sc->istats.itype_phys++; 617116491Sharti utopia_intr(&sc->utopia); 618116491Sharti break; 619116491Sharti 620116491Sharti#if HE_REGM_ITYPE_UNKNOWN != HE_REGM_ITYPE_INVALID 621116491Sharti case HE_REGM_ITYPE_UNKNOWN: 622116491Sharti sc->istats.itype_unknown++; 623116491Sharti if_printf(&sc->ifatm.ifnet, "bad interrupt\n"); 624116491Sharti break; 625116491Sharti#endif 626116491Sharti 627116491Sharti case HE_REGM_ITYPE_ERR: 628116491Sharti sc->istats.itype_err++; 629116491Sharti switch (status) { 630116491Sharti 631116491Sharti case HE_REGM_ITYPE_PERR: 632116491Sharti if_printf(&sc->ifatm.ifnet, "parity error\n"); 633116491Sharti break; 634116491Sharti 635116491Sharti case HE_REGM_ITYPE_ABORT: 636116491Sharti if_printf(&sc->ifatm.ifnet, "abort interrupt " 637116491Sharti "addr=0x%08x\n", 638116491Sharti READ4(sc, HE_REGO_ABORT_ADDR)); 639116491Sharti break; 640116491Sharti 641116491Sharti default: 642116491Sharti if_printf(&sc->ifatm.ifnet, 643116491Sharti "bad interrupt type %08x\n", status); 644116491Sharti break; 645116491Sharti } 646116491Sharti break; 647116491Sharti 648116491Sharti case HE_REGM_ITYPE_INVALID: 649116491Sharti /* this is the documented fix for the ISW bug 8.1.1 650116491Sharti * Note, that the documented fix is partly wrong: 651116491Sharti * the ISWs should be intialized to 0xf8 not 0xff */ 652116491Sharti sc->istats.bug_bad_isw++; 653116491Sharti DBG(sc, INTR, ("hatm: invalid ISW bug triggered")); 654116491Sharti he_intr_tbrq(sc, &sc->tbrq, 0); 655116491Sharti he_intr_rbp(sc, &sc->rbp_s0, 0, 0); 656116491Sharti he_intr_rbp(sc, &sc->rbp_l0, 1, 0); 657116491Sharti he_intr_rbp(sc, &sc->rbp_s1, 0, 1); 658116491Sharti he_intr_rbrq(sc, &sc->rbrq_0, 0); 659116491Sharti he_intr_rbrq(sc, &sc->rbrq_1, 1); 660116491Sharti utopia_intr(&sc->utopia); 661116491Sharti break; 662116491Sharti 663116491Sharti default: 664116491Sharti if_printf(&sc->ifatm.ifnet, "bad interrupt type %08x\n", 665116491Sharti status); 666116491Sharti break; 667116491Sharti } 668116491Sharti } 669116491Sharti 670116491Sharti /* write back head to clear queue */ 671116491Sharti WRITE4(sc, HE_REGO_IRQ_HEAD(0), 672116491Sharti ((q->size - 1) << HE_REGS_IRQ_HEAD_SIZE) | 673116491Sharti (q->thresh << HE_REGS_IRQ_HEAD_THRESH) | 674116491Sharti (q->head << HE_REGS_IRQ_HEAD_HEAD)); 675116491Sharti BARRIER_W(sc); 676116491Sharti 677116491Sharti /* workaround the back-to-back irq access problem (8.1.2) */ 678116491Sharti (void)READ4(sc, HE_REGO_INT_FIFO); 679116491Sharti BARRIER_R(sc); 680116491Sharti 681116491Sharti mtx_unlock(&sc->mtx); 682116491Sharti} 683