1 /* $NetBSD: aac_pci.c,v 1.2 2002/05/15 14:15:17 augustss Exp $ */ 2 3 /*- 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /*- 40 * Copyright (c) 2000 Michael Smith 41 * Copyright (c) 2000 BSDi 42 * Copyright (c) 2000 Niklas Hallqvist 43 * All rights reserved. 44 * 45 * Redistribution and use in source and binary forms, with or without 46 * modification, are permitted provided that the following conditions 47 * are met: 48 * 1. Redistributions of source code must retain the above copyright 49 * notice, this list of conditions and the following disclaimer. 50 * 2. Redistributions in binary form must reproduce the above copyright 51 * notice, this list of conditions and the following disclaimer in the 52 * documentation and/or other materials provided with the distribution. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 57 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 64 * SUCH DAMAGE. 65 * 66 * from FreeBSD: aac_pci.c,v 1.1 2000/09/13 03:20:34 msmith Exp 67 * via OpenBSD: aac_pci.c,v 1.7 2002/03/14 01:26:58 millert Exp 68 */ 69 70 /* 71 * PCI front-end for the `aac' driver. 72 */ 73 74 #include <sys/cdefs.h> 75 __KERNEL_RCSID(0, "$NetBSD: aac_pci.c,v 1.2 2002/05/15 14:15:17 augustss Exp $"); 76 77 #include <sys/param.h> 78 #include <sys/systm.h> 79 #include <sys/device.h> 80 #include <sys/kernel.h> 81 #include <sys/malloc.h> 82 #include <sys/queue.h> 83 84 #include <machine/bus.h> 85 #include <machine/endian.h> 86 #include <machine/intr.h> 87 88 #include <dev/pci/pcidevs.h> 89 #include <dev/pci/pcireg.h> 90 #include <dev/pci/pcivar.h> 91 92 #include <dev/ic/aacreg.h> 93 #include <dev/ic/aacvar.h> 94 95 int aac_pci_match(struct device *, struct cfdata *, void *); 96 void aac_pci_attach(struct device *, struct device *, void *); 97 const struct aac_ident *aac_find_ident(struct pci_attach_args *); 98 99 /* i960Rx interface */ 100 int aac_rx_get_fwstatus(struct aac_softc *); 101 void aac_rx_qnotify(struct aac_softc *, int); 102 int aac_rx_get_istatus(struct aac_softc *); 103 void aac_rx_clear_istatus(struct aac_softc *, int); 104 void aac_rx_set_mailbox(struct aac_softc *, u_int32_t, u_int32_t, 105 u_int32_t, u_int32_t, u_int32_t); 106 int aac_rx_get_mailboxstatus(struct aac_softc *); 107 void aac_rx_set_interrupts(struct aac_softc *, int); 108 109 /* StrongARM interface */ 110 int aac_sa_get_fwstatus(struct aac_softc *); 111 void aac_sa_qnotify(struct aac_softc *, int); 112 int aac_sa_get_istatus(struct aac_softc *); 113 void aac_sa_clear_istatus(struct aac_softc *, int); 114 void aac_sa_set_mailbox(struct aac_softc *, u_int32_t, u_int32_t, 115 u_int32_t, u_int32_t, u_int32_t); 116 int aac_sa_get_mailboxstatus(struct aac_softc *); 117 void aac_sa_set_interrupts(struct aac_softc *, int); 118 119 const struct aac_interface aac_rx_interface = { 120 aac_rx_get_fwstatus, 121 aac_rx_qnotify, 122 aac_rx_get_istatus, 123 aac_rx_clear_istatus, 124 aac_rx_set_mailbox, 125 aac_rx_get_mailboxstatus, 126 aac_rx_set_interrupts 127 }; 128 129 const struct aac_interface aac_sa_interface = { 130 aac_sa_get_fwstatus, 131 aac_sa_qnotify, 132 aac_sa_get_istatus, 133 aac_sa_clear_istatus, 134 aac_sa_set_mailbox, 135 aac_sa_get_mailboxstatus, 136 aac_sa_set_interrupts 137 }; 138 139 struct aac_ident { 140 u_short vendor; 141 u_short device; 142 u_short subvendor; 143 u_short subdevice; 144 u_short hwif; 145 u_short quirks; 146 const char *prodstr; 147 } const aac_ident[] = { 148 { 149 PCI_VENDOR_DELL, 150 PCI_PRODUCT_DELL_PERC_2SI, 151 PCI_VENDOR_DELL, 152 PCI_PRODUCT_DELL_PERC_2SI, 153 AAC_HWIF_I960RX, 154 0, 155 "Dell PERC 2/Si" 156 }, 157 { 158 PCI_VENDOR_DELL, 159 PCI_PRODUCT_DELL_PERC_3DI, 160 PCI_VENDOR_DELL, 161 PCI_PRODUCT_DELL_PERC_3DI, 162 AAC_HWIF_I960RX, 163 0, 164 "Dell PERC 3/Di" 165 }, 166 { 167 PCI_VENDOR_DELL, 168 PCI_PRODUCT_DELL_PERC_3DI, 169 PCI_VENDOR_DELL, 170 PCI_PRODUCT_DELL_PERC_3DI_SUB2, 171 AAC_HWIF_I960RX, 172 0, 173 "Dell PERC 3/Di" 174 }, 175 { 176 PCI_VENDOR_DELL, 177 PCI_PRODUCT_DELL_PERC_3DI, 178 PCI_VENDOR_DELL, 179 PCI_PRODUCT_DELL_PERC_3DI_SUB3, 180 AAC_HWIF_I960RX, 181 0, 182 "Dell PERC 3/Di" 183 }, 184 { 185 PCI_VENDOR_DELL, 186 PCI_PRODUCT_DELL_PERC_3DI_2, 187 PCI_VENDOR_DELL, 188 PCI_PRODUCT_DELL_PERC_3DI_2_SUB, 189 AAC_HWIF_I960RX, 190 0, 191 "Dell PERC 3/Di" 192 }, 193 { 194 PCI_VENDOR_DELL, 195 PCI_PRODUCT_DELL_PERC_3SI, 196 PCI_VENDOR_DELL, 197 PCI_PRODUCT_DELL_PERC_3SI, 198 AAC_HWIF_I960RX, 199 0, 200 "Dell PERC 3/Si" 201 }, 202 { 203 PCI_VENDOR_DELL, 204 PCI_PRODUCT_DELL_PERC_3SI_2, 205 PCI_VENDOR_DELL, 206 PCI_PRODUCT_DELL_PERC_3SI_2_SUB, 207 AAC_HWIF_I960RX, 208 0, 209 "Dell PERC 3/Si" 210 }, 211 { 212 PCI_VENDOR_ADP2, 213 PCI_PRODUCT_ADP2_AAC2622, 214 PCI_VENDOR_ADP2, 215 PCI_PRODUCT_ADP2_AAC2622, 216 AAC_HWIF_I960RX, 217 0, 218 "Adaptec ADP-2622" 219 }, 220 { 221 PCI_VENDOR_ADP2, 222 PCI_PRODUCT_ADP2_ASR2200S, 223 PCI_VENDOR_ADP2, 224 PCI_PRODUCT_ADP2_ASR2200S, 225 AAC_HWIF_I960RX, 226 0, 227 "Adaptec ASR-2200S" 228 }, 229 { 230 PCI_VENDOR_ADP2, 231 PCI_PRODUCT_ADP2_ASR2200S, 232 PCI_VENDOR_ADP2, 233 PCI_PRODUCT_ADP2_ASR2120S, 234 AAC_HWIF_I960RX, 235 0, 236 "Adaptec ASR-2120S" 237 }, 238 { 239 PCI_VENDOR_DEC, 240 PCI_PRODUCT_DEC_21554, 241 PCI_VENDOR_ADP2, 242 PCI_PRODUCT_ADP2_AAC364, 243 AAC_HWIF_STRONGARM, 244 0, 245 "Adaptec AAC-364" 246 }, 247 { 248 PCI_VENDOR_DEC, 249 PCI_PRODUCT_DEC_21554, 250 PCI_VENDOR_ADP2, 251 PCI_PRODUCT_ADP2_ASR5400S, 252 AAC_HWIF_STRONGARM, 253 0, 254 "Adaptec ASR-5400S" 255 }, 256 { 257 PCI_VENDOR_DEC, 258 PCI_PRODUCT_DEC_21554, 259 PCI_VENDOR_ADP2, 260 PCI_PRODUCT_ADP2_PERC_2QC, 261 AAC_HWIF_STRONGARM, 262 AAC_QUIRK_PERC2QC, 263 "Dell PERC 2/QC" 264 }, 265 { 266 PCI_VENDOR_DEC, 267 PCI_PRODUCT_DEC_21554, 268 PCI_VENDOR_ADP2, 269 PCI_PRODUCT_ADP2_PERC_3QC, 270 AAC_HWIF_STRONGARM, 271 0, 272 "Dell PERC 3/QC" 273 }, 274 { 275 PCI_VENDOR_DEC, 276 PCI_PRODUCT_DEC_21554, 277 PCI_VENDOR_HP, 278 PCI_PRODUCT_HP_NETRAID_4M, 279 AAC_HWIF_STRONGARM, 280 0, 281 "HP NetRAID-4M" 282 }, 283 }; 284 285 struct cfattach aac_pci_ca = { 286 sizeof(struct aac_softc), aac_pci_match, aac_pci_attach 287 }; 288 289 const struct aac_ident * 290 aac_find_ident(struct pci_attach_args *pa) 291 { 292 const struct aac_ident *m, *mm; 293 u_int32_t subsysid; 294 295 m = aac_ident; 296 mm = aac_ident + (sizeof(aac_ident) / sizeof(aac_ident[0])); 297 298 while (m < mm) { 299 if (m->vendor == PCI_VENDOR(pa->pa_id) && 300 m->device == PCI_PRODUCT(pa->pa_id)) { 301 subsysid = pci_conf_read(pa->pa_pc, pa->pa_tag, 302 PCI_SUBSYS_ID_REG); 303 if (m->subvendor == PCI_VENDOR(subsysid) && 304 m->subdevice == PCI_PRODUCT(subsysid)) 305 return (m); 306 } 307 m++; 308 } 309 310 return (NULL); 311 } 312 313 int 314 aac_pci_match(struct device *parent, struct cfdata *match, void *aux) 315 { 316 struct pci_attach_args *pa; 317 318 pa = aux; 319 320 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_I2O) 321 return (0); 322 323 return (aac_find_ident(pa) != NULL); 324 } 325 326 void 327 aac_pci_attach(struct device *parent, struct device *self, void *aux) 328 { 329 struct pci_attach_args *pa; 330 pci_chipset_tag_t pc; 331 struct aac_softc *sc; 332 u_int16_t command; 333 bus_addr_t membase; 334 bus_size_t memsize; 335 pci_intr_handle_t ih; 336 const char *intrstr; 337 int state; 338 const struct aac_ident *m; 339 340 pa = aux; 341 pc = pa->pa_pc; 342 sc = (struct aac_softc *)self; 343 state = 0; 344 345 printf(": "); 346 347 /* 348 * Verify that the adapter is correctly set up in PCI space. 349 */ 350 command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 351 command |= PCI_COMMAND_MASTER_ENABLE; 352 pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, command); 353 command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 354 AAC_DPRINTF(AAC_D_MISC, ("pci command status reg 0x08x ")); 355 356 if ((command & PCI_COMMAND_MASTER_ENABLE) == 0) { 357 printf("can't enable bus-master feature\n"); 358 goto bail_out; 359 } 360 361 if ((command & PCI_COMMAND_MEM_ENABLE) == 0) { 362 printf("memory window not available\n"); 363 goto bail_out; 364 } 365 366 /* 367 * Map control/status registers. 368 */ 369 if (pci_mapreg_map(pa, PCI_MAPREG_START, 370 PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0, &sc->sc_memt, 371 &sc->sc_memh, &membase, &memsize)) { 372 printf("can't find mem space\n"); 373 goto bail_out; 374 } 375 state++; 376 377 if (pci_intr_map(pa, &ih)) { 378 printf("couldn't map interrupt\n"); 379 goto bail_out; 380 } 381 intrstr = pci_intr_string(pc, ih); 382 sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, aac_intr, sc); 383 if (sc->sc_ih == NULL) { 384 printf("couldn't establish interrupt"); 385 if (intrstr != NULL) 386 printf(" at %s", intrstr); 387 printf("\n"); 388 goto bail_out; 389 } 390 state++; 391 392 sc->sc_dmat = pa->pa_dmat; 393 394 m = aac_find_ident(pa); 395 printf("%s\n", m->prodstr); 396 if (intrstr != NULL) 397 printf("%s: interrupting at %s\n", sc->sc_dv.dv_xname, intrstr); 398 399 sc->sc_hwif = m->hwif; 400 sc->sc_quirks = m->quirks; 401 switch (sc->sc_hwif) { 402 case AAC_HWIF_I960RX: 403 AAC_DPRINTF(AAC_D_MISC, 404 ("set hardware up for i960Rx")); 405 sc->sc_if = aac_rx_interface; 406 break; 407 408 case AAC_HWIF_STRONGARM: 409 AAC_DPRINTF(AAC_D_MISC, 410 ("set hardware up for StrongARM")); 411 sc->sc_if = aac_sa_interface; 412 break; 413 } 414 415 if (!aac_attach(sc)) 416 return; 417 418 bail_out: 419 if (state > 1) 420 pci_intr_disestablish(pc, sc->sc_ih); 421 if (state > 0) 422 bus_space_unmap(sc->sc_memt, sc->sc_memh, memsize); 423 } 424 425 /* 426 * Read the current firmware status word. 427 */ 428 int 429 aac_sa_get_fwstatus(struct aac_softc *sc) 430 { 431 432 return (AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 433 } 434 435 int 436 aac_rx_get_fwstatus(struct aac_softc *sc) 437 { 438 439 return (AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 440 } 441 442 /* 443 * Notify the controller of a change in a given queue 444 */ 445 446 void 447 aac_sa_qnotify(struct aac_softc *sc, int qbit) 448 { 449 450 AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 451 } 452 453 void 454 aac_rx_qnotify(struct aac_softc *sc, int qbit) 455 { 456 457 AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 458 } 459 460 /* 461 * Get the interrupt reason bits 462 */ 463 int 464 aac_sa_get_istatus(struct aac_softc *sc) 465 { 466 467 return (AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 468 } 469 470 int 471 aac_rx_get_istatus(struct aac_softc *sc) 472 { 473 474 return (AAC_GETREG4(sc, AAC_RX_ODBR)); 475 } 476 477 /* 478 * Clear some interrupt reason bits 479 */ 480 void 481 aac_sa_clear_istatus(struct aac_softc *sc, int mask) 482 { 483 484 AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 485 } 486 487 void 488 aac_rx_clear_istatus(struct aac_softc *sc, int mask) 489 { 490 491 AAC_SETREG4(sc, AAC_RX_ODBR, mask); 492 } 493 494 /* 495 * Populate the mailbox and set the command word 496 */ 497 void 498 aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 499 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 500 u_int32_t arg3) 501 { 502 503 AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 504 AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 505 AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 506 AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 507 AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 508 } 509 510 void 511 aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 512 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 513 u_int32_t arg3) 514 { 515 516 AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 517 AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 518 AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 519 AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 520 AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 521 } 522 523 /* 524 * Fetch the immediate command status word 525 */ 526 int 527 aac_sa_get_mailboxstatus(struct aac_softc *sc) 528 { 529 530 return (AAC_GETREG4(sc, AAC_SA_MAILBOX)); 531 } 532 533 int 534 aac_rx_get_mailboxstatus(struct aac_softc *sc) 535 { 536 537 return (AAC_GETREG4(sc, AAC_RX_MAILBOX)); 538 } 539 540 /* 541 * Set/clear interrupt masks 542 */ 543 void 544 aac_sa_set_interrupts(struct aac_softc *sc, int enable) 545 { 546 547 if (enable) 548 AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 549 else 550 AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 551 } 552 553 void 554 aac_rx_set_interrupts(struct aac_softc *sc, int enable) 555 { 556 557 if (enable) 558 AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 559 else 560 AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 561 } 562