10SN/A/*- 217205Sihse * Copyright (c) 2003 30SN/A * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 40SN/A * All rights reserved. 50SN/A * 60SN/A * Redistribution and use in source and binary forms, with or without 72362SN/A * modification, are permitted provided that the following conditions 80SN/A * are met: 92362SN/A * 1. Redistributions of source code must retain the above copyright 100SN/A * notice, this list of conditions and the following disclaimer. 110SN/A * 2. Redistributions in binary form must reproduce the above copyright 120SN/A * notice, this list of conditions and the following disclaimer in the 130SN/A * documentation and/or other materials provided with the distribution. 140SN/A * 150SN/A * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 160SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 170SN/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 180SN/A * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 190SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 200SN/A * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 212362SN/A * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 222362SN/A * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 232362SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 240SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 250SN/A * SUCH DAMAGE. 260SN/A * 270SN/A * Author: Hartmut Brandt <harti@freebsd.org> 280SN/A * 290SN/A * Driver for IDT77252 based cards like ProSum's. 300SN/A */ 310SN/A 320SN/A#include <sys/cdefs.h> 330SN/A__FBSDID("$FreeBSD$"); 340SN/A 350SN/A#include "opt_inet.h" 360SN/A#include "opt_natm.h" 370SN/A 387549SN/A#include <sys/types.h> 390SN/A#include <sys/param.h> 400SN/A#include <sys/systm.h> 410SN/A#include <sys/malloc.h> 420SN/A#include <sys/kernel.h> 430SN/A#include <sys/bus.h> 447549SN/A#include <sys/errno.h> 450SN/A#include <sys/conf.h> 460SN/A#include <sys/module.h> 470SN/A#include <sys/lock.h> 487549SN/A#include <sys/mutex.h> 497549SN/A#include <sys/sysctl.h> 500SN/A#include <sys/queue.h> 510SN/A#include <sys/condvar.h> 520SN/A#include <sys/endian.h> 530SN/A#include <vm/uma.h> 540SN/A 550SN/A#include <sys/sockio.h> 560SN/A#include <sys/mbuf.h> 570SN/A#include <sys/socket.h> 580SN/A 590SN/A#include <net/if.h> 600SN/A#include <net/if_media.h> 610SN/A#include <net/if_atm.h> 620SN/A#include <net/route.h> 630SN/A#include <netinet/in.h> 640SN/A#include <netinet/if_atm.h> 650SN/A 660SN/A#include <machine/bus.h> 670SN/A#include <machine/resource.h> 680SN/A#include <sys/bus.h> 690SN/A#include <sys/rman.h> 707549SN/A#include <sys/mbpool.h> 710SN/A 720SN/A#include <dev/utopia/utopia.h> 730SN/A#include <dev/patm/idt77252reg.h> 740SN/A#include <dev/patm/if_patmvar.h> 750SN/A 760SN/Astatic void patm_tst_init(struct patm_softc *sc); 777549SN/Astatic void patm_scd_init(struct patm_softc *sc); 780SN/A 790SN/A/* 807549SN/A * Start the card. This assumes the mutex to be held 810SN/A */ 820SN/Avoid 830SN/Apatm_initialize(struct patm_softc *sc) 840SN/A{ 850SN/A uint32_t cfg; 860SN/A u_int i; 870SN/A 880SN/A patm_debug(sc, ATTACH, "configuring..."); 890SN/A 900SN/A /* clear SRAM */ 911104SN/A for (i = 0; i < sc->mmap->sram * 1024; i += 4) 920SN/A patm_sram_write4(sc, i, 0, 0, 0, 0); 930SN/A patm_scd_init(sc); 940SN/A 957549SN/A /* configuration register. Setting NOIDLE makes the timing wrong! */ 960SN/A cfg = IDT_CFG_TXFIFO9 | IDT_CFG_RXQ512 | PATM_CFG_VPI | 970SN/A /* IDT_CFG_NOIDLE | */ sc->mmap->rxtab; 980SN/A if (!(sc->flags & PATM_UNASS)) 990SN/A cfg |= IDT_CFG_IDLECLP; 1000SN/A patm_nor_write(sc, IDT_NOR_CFG, cfg); 1010SN/A 1020SN/A /* clean all the status queues and the Raw handle */ 1030SN/A memset(sc->tsq, 0, sc->sq_size); 1040SN/A 1050SN/A /* initialize RSQ */ 1060SN/A patm_debug(sc, ATTACH, "RSQ %llx", (unsigned long long)sc->rsq_phy); 1070SN/A patm_nor_write(sc, IDT_NOR_RSQB, sc->rsq_phy); 1087549SN/A patm_nor_write(sc, IDT_NOR_RSQT, sc->rsq_phy); 1097549SN/A patm_nor_write(sc, IDT_NOR_RSQH, 0); 1100SN/A sc->rsq_last = PATM_RSQ_SIZE - 1; 1110SN/A 1120SN/A /* initialize TSTB */ 1130SN/A patm_nor_write(sc, IDT_NOR_TSTB, sc->mmap->tst1base << 2); 1147549SN/A patm_tst_init(sc); 1157549SN/A 1160SN/A /* initialize TSQ */ 1177549SN/A for (i = 0; i < IDT_TSQ_SIZE; i++) 1187549SN/A sc->tsq[i].stamp = htole32(IDT_TSQE_EMPTY); 1197549SN/A patm_nor_write(sc, IDT_NOR_TSQB, sc->tsq_phy); 1200SN/A patm_nor_write(sc, IDT_NOR_TSQH, 0); 1210SN/A patm_nor_write(sc, IDT_NOR_TSQT, 0); 1220SN/A sc->tsq_next = sc->tsq; 1230SN/A 1240SN/A /* GP */ 1250SN/A#if BYTE_ORDER == BIG_ENDIAN && 0 1260SN/A patm_nor_write(sc, IDT_NOR_GP, IDT_GP_BIGE); 1270SN/A#else 1280SN/A patm_nor_write(sc, IDT_NOR_GP, 0); 1290SN/A#endif 1300SN/A 1317549SN/A /* VPM */ 1327549SN/A patm_nor_write(sc, IDT_NOR_VPM, 0); 1330SN/A 1340SN/A /* RxFIFO */ 1350SN/A patm_nor_write(sc, IDT_NOR_RXFD, 1360SN/A IDT_RXFD(sc->mmap->rxfifo_addr, sc->mmap->rxfifo_code)); 1377549SN/A patm_nor_write(sc, IDT_NOR_RXFT, 0); 1387549SN/A patm_nor_write(sc, IDT_NOR_RXFH, 0); 1390SN/A 1407549SN/A /* RAWHND */ 1410SN/A patm_debug(sc, ATTACH, "RWH %llx", 1427549SN/A (unsigned long long)sc->rawhnd_phy); 1437549SN/A patm_nor_write(sc, IDT_NOR_RAWHND, sc->rawhnd_phy); 1440SN/A 1450SN/A /* ABRSTD */ 1460SN/A patm_nor_write(sc, IDT_NOR_ABRSTD, 1470SN/A IDT_ABRSTD(sc->mmap->abrstd_addr, sc->mmap->abrstd_code)); 1480SN/A for (i = 0; i < sc->mmap->abrstd_size; i++) 1490SN/A patm_sram_write(sc, sc->mmap->abrstd_addr + i, 0); 1500SN/A patm_nor_write(sc, IDT_NOR_ABRRQ, 0); 1510SN/A patm_nor_write(sc, IDT_NOR_VBRRQ, 0); 1520SN/A 1530SN/A /* rate tables */ 1540SN/A if (sc->flags & PATM_25M) { 1550SN/A for (i = 0; i < patm_rtables_size; i++) 1567549SN/A patm_sram_write(sc, sc->mmap->rtables + i, 1577549SN/A patm_rtables25[i]); 1580SN/A } else { 1590SN/A for (i = 0; i < patm_rtables_size; i++) 1607549SN/A patm_sram_write(sc, sc->mmap->rtables + i, 1617549SN/A patm_rtables155[i]); 1620SN/A } 1630SN/A patm_nor_write(sc, IDT_NOR_RTBL, sc->mmap->rtables << 2); 1640SN/A 1657549SN/A /* Maximum deficit */ 1667549SN/A patm_nor_write(sc, IDT_NOR_MXDFCT, 32 | IDT_MDFCT_LCI | IDT_MDFCT_LNI); 1670SN/A 1687549SN/A /* Free buffer queues */ 1697549SN/A patm_nor_write(sc, IDT_NOR_FBQP0, 0); 1700SN/A patm_nor_write(sc, IDT_NOR_FBQP1, 0); 1710SN/A patm_nor_write(sc, IDT_NOR_FBQP2, 0); 1720SN/A patm_nor_write(sc, IDT_NOR_FBQP3, 0); 1730SN/A 1740SN/A patm_nor_write(sc, IDT_NOR_FBQWP0, 0); 1750SN/A patm_nor_write(sc, IDT_NOR_FBQWP1, 0); 1760SN/A patm_nor_write(sc, IDT_NOR_FBQWP2, 0); 1770SN/A patm_nor_write(sc, IDT_NOR_FBQWP3, 0); 1780SN/A 1790SN/A patm_nor_write(sc, IDT_NOR_FBQS0, 1800SN/A (SMBUF_THRESHOLD << 28) | 1810SN/A (SMBUF_NI_THRESH << 24) | 1820SN/A (SMBUF_CI_THRESH << 20) | 1837549SN/A SMBUF_CELLS); 1840SN/A patm_nor_write(sc, IDT_NOR_FBQS1, 1853465SN/A (LMBUF_THRESHOLD << 28) | 18617205Sihse (LMBUF_NI_THRESH << 24) | 18717205Sihse (LMBUF_CI_THRESH << 20) | 1880SN/A LMBUF_CELLS); 1890SN/A patm_nor_write(sc, IDT_NOR_FBQS2, 1907549SN/A (VMBUF_THRESHOLD << 28) | VMBUF_CELLS); 1917549SN/A patm_nor_write(sc, IDT_NOR_FBQS3, 0); 1927549SN/A 1930SN/A /* make SCD0 for UBR0 */ 1940SN/A if ((sc->scd0 = patm_scd_alloc(sc)) == NULL) { 1950SN/A patm_printf(sc, "cannot create UBR0 SCD\n"); 1967549SN/A patm_reset(sc); 1977549SN/A return; 1980SN/A } 1997549SN/A sc->scd0->q.ifq_maxlen = PATM_DLFT_MAXQ; 2007549SN/A 2010SN/A patm_scd_setup(sc, sc->scd0); 2020SN/A patm_tct_setup(sc, sc->scd0, NULL); 2030SN/A 2040SN/A patm_debug(sc, ATTACH, "go..."); 2050SN/A 2060SN/A sc->utopia.flags &= ~UTP_FL_POLL_CARRIER; 2070SN/A sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 2080SN/A 2090SN/A /* enable interrupts, Tx and Rx paths */ 2107549SN/A cfg |= IDT_CFG_RXPTH | IDT_CFG_RXIIMM | IDT_CFG_RAWIE | IDT_CFG_RQFIE | 2110SN/A IDT_CFG_TIMOIE | IDT_CFG_FBIE | IDT_CFG_TXENB | IDT_CFG_TXINT | 2120SN/A IDT_CFG_TXUIE | IDT_CFG_TXSFI | IDT_CFG_PHYIE; 2130SN/A patm_nor_write(sc, IDT_NOR_CFG, cfg); 2140SN/A 2150SN/A for (i = 0; i < sc->mmap->max_conn; i++) 2160SN/A if (sc->vccs[i] != NULL) 2177549SN/A patm_load_vc(sc, sc->vccs[i], 1); 2180SN/A 2190SN/A ATMEV_SEND_IFSTATE_CHANGED(IFP2IFATM(sc->ifp), 2207549SN/A sc->utopia.carrier == UTP_CARR_OK); 2210SN/A} 2220SN/A 2230SN/A/* 2247549SN/A * External callable start function 2250SN/A */ 2260SN/Avoid 2270SN/Apatm_init(void *p) 2280SN/A{ 2290SN/A struct patm_softc *sc = p; 2300SN/A 2310SN/A mtx_lock(&sc->mtx); 2320SN/A patm_stop(sc); 2330SN/A patm_initialize(sc); 2340SN/A mtx_unlock(&sc->mtx); 2350SN/A} 2360SN/A 2370SN/A/* 2380SN/A * Stop the interface 2390SN/A */ 2400SN/Avoid 2410SN/Apatm_stop(struct patm_softc *sc) 2420SN/A{ 2430SN/A u_int i; 2440SN/A struct mbuf *m; 2450SN/A struct patm_txmap *map; 2460SN/A struct patm_scd *scd; 2470SN/A 2480SN/A sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2490SN/A sc->utopia.flags |= UTP_FL_POLL_CARRIER; 2507549SN/A 2510SN/A patm_reset(sc); 2520SN/A 2530SN/A mtx_lock(&sc->tst_lock); 2540SN/A i = sc->tst_state; 2550SN/A sc->tst_state = 0; 2560SN/A callout_stop(&sc->tst_callout); 2577549SN/A mtx_unlock(&sc->tst_lock); 2580SN/A 2590SN/A if (i != 0) { 2600SN/A /* this means we are just entering or leaving the timeout. 2610SN/A * wait a little bit. Doing this correctly would be more 2620SN/A * involved */ 2630SN/A DELAY(1000); 2641104SN/A } 2650SN/A 2660SN/A /* 2670SN/A * Give any waiters on closing a VCC a chance. They will stop 2687549SN/A * to wait if they see that IFF_DRV_RUNNING disappeared. 2690SN/A */ 2700SN/A cv_broadcast(&sc->vcc_cv); 2710SN/A 2720SN/A /* free large buffers */ 2730SN/A patm_debug(sc, ATTACH, "freeing large buffers..."); 2740SN/A for (i = 0; i < sc->lbuf_max; i++) 2750SN/A if (sc->lbufs[i].m != NULL) 2760SN/A patm_lbuf_free(sc, &sc->lbufs[i]); 2770SN/A 2780SN/A /* free small buffers that are on the card */ 2790SN/A patm_debug(sc, ATTACH, "freeing small buffers..."); 2800SN/A mbp_card_free(sc->sbuf_pool); 2810SN/A 2827549SN/A /* free aal0 buffers that are on the card */ 2830SN/A patm_debug(sc, ATTACH, "freeing aal0 buffers..."); 2840SN/A mbp_card_free(sc->vbuf_pool); 2850SN/A 2860SN/A /* freeing partial receive chains and reset vcc state */ 2870SN/A for (i = 0; i < sc->mmap->max_conn; i++) { 2880SN/A if (sc->vccs[i] != NULL) { 2897549SN/A if (sc->vccs[i]->chain != NULL) { 2900SN/A m_freem(sc->vccs[i]->chain); 2910SN/A sc->vccs[i]->chain = NULL; 2927549SN/A sc->vccs[i]->last = NULL; 2937549SN/A } 2940SN/A 2950SN/A if (sc->vccs[i]->vflags & (PATM_VCC_RX_CLOSING | 2960SN/A PATM_VCC_TX_CLOSING)) { 2970SN/A uma_zfree(sc->vcc_zone, sc->vccs[i]); 2980SN/A sc->vccs[i] = NULL; 2990SN/A } else { 3000SN/A /* keep */ 3010SN/A sc->vccs[i]->vflags &= ~PATM_VCC_OPEN; 3020SN/A sc->vccs[i]->cps = 0; 3030SN/A sc->vccs[i]->scd = NULL; 3040SN/A } 3050SN/A } 3060SN/A } 3070SN/A 3080SN/A /* stop all active SCDs */ 3090SN/A while ((scd = LIST_FIRST(&sc->scd_list)) != NULL) { 3100SN/A /* free queue packets */ 3110SN/A for (;;) { 3120SN/A _IF_DEQUEUE(&scd->q, m); 3130SN/A if (m == NULL) 3140SN/A break; 3150SN/A m_freem(m); 316 } 317 318 /* free transmitting packets */ 319 for (i = 0; i < IDT_TSQE_TAG_SPACE; i++) { 320 if ((m = scd->on_card[i]) != NULL) { 321 scd->on_card[i] = 0; 322 map = m->m_pkthdr.PH_loc.ptr; 323 324 bus_dmamap_unload(sc->tx_tag, map->map); 325 SLIST_INSERT_HEAD(&sc->tx_maps_free, map, link); 326 m_freem(m); 327 } 328 } 329 patm_scd_free(sc, scd); 330 } 331 sc->scd0 = NULL; 332 333 sc->flags &= ~PATM_CLR; 334 335 /* reset raw cell queue */ 336 sc->rawh = NULL; 337 338 ATMEV_SEND_IFSTATE_CHANGED(IFP2IFATM(sc->ifp), 339 sc->utopia.carrier == UTP_CARR_OK); 340} 341 342/* 343 * Stop the card and reset it 344 */ 345void 346patm_reset(struct patm_softc *sc) 347{ 348 349 patm_debug(sc, ATTACH, "resetting..."); 350 351 patm_nor_write(sc, IDT_NOR_CFG, IDT_CFG_SWRST); 352 DELAY(200); 353 patm_nor_write(sc, IDT_NOR_CFG, 0); 354 DELAY(200); 355 356 patm_nor_write(sc, IDT_NOR_RSQH, 0); 357 patm_nor_write(sc, IDT_NOR_TSQH, 0); 358 359 patm_nor_write(sc, IDT_NOR_GP, IDT_GP_PHY_RST); 360 DELAY(50); 361 patm_nor_write(sc, IDT_NOR_GP, IDT_GP_EEDO | IDT_GP_EECS); 362 DELAY(50); 363} 364 365/* 366 * Initialize the soft TST to contain only ABR scheduling and 367 * write it to SRAM 368 */ 369static void 370patm_tst_init(struct patm_softc *sc) 371{ 372 u_int i; 373 u_int base, idle; 374 375 base = sc->mmap->tst1base; 376 idle = sc->mmap->tst1base + sc->mmap->tst_size; 377 378 /* soft */ 379 for (i = 0; i < sc->mmap->tst_size - 1; i++) 380 sc->tst_soft[i] = IDT_TST_VBR; 381 382 sc->tst_state = 0; 383 sc->tst_jump[0] = base + sc->mmap->tst_size - 1; 384 sc->tst_jump[1] = idle + sc->mmap->tst_size - 1; 385 sc->tst_base[0] = base; 386 sc->tst_base[1] = idle; 387 388 /* TST1 */ 389 for (i = 0; i < sc->mmap->tst_size - 1; i++) 390 patm_sram_write(sc, base + i, IDT_TST_VBR); 391 patm_sram_write(sc, sc->tst_jump[0], IDT_TST_BR | (base << 2)); 392 393 /* TST2 */ 394 for (i = 0; i < sc->mmap->tst_size - 1; i++) 395 patm_sram_write(sc, idle + i, IDT_TST_VBR); 396 patm_sram_write(sc, sc->tst_jump[1], IDT_TST_BR | (idle << 2)); 397 398 sc->tst_free = sc->mmap->tst_size - 1; 399 sc->tst_reserve = sc->tst_free * PATM_TST_RESERVE / 100; 400 sc->bwrem = IFP2IFATM(sc->ifp)->mib.pcr; 401} 402 403/* 404 * Initialize the SCDs. This is done by building a list of all free 405 * SCDs in SRAM. The first word of each potential SCD is used as a 406 * link to the next free SCD. The list is rooted in softc. 407 */ 408static void 409patm_scd_init(struct patm_softc *sc) 410{ 411 u_int s; /* SRAM address of current SCD */ 412 413 sc->scd_free = 0; 414 for (s = sc->mmap->scd_base; s + 12 <= sc->mmap->tst1base; s += 12) { 415 patm_sram_write(sc, s, sc->scd_free); 416 sc->scd_free = s; 417 } 418} 419 420/* 421 * allocate an SCQ 422 */ 423struct patm_scd * 424patm_scd_alloc(struct patm_softc *sc) 425{ 426 u_int sram, next; /* SRAM address of this and next SCD */ 427 int error; 428 void *p; 429 struct patm_scd *scd; 430 bus_dmamap_t map; 431 bus_addr_t phy; 432 433 /* get an SCD from the free list */ 434 if ((sram = sc->scd_free) == 0) 435 return (NULL); 436 next = patm_sram_read(sc, sram); 437 438 /* allocate memory for the queue and our host stuff */ 439 error = bus_dmamem_alloc(sc->scd_tag, &p, BUS_DMA_NOWAIT, &map); 440 if (error != 0) 441 return (NULL); 442 phy = 0x3ff; 443 error = bus_dmamap_load(sc->scd_tag, map, p, sizeof(scd->scq), 444 patm_load_callback, &phy, BUS_DMA_NOWAIT); 445 if (error != 0) { 446 bus_dmamem_free(sc->scd_tag, p, map); 447 return (NULL); 448 } 449 KASSERT((phy & 0x1ff) == 0, ("SCD not aligned %lx", (u_long)phy)); 450 451 scd = p; 452 bzero(scd, sizeof(*scd)); 453 454 scd->sram = sram; 455 scd->phy = phy; 456 scd->map = map; 457 scd->space = IDT_SCQ_SIZE; 458 scd->last_tag = IDT_TSQE_TAG_SPACE - 1; 459 scd->q.ifq_maxlen = PATM_TX_IFQLEN; 460 461 /* remove the scd from the free list */ 462 sc->scd_free = next; 463 LIST_INSERT_HEAD(&sc->scd_list, scd, link); 464 465 return (scd); 466} 467 468/* 469 * Free an SCD 470 */ 471void 472patm_scd_free(struct patm_softc *sc, struct patm_scd *scd) 473{ 474 475 LIST_REMOVE(scd, link); 476 477 /* clear SCD and insert link word */ 478 patm_sram_write4(sc, scd->sram, sc->scd_free, 0, 0, 0); 479 patm_sram_write4(sc, scd->sram, 0, 0, 0, 0); 480 patm_sram_write4(sc, scd->sram, 0, 0, 0, 0); 481 482 /* put on free list */ 483 sc->scd_free = scd->sram; 484 485 /* free memory */ 486 bus_dmamap_unload(sc->scd_tag, scd->map); 487 bus_dmamem_free(sc->scd_tag, scd, scd->map); 488} 489 490/* 491 * DMA loading helper function. This function handles the loading of 492 * all one segment DMA maps. The argument is a pointer to a bus_addr_t 493 * which must contain the desired alignment of the address as a bitmap. 494 */ 495void 496patm_load_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 497{ 498 bus_addr_t *phy = arg; 499 500 if (error) 501 return; 502 503 KASSERT(nsegs == 1, 504 ("too many segments for DMA: %d", nsegs)); 505 KASSERT(segs[0].ds_addr <= 0xffffffffUL, 506 ("phys addr too large %lx", (u_long)segs[0].ds_addr)); 507 KASSERT((segs[0].ds_addr & *phy) == 0, 508 ("bad alignment %lx:%lx", (u_long)segs[0].ds_addr, (u_long)*phy)); 509 510 *phy = segs[0].ds_addr; 511} 512