1/* $NetBSD: iavc_pci.c,v 1.12 2009/11/26 15:17:09 njoly Exp $ */ 2 3/* 4 * Copyright (c) 2001-2003 Cubical Solutions Ltd. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * capi/iavc/iavc_pci.c 29 * The AVM ISDN controllers' PCI bus attachment handling. 30 * 31 * $FreeBSD: src/sys/i4b/capi/iavc/iavc_pci.c,v 1.1.2.1 2001/08/10 14:08:34 obrien Exp $ 32 */ 33 34#include <sys/cdefs.h> 35__KERNEL_RCSID(0, "$NetBSD: iavc_pci.c,v 1.12 2009/11/26 15:17:09 njoly Exp $"); 36 37#include <sys/param.h> 38#include <sys/kernel.h> 39#include <sys/systm.h> 40#include <sys/mbuf.h> 41#include <sys/callout.h> 42#include <sys/socket.h> 43#include <sys/device.h> 44#include <net/if.h> 45 46#include <sys/bus.h> 47 48#include <dev/pci/pcireg.h> 49#include <dev/pci/pcivar.h> 50#include <dev/pci/pcidevs.h> 51 52#include <netisdn/i4b_ioctl.h> 53#include <netisdn/i4b_l3l4.h> 54#include <netisdn/i4b_capi.h> 55 56#include <dev/ic/iavcvar.h> 57#include <dev/ic/iavcreg.h> 58 59struct iavc_pci_softc { 60 struct iavc_softc sc_iavc; 61 62 bus_addr_t mem_base; 63 bus_size_t mem_size; 64 bus_addr_t io_base; 65 bus_size_t io_size; 66 67 pci_chipset_tag_t sc_pc; 68 69 void *sc_ih; /* interrupt handler */ 70}; 71#define IAVC_PCI_IOBA 0x14 72#define IAVC_PCI_MMBA 0x10 73 74/* PCI driver linkage */ 75 76static const struct iavc_pci_product *find_cardname(struct pci_attach_args *); 77 78static int iavc_pci_probe(device_t, cfdata_t, void *); 79static void iavc_pci_attach(device_t, device_t, void *); 80 81int iavc_pci_intr(void *); 82 83CFATTACH_DECL(iavc_pci, sizeof(struct iavc_pci_softc), 84 iavc_pci_probe, iavc_pci_attach, NULL, NULL); 85 86static const struct iavc_pci_product { 87 pci_vendor_id_t npp_vendor; 88 pci_product_id_t npp_product; 89 const char *name; 90} iavc_pci_products[] = { 91 { PCI_VENDOR_AVM, PCI_PRODUCT_AVM_B1, "AVM B1 PCI" }, 92 { PCI_VENDOR_AVM, PCI_PRODUCT_AVM_T1, "AVM T1 PCI" }, 93 { 0, 0, NULL }, 94}; 95 96static const struct iavc_pci_product * 97find_cardname(struct pci_attach_args * pa) 98{ 99 const struct iavc_pci_product *pp = NULL; 100 101 for (pp = iavc_pci_products; pp->npp_vendor; pp++) { 102 if (PCI_VENDOR(pa->pa_id) == pp->npp_vendor && 103 PCI_PRODUCT(pa->pa_id) == pp->npp_product) 104 return pp; 105 } 106 107 return NULL; 108} 109 110static int 111iavc_pci_probe(device_t parent, cfdata_t match, void *aux) 112{ 113 struct pci_attach_args *pa = aux; 114 115 if (find_cardname(pa)) 116 return 1; 117 118 return 0; 119} 120 121static void 122iavc_pci_attach(device_t parent, device_t self, void *aux) 123{ 124 struct iavc_pci_softc *psc = device_private(self); 125 struct iavc_softc *sc = &psc->sc_iavc; 126 struct pci_attach_args *pa = aux; 127 pci_chipset_tag_t pc = pa->pa_pc; 128 const struct iavc_pci_product *pp; 129 pci_intr_handle_t ih; 130 const char *intrstr; 131 int ret; 132 133 pp = find_cardname(pa); 134 if (pp == NULL) 135 return; 136 137 sc->sc_t1 = 0; 138 sc->sc_dma = 0; 139 sc->dmat = pa->pa_dmat; 140 141 iavc_b1dma_reset(sc); 142 143 if (pci_mapreg_map(pa, IAVC_PCI_IOBA, PCI_MAPREG_TYPE_IO, 0, 144 &sc->sc_io_bt, &sc->sc_io_bh, &psc->io_base, &psc->io_size)) { 145 aprint_error(": unable to map i/o registers\n"); 146 return; 147 } 148 149 if (pci_mapreg_map(pa, IAVC_PCI_MMBA, PCI_MAPREG_TYPE_MEM, 0, 150 &sc->sc_mem_bt, &sc->sc_mem_bh, &psc->mem_base, &psc->mem_size)) { 151 aprint_error(": unable to map mem registers\n"); 152 return; 153 } 154 aprint_normal(": %s\n", pp->name); 155 156 if (pp->npp_product == PCI_PRODUCT_AVM_T1) { 157 aprint_error_dev(&sc->sc_dev, "sorry, PRI not yet supported\n"); 158 return; 159 160#if 0 161 sc->sc_capi.card_type = CARD_TYPEC_AVM_T1_PCI; 162 sc->sc_capi.sc_nbch = NBCH_PRI; 163 ret = iavc_t1_detect(sc); 164 if (ret) { 165 if (ret < 6) { 166 aprint_error_dev(&sc->sc_dev, "no card detected?\n"); 167 } else { 168 aprint_error_dev(&sc->sc_dev, "black box not on\n"); 169 } 170 return; 171 } else { 172 sc->sc_dma = 1; 173 sc->sc_t1 = 1; 174 } 175#endif 176 177 } else if (pp->npp_product == PCI_PRODUCT_AVM_B1) { 178 sc->sc_capi.card_type = CARD_TYPEC_AVM_B1_PCI; 179 sc->sc_capi.sc_nbch = NBCH_BRI; 180 ret = iavc_b1dma_detect(sc); 181 if (ret) { 182 ret = iavc_b1_detect(sc); 183 if (ret) { 184 aprint_error_dev(&sc->sc_dev, "no card detected?\n"); 185 return; 186 } 187 } else { 188 sc->sc_dma = 1; 189 } 190 } 191 if (sc->sc_dma) 192 iavc_b1dma_reset(sc); 193 194#if 0 195 /* 196 * XXX: should really be done this way, but this freezes the card 197 */ 198 if (sc->sc_t1) 199 iavc_t1_reset(sc); 200 else 201 iavc_b1_reset(sc); 202#endif 203 204 if (pci_intr_map(pa, &ih)) { 205 aprint_error_dev(&sc->sc_dev, "couldn't map interrupt\n"); 206 return; 207 } 208 209 intrstr = pci_intr_string(pc, ih); 210 psc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, iavc_pci_intr, psc); 211 if (psc->sc_ih == NULL) { 212 aprint_error_dev(&sc->sc_dev, "couldn't establish interrupt"); 213 if (intrstr != NULL) 214 aprint_error(" at %s", intrstr); 215 aprint_error("\n"); 216 return; 217 } 218 psc->sc_pc = pc; 219 aprint_normal("%s: interrupting at %s\n", device_xname(&sc->sc_dev), intrstr); 220 221 memset(&sc->sc_txq, 0, sizeof(struct ifqueue)); 222 sc->sc_txq.ifq_maxlen = sc->sc_capi.sc_nbch * 4; 223 224 sc->sc_intr = 0; 225 sc->sc_state = IAVC_DOWN; 226 sc->sc_blocked = 0; 227 228 /* setup capi link */ 229 sc->sc_capi.load = iavc_load; 230 sc->sc_capi.reg_appl = iavc_register; 231 sc->sc_capi.rel_appl = iavc_release; 232 sc->sc_capi.send = iavc_send; 233 sc->sc_capi.ctx = (void *) sc; 234 235 /* lock & load DMA for TX */ 236 if ((ret = bus_dmamem_alloc(sc->dmat, IAVC_DMA_SIZE, PAGE_SIZE, 0, 237 &sc->txseg, 1, &sc->ntxsegs, BUS_DMA_ALLOCNOW)) != 0) { 238 aprint_error_dev(&sc->sc_dev, "can't allocate tx DMA memory, error = %d\n", 239 ret); 240 goto fail1; 241 } 242 243 if ((ret = bus_dmamem_map(sc->dmat, &sc->txseg, sc->ntxsegs, 244 IAVC_DMA_SIZE, &sc->sc_sendbuf, BUS_DMA_NOWAIT)) != 0) { 245 aprint_error_dev(&sc->sc_dev, "can't map tx DMA memory, error = %d\n", 246 ret); 247 goto fail2; 248 } 249 250 if ((ret = bus_dmamap_create(sc->dmat, IAVC_DMA_SIZE, 1, 251 IAVC_DMA_SIZE, 0, BUS_DMA_ALLOCNOW | BUS_DMA_NOWAIT, 252 &sc->tx_map)) != 0) { 253 aprint_error_dev(&sc->sc_dev, "can't create tx DMA map, error = %d\n", 254 ret); 255 goto fail3; 256 } 257 258 if ((ret = bus_dmamap_load(sc->dmat, sc->tx_map, sc->sc_sendbuf, 259 IAVC_DMA_SIZE, NULL, BUS_DMA_WRITE | BUS_DMA_NOWAIT)) != 0) { 260 aprint_error_dev(&sc->sc_dev, "can't load tx DMA map, error = %d\n", 261 ret); 262 goto fail4; 263 } 264 265 /* do the same for RX */ 266 if ((ret = bus_dmamem_alloc(sc->dmat, IAVC_DMA_SIZE, PAGE_SIZE, 0, 267 &sc->rxseg, 1, &sc->nrxsegs, BUS_DMA_ALLOCNOW)) != 0) { 268 aprint_error_dev(&sc->sc_dev, "can't allocate rx DMA memory, error = %d\n", 269 ret); 270 goto fail5; 271 } 272 273 if ((ret = bus_dmamem_map(sc->dmat, &sc->rxseg, sc->nrxsegs, 274 IAVC_DMA_SIZE, &sc->sc_recvbuf, BUS_DMA_NOWAIT)) != 0) { 275 aprint_error_dev(&sc->sc_dev, "can't map rx DMA memory, error = %d\n", 276 ret); 277 goto fail6; 278 } 279 280 if ((ret = bus_dmamap_create(sc->dmat, IAVC_DMA_SIZE, 1, IAVC_DMA_SIZE, 281 0, BUS_DMA_ALLOCNOW | BUS_DMA_NOWAIT, &sc->rx_map)) != 0) { 282 aprint_error_dev(&sc->sc_dev, "can't create rx DMA map, error = %d\n", 283 ret); 284 goto fail7; 285 } 286 287 if ((ret = bus_dmamap_load(sc->dmat, sc->rx_map, sc->sc_recvbuf, 288 IAVC_DMA_SIZE, NULL, BUS_DMA_READ | BUS_DMA_NOWAIT)) != 0) { 289 aprint_error_dev(&sc->sc_dev, "can't load rx DMA map, error = %d\n", 290 ret); 291 goto fail8; 292 } 293 294 if (capi_ll_attach(&sc->sc_capi, device_xname(&sc->sc_dev), pp->name)) { 295 aprint_error_dev(&sc->sc_dev, "capi attach failed\n"); 296 goto fail9; 297 } 298 return; 299 300 /* release resources in case of failed attach */ 301fail9: 302 bus_dmamap_unload(sc->dmat, sc->rx_map); 303fail8: 304 bus_dmamap_destroy(sc->dmat, sc->rx_map); 305fail7: 306 bus_dmamem_unmap(sc->dmat, sc->sc_recvbuf, IAVC_DMA_SIZE); 307fail6: 308 bus_dmamem_free(sc->dmat, &sc->rxseg, sc->nrxsegs); 309fail5: 310 bus_dmamap_unload(sc->dmat, sc->tx_map); 311fail4: 312 bus_dmamap_destroy(sc->dmat, sc->tx_map); 313fail3: 314 bus_dmamem_unmap(sc->dmat, sc->sc_sendbuf, IAVC_DMA_SIZE); 315fail2: 316 bus_dmamem_free(sc->dmat, &sc->txseg, sc->ntxsegs); 317fail1: 318 pci_intr_disestablish(psc->sc_pc, psc->sc_ih); 319 320 return; 321} 322 323int 324iavc_pci_intr(void *arg) 325{ 326 struct iavc_softc *sc = arg; 327 328 return iavc_handle_intr(sc); 329} 330 331#if 0 332static int 333iavc_pci_detach(device_t self, int flags) 334{ 335 struct iavc_pci_softc *psc = device_private(self); 336 337 bus_space_unmap(psc->sc_iavc.sc_mem_bt, psc->sc_iavc.sc_mem_bh, 338 psc->mem_size); 339 bus_space_free(psc->sc_iavc.sc_mem_bt, psc->sc_iavc.sc_mem_bh, 340 psc->mem_size); 341 bus_space_unmap(psc->sc_iavc.sc_io_bt, psc->sc_iavc.sc_io_bh, 342 psc->io_size); 343 bus_space_free(psc->sc_iavc.sc_io_bt, psc->sc_iavc.sc_io_bh, 344 psc->io_size); 345 346 pci_intr_disestablish(psc->sc_pc, psc->sc_ih); 347 348 /* XXX: capi detach?!? */ 349 350 return 0; 351} 352#endif 353