if_ntwoc_pci.c revision 1.1
1/* $Id: if_ntwoc_pci.c,v 1.1 1998/07/26 03:28:28 explorer Exp $ */ 2 3/* 4 * Copyright (c) 1998 Vixie Enterprises 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 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of Vixie Enterprises nor the names 17 * of its contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY VIXIE ENTERPRISES AND 21 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 22 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 * DISCLAIMED. IN NO EVENT SHALL VIXIE ENTERPRISES OR 25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 28 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 29 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * This software has been written for Vixie Enterprises by Michael Graff 35 * <explorer@flame.org>. To learn more about Vixie Enterprises, see 36 * ``http://www.vix.com''. 37 */ 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/device.h> 42#include <sys/mbuf.h> 43#include <sys/socket.h> 44 45#include <net/if.h> 46 47#include <machine/cpu.h> 48#include <machine/bus.h> 49#include <machine/intr.h> 50 51#include <dev/pci/pcivar.h> 52#include <dev/pci/pcireg.h> 53#include <dev/pci/pcidevs.h> 54 55#include <dev/ic/hd64570reg.h> 56#include <dev/ic/hd64570var.h> 57 58#include <dev/pci/if_ntwoc_pcireg.h> 59 60#if 0 61#define NTWO_DEBUG 62#endif 63 64#ifdef NTWO_DEBUG 65#define NTWO_DPRINTF(x) printf x 66#else 67#define NTWO_DPRINTF(x) 68#endif 69 70/* 71 * Card specific config register location 72 */ 73#define PCI_CBMA_ASIC 0x10 /* Configuration Base Memory Address */ 74#define PCI_CBMA_SCA 0x18 75 76struct ntwoc_pci_softc { 77 /* Generic device stuff */ 78 struct device sc_dev; /* Common to all devices */ 79 80 /* PCI chipset glue */ 81 pci_intr_handle_t *sc_ih; /* Interrupt handler */ 82 pci_chipset_tag_t sc_sr; /* PCI chipset handle */ 83 84 bus_space_tag_t sc_asic_iot; /* space cookie (for ASIC) */ 85 bus_space_handle_t sc_asic_ioh; /* bus space handle (for ASIC) */ 86 87 struct sca_softc sc_sca; /* the SCA itself */ 88}; 89 90static int ntwoc_pci_match __P((struct device *, struct cfdata *, void *)); 91static void ntwoc_pci_attach __P((struct device *, struct device *, void *)); 92 93static int ntwoc_intr __P((void *)); 94static void ntwoc_shutdown __P((void *sc)); 95static void ntwoc_dtr_callback __P((void *, int, int)); 96 97struct cfattach ntwoc_pci_ca = { 98 sizeof(struct ntwoc_pci_softc), ntwoc_pci_match, ntwoc_pci_attach, 99}; 100 101/* 102 * Names for daughter card types. These match the NTWOC_DB_* defines. 103 */ 104char *ntwoc_db_names[] = { 105 "V.35", "Unknown 0x01", "Test", "Unknown 0x03", 106 "RS232", "Unknown 0x05", "RS422", "None" 107}; 108 109static int 110ntwoc_pci_match(struct device *parent, struct cfdata *match, void *aux) 111{ 112 struct pci_attach_args *pa = (struct pci_attach_args *)aux; 113 114 if ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_RISCOM) 115 && (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_RISCOM_N2)) 116 return 1; 117 118 return 0; 119} 120 121static void 122ntwoc_pci_attach(struct device *parent, struct device *self, void *aux) 123{ 124 struct ntwoc_pci_softc *sc = (void *)self; 125 struct pci_attach_args *pa = aux; 126 struct sca_softc *sca = &sc->sc_sca; 127 pci_intr_handle_t ih; 128 const char *intrstr; 129 pcireg_t csr; 130 u_int16_t frontend_cr; 131 u_int16_t db0, db1; 132 u_int numports; 133 134 printf(": N2 Serial Interface\n"); 135 136 /* 137 * Map in the ASIC configuration space 138 */ 139 if (pci_mapreg_map(pa, PCI_CBMA_ASIC, PCI_MAPREG_TYPE_MEM, 0, 140 &sc->sc_asic_iot, &sc->sc_asic_ioh, NULL, NULL)) { 141 printf("%s: Can't map register space (ASIC)\n", 142 sc->sc_dev.dv_xname); 143 return; 144 } 145 /* 146 * Map in the serial controller configuration space 147 */ 148 if (pci_mapreg_map(pa, PCI_CBMA_SCA, PCI_MAPREG_TYPE_MEM, 0, 149 &sca->sc_iot, &sca->sc_ioh, NULL, NULL)) { 150 printf("%s: Can't map register space (SCA)\n", 151 sc->sc_dev.dv_xname); 152 return; 153 } 154 155 /* 156 * Enable the card 157 */ 158 csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 159 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, csr); 160 161 /* 162 * Map and establish the interrupt 163 */ 164 if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin, 165 pa->pa_intrline, &ih)) { 166 printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname); 167 return; 168 } 169 intrstr = pci_intr_string(pa->pa_pc, ih); 170 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET, ntwoc_intr, sc); 171 if (sc->sc_ih == NULL) { 172 printf("%s: couldn't establish interrupt", 173 sc->sc_dev.dv_xname); 174 if (intrstr != NULL) 175 printf(" at %s", intrstr); 176 printf("\n"); 177 return; 178 } 179 printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); 180 181 /* 182 * Perform total black magic. This is not only extremely 183 * disgusting, but it should be explained a lot more in the 184 * card's documentation. 185 * 186 * From what I gather, this does nothing more than configure the 187 * PCI to ISA translator ASIC the N2pci card uses. 188 * 189 * From the FreeBSD driver: 190 * offset 191 * 0x00 - Map Range - Mem-mapped to locate anywhere 192 * 0x04 - Re-Map - PCI address decode enable 193 * 0x18 - Bus Region - 32-bit bus, ready enable 194 * 0x1c - Master Range - include all 16 MB 195 * 0x20 - Master RAM - Map SCA Base at 0 196 * 0x28 - Master Remap - direct master memory enable 197 * 0x68 - Interrupt - Enable interrupt (0 to disable) 198 */ 199 bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh, 200 0x00, 0xfffff000); 201 bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh, 202 0x04, 1); 203 bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh, 204 0x18, 0x40030043); 205 bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh, 206 0x1c, 0xff000000); 207 bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh, 208 0x20, 0); 209 bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh, 210 0x28, 0xe9); 211 bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh, 212 0x68, 0x10900); 213 214 /* 215 * pass the dma tag to the SCA 216 */ 217 sca->sc_dmat = pa->pa_dmat; 218 219 /* 220 * Read the configuration information off the daughter card. 221 */ 222 frontend_cr = bus_space_read_2(sca->sc_iot, sca->sc_ioh, NTWOC_FECR); 223 NTWO_DPRINTF(("%s: frontend_cr = 0x%04x\n", 224 sc->sc_dev.dv_xname, frontend_cr)); 225 226 db0 = (frontend_cr & NTWOC_FECR_ID0) >> NTWOC_FECR_ID0_SHIFT; 227 db1 = (frontend_cr & NTWOC_FECR_ID1) >> NTWOC_FECR_ID1_SHIFT; 228 229 /* 230 * Port 1 HAS to be present. If it isn't, don't attach anything. 231 */ 232 if (db0 == NTWOC_FE_ID_NONE) { 233 printf("%s: no ports available\n", sc->sc_dev.dv_xname); 234 return; 235 } 236 237 /* 238 * Port 1 is present. Now, check to see if port 2 is also 239 * present. 240 */ 241 numports = 1; 242 if (db1 != NTWOC_FE_ID_NONE) 243 numports++; 244 245 printf("%s: %d port%s\n", sc->sc_dev.dv_xname, numports, 246 (numports > 1 ? "s" : "")); 247 printf("%s: port 0 interface card: %s\n", sc->sc_dev.dv_xname, 248 ntwoc_db_names[db0]); 249 if (numports > 1) 250 printf("%s: port 1 interface card: %s\n", sc->sc_dev.dv_xname, 251 ntwoc_db_names[db1]); 252 253 /* 254 * enable the RS422 tristate transmit 255 * diable clock output (use receiver clock for both) 256 */ 257 frontend_cr |= (NTWOC_FECR_TE0 | NTWOC_FECR_TE1); 258 frontend_cr &= ~(NTWOC_FECR_ETC0 | NTWOC_FECR_ETC1); 259 bus_space_write_2(sc->sc_sca.sc_iot, sc->sc_sca.sc_ioh, 260 NTWOC_FECR, frontend_cr); 261 262 /* 263 * initialize the SCA. This will allocate DMAable memory based 264 * on the number of ports we passed in, the size of each 265 * buffer, and the number of buffers per port. 266 */ 267 sca->parent = &sc->sc_dev; 268 sca->dtr_callback = ntwoc_dtr_callback; 269 sca->dtr_aux = sc; 270 sca_init(sca, numports); 271 272 /* 273 * always initialize port 0, since we have to have found it to 274 * get this far. If we have two ports, attach the second 275 * as well. 276 */ 277 sca_port_attach(sca, 0); 278 if (numports == 2) 279 sca_port_attach(sca, 1); 280 281 /* 282 * Add shutdown hook so that DMA is disabled prior to reboot. Not 283 * doing do could allow DMA to corrupt kernel memory during the 284 * reboot before the driver initializes. 285 */ 286 shutdownhook_establish(ntwoc_shutdown, sc); 287} 288 289static int 290ntwoc_intr(void *arg) 291{ 292 struct ntwoc_pci_softc *sc = (struct ntwoc_pci_softc *)arg; 293 294 return sca_hardintr(&sc->sc_sca); 295} 296 297/* 298 * shut down interrupts and DMA, so we don't trash the kernel on warm 299 * boot. Also, lower DTR on each port and disable card interrupts. 300 */ 301static void 302ntwoc_shutdown(void *aux) 303{ 304 struct ntwoc_pci_softc *sc = aux; 305 u_int16_t fecr; 306 307 /* 308 * shut down the SCA ports 309 */ 310 sca_shutdown(&sc->sc_sca); 311 312 /* 313 * disable interupts for the whole card. Black magic, see comment 314 * above. 315 */ 316 bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh, 317 0x68, 0x10900); 318 319 /* 320 * lower DTR on both ports 321 */ 322 fecr = bus_space_read_2(sc->sc_sca.sc_iot, 323 sc->sc_sca.sc_ioh, NTWOC_FECR); 324 fecr |= (NTWOC_FECR_DTR0 | NTWOC_FECR_DTR1); 325 bus_space_write_2(sc->sc_sca.sc_iot, sc->sc_sca.sc_ioh, 326 NTWOC_FECR, fecr); 327} 328 329static void 330ntwoc_dtr_callback(void *aux, int port, int state) 331{ 332 struct ntwoc_pci_softc *sc = aux; 333 u_int16_t fecr; 334 335 fecr = bus_space_read_2(sc->sc_sca.sc_iot, 336 sc->sc_sca.sc_ioh, NTWOC_FECR); 337 338 NTWO_DPRINTF(("port == %d, state == %d, old fecr: 0x%04x\n", 339 port, state, fecr)); 340 341 if (port == 0) { 342 if (state == 0) 343 fecr |= NTWOC_FECR_DTR0; 344 else 345 fecr &= ~NTWOC_FECR_DTR0; 346 } else { 347 if (state == 0) 348 fecr |= NTWOC_FECR_DTR1; 349 else 350 fecr &= ~NTWOC_FECR_DTR1; 351 } 352 353 NTWO_DPRINTF(("new fecr: 0x%04x\n", fecr)); 354 355 bus_space_write_2(sc->sc_sca.sc_iot, sc->sc_sca.sc_ioh, 356 NTWOC_FECR, fecr); 357} 358