amr_pci.c revision 157586
1/*- 2 * Copyright (c) 1999,2000 Michael Smith 3 * Copyright (c) 2000 BSDi 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27/*- 28 * Copyright (c) 2002 Eric Moore 29 * Copyright (c) 2002, 2004 LSI Logic Corporation 30 * All rights reserved. 31 * 32 * Redistribution and use in source and binary forms, with or without 33 * modification, are permitted provided that the following conditions 34 * are met: 35 * 1. Redistributions of source code must retain the above copyright 36 * notice, this list of conditions and the following disclaimer. 37 * 2. Redistributions in binary form must reproduce the above copyright 38 * notice, this list of conditions and the following disclaimer in the 39 * documentation and/or other materials provided with the distribution. 40 * 3. The party using or redistributing the source code and binary forms 41 * agrees to the disclaimer below and the terms and conditions set forth 42 * herein. 43 * 44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 47 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 54 * SUCH DAMAGE. 55 */ 56 57#include <sys/cdefs.h> 58__FBSDID("$FreeBSD: head/sys/dev/amr/amr_pci.c 157586 2006-04-08 05:08:17Z scottl $"); 59 60#include <sys/param.h> 61#include <sys/systm.h> 62#include <sys/kernel.h> 63#include <sys/module.h> 64#include <sys/sysctl.h> 65 66#include <sys/bio.h> 67#include <sys/bus.h> 68#include <sys/conf.h> 69 70#include <machine/bus.h> 71#include <machine/resource.h> 72#include <sys/rman.h> 73 74#include <dev/pci/pcireg.h> 75#include <dev/pci/pcivar.h> 76 77#include <dev/amr/amrio.h> 78#include <dev/amr/amrreg.h> 79#include <dev/amr/amrvar.h> 80 81static int amr_pci_probe(device_t dev); 82static int amr_pci_attach(device_t dev); 83static int amr_pci_detach(device_t dev); 84static int amr_pci_shutdown(device_t dev); 85static int amr_pci_suspend(device_t dev); 86static int amr_pci_resume(device_t dev); 87static void amr_pci_intr(void *arg); 88static void amr_pci_free(struct amr_softc *sc); 89static void amr_sglist_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error); 90static int amr_sglist_map(struct amr_softc *sc); 91static void amr_setup_mbox_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error); 92static int amr_setup_mbox(struct amr_softc *sc); 93 94static u_int amr_force_sg32 = 0; 95TUNABLE_INT("hw.amr.force_sg32", &amr_force_sg32); 96SYSCTL_DECL(_hw_amr); 97SYSCTL_UINT(_hw_amr, OID_AUTO, force_sg32, CTLFLAG_RDTUN, &amr_force_sg32, 0, 98 "Force the AMR driver to use 32bit scatter gather"); 99 100static device_method_t amr_methods[] = { 101 /* Device interface */ 102 DEVMETHOD(device_probe, amr_pci_probe), 103 DEVMETHOD(device_attach, amr_pci_attach), 104 DEVMETHOD(device_detach, amr_pci_detach), 105 DEVMETHOD(device_shutdown, amr_pci_shutdown), 106 DEVMETHOD(device_suspend, amr_pci_suspend), 107 DEVMETHOD(device_resume, amr_pci_resume), 108 109 DEVMETHOD(bus_print_child, bus_generic_print_child), 110 DEVMETHOD(bus_driver_added, bus_generic_driver_added), 111 { 0, 0 } 112}; 113 114static driver_t amr_pci_driver = { 115 "amr", 116 amr_methods, 117 sizeof(struct amr_softc) 118}; 119 120static devclass_t amr_devclass; 121DRIVER_MODULE(amr, pci, amr_pci_driver, amr_devclass, 0, 0); 122 123static struct amr_ident 124{ 125 int vendor; 126 int device; 127 int flags; 128#define AMR_ID_PROBE_SIG (1<<0) /* generic i960RD, check signature */ 129#define AMR_ID_DO_SG64 (1<<1) 130#define AMR_ID_QUARTZ (1<<2) 131} amr_device_ids[] = { 132 {0x101e, 0x9010, 0}, 133 {0x101e, 0x9060, 0}, 134 {0x8086, 0x1960, AMR_ID_QUARTZ | AMR_ID_PROBE_SIG}, 135 {0x101e, 0x1960, AMR_ID_QUARTZ}, 136 {0x1000, 0x1960, AMR_ID_QUARTZ | AMR_ID_DO_SG64 | AMR_ID_PROBE_SIG}, 137 {0x1000, 0x0407, AMR_ID_QUARTZ | AMR_ID_DO_SG64}, 138 {0x1000, 0x0408, AMR_ID_QUARTZ | AMR_ID_DO_SG64}, 139 {0x1000, 0x0409, AMR_ID_QUARTZ | AMR_ID_DO_SG64}, 140 {0x1028, 0x000e, AMR_ID_QUARTZ | AMR_ID_DO_SG64 | AMR_ID_PROBE_SIG}, /* perc4/di i960 */ 141 {0x1028, 0x000f, AMR_ID_QUARTZ | AMR_ID_DO_SG64}, /* perc4/di Verde*/ 142 {0x1028, 0x0013, AMR_ID_QUARTZ | AMR_ID_DO_SG64}, /* perc4/di */ 143 {0, 0, 0} 144}; 145 146static struct amr_ident * 147amr_find_ident(device_t dev) 148{ 149 struct amr_ident *id; 150 int sig; 151 152 for (id = amr_device_ids; id->vendor != 0; id++) { 153 if ((pci_get_vendor(dev) == id->vendor) && 154 (pci_get_device(dev) == id->device)) { 155 156 /* do we need to test for a signature? */ 157 if (id->flags & AMR_ID_PROBE_SIG) { 158 sig = pci_read_config(dev, AMR_CFG_SIG, 2); 159 if ((sig != AMR_SIGNATURE_1) && (sig != AMR_SIGNATURE_2)) 160 continue; 161 } 162 return (id); 163 } 164 } 165 return (NULL); 166} 167 168static int 169amr_pci_probe(device_t dev) 170{ 171 172 debug_called(1); 173 174 if (amr_find_ident(dev) != NULL) { 175 device_set_desc(dev, LSI_DESC_PCI); 176 return(BUS_PROBE_DEFAULT); 177 } 178 return(ENXIO); 179} 180 181static int 182amr_pci_attach(device_t dev) 183{ 184 struct amr_softc *sc; 185 struct amr_ident *id; 186 int rid, rtype, error; 187 u_int32_t command; 188 189 debug_called(1); 190 191 /* 192 * Initialise softc. 193 */ 194 sc = device_get_softc(dev); 195 bzero(sc, sizeof(*sc)); 196 sc->amr_dev = dev; 197 198 /* assume failure is 'not configured' */ 199 error = ENXIO; 200 201 /* 202 * Determine board type. 203 */ 204 if ((id = amr_find_ident(dev)) == NULL) 205 return (ENXIO); 206 207 command = pci_read_config(dev, PCIR_COMMAND, 1); 208 if (id->flags & AMR_ID_QUARTZ) { 209 /* 210 * Make sure we are going to be able to talk to this board. 211 */ 212 if ((command & PCIM_CMD_MEMEN) == 0) { 213 device_printf(dev, "memory window not available\n"); 214 return (ENXIO); 215 } 216 sc->amr_type |= AMR_TYPE_QUARTZ; 217 } else { 218 /* 219 * Make sure we are going to be able to talk to this board. 220 */ 221 if ((command & PCIM_CMD_PORTEN) == 0) { 222 device_printf(dev, "I/O window not available\n"); 223 return (ENXIO); 224 } 225 } 226 227 if ((amr_force_sg32 == 0) && (id->flags & AMR_ID_DO_SG64) && 228 (sizeof(vm_paddr_t) > 4)) { 229 device_printf(dev, "Using 64-bit DMA\n"); 230 sc->amr_type |= AMR_TYPE_SG64; 231 } 232 233 /* force the busmaster enable bit on */ 234 if (!(command & PCIM_CMD_BUSMASTEREN)) { 235 device_printf(dev, "busmaster bit not set, enabling\n"); 236 command |= PCIM_CMD_BUSMASTEREN; 237 pci_write_config(dev, PCIR_COMMAND, command, 2); 238 } 239 240 /* 241 * Allocate the PCI register window. 242 */ 243 rid = PCIR_BAR(0); 244 rtype = AMR_IS_QUARTZ(sc) ? SYS_RES_MEMORY : SYS_RES_IOPORT; 245 sc->amr_reg = bus_alloc_resource_any(dev, rtype, &rid, RF_ACTIVE); 246 if (sc->amr_reg == NULL) { 247 device_printf(sc->amr_dev, "can't allocate register window\n"); 248 goto out; 249 } 250 sc->amr_btag = rman_get_bustag(sc->amr_reg); 251 sc->amr_bhandle = rman_get_bushandle(sc->amr_reg); 252 253 /* 254 * Allocate and connect our interrupt. 255 */ 256 rid = 0; 257 sc->amr_irq = bus_alloc_resource_any(sc->amr_dev, SYS_RES_IRQ, &rid, 258 RF_SHAREABLE | RF_ACTIVE); 259 if (sc->amr_irq == NULL) { 260 device_printf(sc->amr_dev, "can't allocate interrupt\n"); 261 goto out; 262 } 263 if (bus_setup_intr(sc->amr_dev, sc->amr_irq, 264 INTR_TYPE_BIO | INTR_ENTROPY | INTR_MPSAFE, amr_pci_intr, 265 sc, &sc->amr_intr)) { 266 device_printf(sc->amr_dev, "can't set up interrupt\n"); 267 goto out; 268 } 269 270 debug(2, "interrupt attached"); 271 272 /* assume failure is 'out of memory' */ 273 error = ENOMEM; 274 275 /* 276 * Allocate the parent bus DMA tag appropriate for PCI. 277 */ 278 if (bus_dma_tag_create(NULL, /* parent */ 279 1, 0, /* alignment,boundary */ 280 AMR_IS_SG64(sc) ? 281 BUS_SPACE_MAXADDR : 282 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 283 BUS_SPACE_MAXADDR, /* highaddr */ 284 NULL, NULL, /* filter, filterarg */ 285 MAXBSIZE, AMR_NSEG, /* maxsize, nsegments */ 286 BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 287 0, /* flags */ 288 NULL, NULL, /* lockfunc, lockarg */ 289 &sc->amr_parent_dmat)) { 290 device_printf(dev, "can't allocate parent DMA tag\n"); 291 goto out; 292 } 293 294 /* 295 * Create DMA tag for mapping buffers into controller-addressable space. 296 */ 297 if (bus_dma_tag_create(sc->amr_parent_dmat, /* parent */ 298 1, 0, /* alignment,boundary */ 299 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 300 BUS_SPACE_MAXADDR, /* highaddr */ 301 NULL, NULL, /* filter, filterarg */ 302 MAXBSIZE, AMR_NSEG, /* maxsize, nsegments */ 303 MAXBSIZE, /* maxsegsize */ 304 BUS_DMA_ALLOCNOW, /* flags */ 305 busdma_lock_mutex, /* lockfunc */ 306 &sc->amr_list_lock, /* lockarg */ 307 &sc->amr_buffer_dmat)) { 308 device_printf(sc->amr_dev, "can't allocate buffer DMA tag\n"); 309 goto out; 310 } 311 312 if (bus_dma_tag_create(sc->amr_parent_dmat, /* parent */ 313 1, 0, /* alignment,boundary */ 314 BUS_SPACE_MAXADDR, /* lowaddr */ 315 BUS_SPACE_MAXADDR, /* highaddr */ 316 NULL, NULL, /* filter, filterarg */ 317 MAXBSIZE, AMR_NSEG, /* maxsize, nsegments */ 318 MAXBSIZE, /* maxsegsize */ 319 BUS_DMA_ALLOCNOW, /* flags */ 320 busdma_lock_mutex, /* lockfunc */ 321 &sc->amr_list_lock, /* lockarg */ 322 &sc->amr_buffer64_dmat)) { 323 device_printf(sc->amr_dev, "can't allocate buffer DMA tag\n"); 324 goto out; 325 } 326 327 debug(2, "dma tag done"); 328 329 /* 330 * Allocate and set up mailbox in a bus-visible fashion. 331 */ 332 mtx_init(&sc->amr_list_lock, "AMR List Lock", NULL, MTX_DEF); 333 mtx_init(&sc->amr_hw_lock, "AMR HW Lock", NULL, MTX_DEF); 334 if ((error = amr_setup_mbox(sc)) != 0) 335 goto out; 336 337 debug(2, "mailbox setup"); 338 339 /* 340 * Build the scatter/gather buffers. 341 */ 342 if (amr_sglist_map(sc)) 343 goto out; 344 345 debug(2, "s/g list mapped"); 346 347 /* 348 * Do bus-independant initialisation, bring controller online. 349 */ 350 error = amr_attach(sc); 351 352out: 353 if (error) 354 amr_pci_free(sc); 355 return(error); 356} 357 358/******************************************************************************** 359 * Disconnect from the controller completely, in preparation for unload. 360 */ 361static int 362amr_pci_detach(device_t dev) 363{ 364 struct amr_softc *sc = device_get_softc(dev); 365 int error; 366 367 debug_called(1); 368 369 if (sc->amr_state & AMR_STATE_OPEN) 370 return(EBUSY); 371 372 if ((error = amr_pci_shutdown(dev))) 373 return(error); 374 375 amr_pci_free(sc); 376 377 return(0); 378} 379 380/******************************************************************************** 381 * Bring the controller down to a dormant state and detach all child devices. 382 * 383 * This function is called before detach, system shutdown, or before performing 384 * an operation which may add or delete system disks. (Call amr_startup to 385 * resume normal operation.) 386 * 387 * Note that we can assume that the bioq on the controller is empty, as we won't 388 * allow shutdown if any device is open. 389 */ 390static int 391amr_pci_shutdown(device_t dev) 392{ 393 struct amr_softc *sc = device_get_softc(dev); 394 int i,error; 395 396 debug_called(1); 397 398 /* mark ourselves as in-shutdown */ 399 sc->amr_state |= AMR_STATE_SHUTDOWN; 400 401 402 /* flush controller */ 403 device_printf(sc->amr_dev, "flushing cache..."); 404 printf("%s\n", amr_flush(sc) ? "failed" : "done"); 405 406 error = 0; 407 408 /* delete all our child devices */ 409 for(i = 0 ; i < AMR_MAXLD; i++) { 410 if( sc->amr_drive[i].al_disk != 0) { 411 if((error = device_delete_child(sc->amr_dev,sc->amr_drive[i].al_disk)) != 0) 412 goto shutdown_out; 413 sc->amr_drive[i].al_disk = 0; 414 } 415 } 416 417 /* XXX disable interrupts? */ 418 419shutdown_out: 420 return(error); 421} 422 423/******************************************************************************** 424 * Bring the controller to a quiescent state, ready for system suspend. 425 */ 426static int 427amr_pci_suspend(device_t dev) 428{ 429 struct amr_softc *sc = device_get_softc(dev); 430 431 debug_called(1); 432 433 sc->amr_state |= AMR_STATE_SUSPEND; 434 435 /* flush controller */ 436 device_printf(sc->amr_dev, "flushing cache..."); 437 printf("%s\n", amr_flush(sc) ? "failed" : "done"); 438 439 /* XXX disable interrupts? */ 440 441 return(0); 442} 443 444/******************************************************************************** 445 * Bring the controller back to a state ready for operation. 446 */ 447static int 448amr_pci_resume(device_t dev) 449{ 450 struct amr_softc *sc = device_get_softc(dev); 451 452 debug_called(1); 453 454 sc->amr_state &= ~AMR_STATE_SUSPEND; 455 456 /* XXX enable interrupts? */ 457 458 return(0); 459} 460 461/******************************************************************************* 462 * Take an interrupt, or be poked by other code to look for interrupt-worthy 463 * status. 464 */ 465static void 466amr_pci_intr(void *arg) 467{ 468 struct amr_softc *sc = (struct amr_softc *)arg; 469 470 debug_called(2); 471 472 /* collect finished commands, queue anything waiting */ 473 amr_done(sc); 474} 475 476/******************************************************************************** 477 * Free all of the resources associated with (sc) 478 * 479 * Should not be called if the controller is active. 480 */ 481static void 482amr_pci_free(struct amr_softc *sc) 483{ 484 void *p 485 486 debug_called(1); 487 488 amr_free(sc); 489 490 /* destroy data-transfer DMA tag */ 491 if (sc->amr_buffer_dmat) 492 bus_dma_tag_destroy(sc->amr_buffer_dmat); 493 if (sc->amr_buffer64_dmat) 494 bus_dma_tag_destroy(sc->amr_buffer64_dmat); 495 496 /* free and destroy DMA memory and tag for s/g lists */ 497 if (sc->amr_sgtable) 498 bus_dmamem_free(sc->amr_sg_dmat, sc->amr_sgtable, sc->amr_sg_dmamap); 499 if (sc->amr_sg_dmat) 500 bus_dma_tag_destroy(sc->amr_sg_dmat); 501 502 /* free and destroy DMA memory and tag for mailbox */ 503 p = (void *)(uintptr_t)(volatile void *)sc->amr_mailbox64; 504 if (sc->amr_mailbox) { 505 bus_dmamem_free(sc->amr_mailbox_dmat, p, sc->amr_mailbox_dmamap); 506 } 507 if (sc->amr_mailbox_dmat) 508 bus_dma_tag_destroy(sc->amr_mailbox_dmat); 509 510 /* disconnect the interrupt handler */ 511 if (sc->amr_intr) 512 bus_teardown_intr(sc->amr_dev, sc->amr_irq, sc->amr_intr); 513 if (sc->amr_irq != NULL) 514 bus_release_resource(sc->amr_dev, SYS_RES_IRQ, 0, sc->amr_irq); 515 516 /* destroy the parent DMA tag */ 517 if (sc->amr_parent_dmat) 518 bus_dma_tag_destroy(sc->amr_parent_dmat); 519 520 /* release the register window mapping */ 521 if (sc->amr_reg != NULL) 522 bus_release_resource(sc->amr_dev, 523 AMR_IS_QUARTZ(sc) ? SYS_RES_MEMORY : SYS_RES_IOPORT, 524 PCIR_BAR(0), sc->amr_reg); 525} 526 527/******************************************************************************** 528 * Allocate and map the scatter/gather table in bus space. 529 */ 530static void 531amr_sglist_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 532{ 533 struct amr_softc *sc = (struct amr_softc *)arg; 534 535 debug_called(1); 536 537 /* save base of s/g table's address in bus space */ 538 sc->amr_sgbusaddr = segs->ds_addr; 539} 540 541static int 542amr_sglist_map(struct amr_softc *sc) 543{ 544 size_t segsize; 545 void *p; 546 int error; 547 548 debug_called(1); 549 550 /* 551 * Create a single tag describing a region large enough to hold all of 552 * the s/g lists we will need. 553 * 554 * Note that we could probably use AMR_LIMITCMD here, but that may become 555 * tunable. 556 */ 557 if (AMR_IS_SG64(sc)) 558 segsize = sizeof(struct amr_sg64entry) * AMR_NSEG * AMR_MAXCMD; 559 else 560 segsize = sizeof(struct amr_sgentry) * AMR_NSEG * AMR_MAXCMD; 561 562 error = bus_dma_tag_create(sc->amr_parent_dmat, /* parent */ 563 1, 0, /* alignment,boundary */ 564 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 565 BUS_SPACE_MAXADDR, /* highaddr */ 566 NULL, NULL, /* filter, filterarg */ 567 segsize, 1, /* maxsize, nsegments */ 568 BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 569 0, /* flags */ 570 NULL, NULL, /* lockfunc, lockarg */ 571 &sc->amr_sg_dmat); 572 if (error != 0) { 573 device_printf(sc->amr_dev, "can't allocate scatter/gather DMA tag\n"); 574 return(ENOMEM); 575 } 576 577 /* 578 * Allocate enough s/g maps for all commands and permanently map them into 579 * controller-visible space. 580 * 581 * XXX this assumes we can get enough space for all the s/g maps in one 582 * contiguous slab. We may need to switch to a more complex arrangement 583 * where we allocate in smaller chunks and keep a lookup table from slot 584 * to bus address. 585 * 586 * XXX HACK ALERT: at least some controllers don't like the s/g memory 587 * being allocated below 0x2000. We leak some memory if 588 * we get some below this mark and allocate again. We 589 * should be able to avoid this with the tag setup, but 590 * that does't seem to work. 591 */ 592retry: 593 error = bus_dmamem_alloc(sc->amr_sg_dmat, (void **)&p, BUS_DMA_NOWAIT, &sc->amr_sg_dmamap); 594 if (error) { 595 device_printf(sc->amr_dev, "can't allocate s/g table\n"); 596 return(ENOMEM); 597 } 598 bus_dmamap_load(sc->amr_sg_dmat, sc->amr_sg_dmamap, p, segsize, amr_sglist_map_helper, sc, 0); 599 if (sc->amr_sgbusaddr < 0x2000) { 600 debug(1, "s/g table too low (0x%x), reallocating\n", sc->amr_sgbusaddr); 601 goto retry; 602 } 603 604 if (AMR_IS_SG64(sc)) 605 sc->amr_sg64table = (struct amr_sg64entry *)p; 606 sc->amr_sgtable = (struct amr_sgentry *)p; 607 608 return(0); 609} 610 611/******************************************************************************** 612 * Allocate and set up mailbox areas for the controller (sc) 613 * 614 * The basic mailbox structure should be 16-byte aligned. This means that the 615 * mailbox64 structure has 4 bytes hanging off the bottom. 616 */ 617static void 618amr_setup_mbox_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 619{ 620 struct amr_softc *sc = (struct amr_softc *)arg; 621 622 debug_called(1); 623 624 /* save phsyical base of the basic mailbox structure */ 625 sc->amr_mailboxphys = segs->ds_addr + offsetof(struct amr_mailbox64, mb); 626} 627 628static int 629amr_setup_mbox(struct amr_softc *sc) 630{ 631 int error; 632 void *p; 633 634 debug_called(1); 635 636 /* 637 * Create a single tag describing a region large enough to hold the entire 638 * mailbox. 639 */ 640 error = bus_dma_tag_create(sc->amr_parent_dmat, /* parent */ 641 16, 0, /* alignment,boundary */ 642 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 643 BUS_SPACE_MAXADDR, /* highaddr */ 644 NULL, NULL, /* filter, filterarg */ 645 sizeof(struct amr_mailbox64), /* maxsize */ 646 1, /* nsegments */ 647 BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 648 0, /* flags */ 649 NULL, NULL, /* lockfunc, lockarg */ 650 &sc->amr_mailbox_dmat); 651 if (error != 0) { 652 device_printf(sc->amr_dev, "can't allocate mailbox tag\n"); 653 return(ENOMEM); 654 } 655 656 /* 657 * Allocate the mailbox structure and permanently map it into 658 * controller-visible space. 659 */ 660 error = bus_dmamem_alloc(sc->amr_mailbox_dmat, (void **)&p, BUS_DMA_NOWAIT, 661 &sc->amr_mailbox_dmamap); 662 if (error) { 663 device_printf(sc->amr_dev, "can't allocate mailbox memory\n"); 664 return(ENOMEM); 665 } 666 bus_dmamap_load(sc->amr_mailbox_dmat, sc->amr_mailbox_dmamap, p, 667 sizeof(struct amr_mailbox64), amr_setup_mbox_helper, sc, 0); 668 /* 669 * Conventional mailbox is inside the mailbox64 region. 670 */ 671 bzero(p, sizeof(struct amr_mailbox64)); 672 sc->amr_mailbox64 = (struct amr_mailbox64 *)p; 673 sc->amr_mailbox = &sc->amr_mailbox64->mb; 674 675 return(0); 676} 677