151974Smsmith/*- 265245Smsmith * Copyright (c) 1999,2000 Michael Smith 365245Smsmith * Copyright (c) 2000 BSDi 451974Smsmith * All rights reserved. 551974Smsmith * 651974Smsmith * Redistribution and use in source and binary forms, with or without 751974Smsmith * modification, are permitted provided that the following conditions 851974Smsmith * are met: 951974Smsmith * 1. Redistributions of source code must retain the above copyright 1051974Smsmith * notice, this list of conditions and the following disclaimer. 1151974Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1251974Smsmith * notice, this list of conditions and the following disclaimer in the 1351974Smsmith * documentation and/or other materials provided with the distribution. 1451974Smsmith * 1551974Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1651974Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1751974Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1851974Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1951974Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2051974Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2151974Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2251974Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2351974Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2451974Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2551974Smsmith * SUCH DAMAGE. 26119418Sobrien */ 27139749Simp/*- 28106225Semoore * Copyright (c) 2002 Eric Moore 29140688Sscottl * Copyright (c) 2002, 2004 LSI Logic Corporation 30106225Semoore * All rights reserved. 31106225Semoore * 32106225Semoore * Redistribution and use in source and binary forms, with or without 33106225Semoore * modification, are permitted provided that the following conditions 34106225Semoore * are met: 35106225Semoore * 1. Redistributions of source code must retain the above copyright 36106225Semoore * notice, this list of conditions and the following disclaimer. 37106225Semoore * 2. Redistributions in binary form must reproduce the above copyright 38106225Semoore * notice, this list of conditions and the following disclaimer in the 39106225Semoore * documentation and/or other materials provided with the distribution. 40105419Semoore * 3. The party using or redistributing the source code and binary forms 41106225Semoore * agrees to the disclaimer below and the terms and conditions set forth 42105419Semoore * herein. 43105419Semoore * 44106225Semoore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 45106225Semoore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 46106225Semoore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 47106225Semoore * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 48106225Semoore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 49106225Semoore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 50106225Semoore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 51106225Semoore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 52106225Semoore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 53106225Semoore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 54106225Semoore * SUCH DAMAGE. 5551974Smsmith */ 5651974Smsmith 57119418Sobrien#include <sys/cdefs.h> 58119418Sobrien__FBSDID("$FreeBSD$"); 59119418Sobrien 6051974Smsmith#include <sys/param.h> 6151974Smsmith#include <sys/systm.h> 6251974Smsmith#include <sys/kernel.h> 63129879Sphk#include <sys/module.h> 64153409Sscottl#include <sys/sysctl.h> 6551974Smsmith 66148850Sscottl#include <sys/bio.h> 6751974Smsmith#include <sys/bus.h> 6851974Smsmith#include <sys/conf.h> 6951974Smsmith 7051974Smsmith#include <machine/bus.h> 7151974Smsmith#include <machine/resource.h> 7251974Smsmith#include <sys/rman.h> 7351974Smsmith 74119277Simp#include <dev/pci/pcireg.h> 75119277Simp#include <dev/pci/pcivar.h> 7651974Smsmith 7751974Smsmith#include <dev/amr/amrio.h> 7851974Smsmith#include <dev/amr/amrreg.h> 7951974Smsmith#include <dev/amr/amrvar.h> 8051974Smsmith 8165245Smsmithstatic int amr_pci_probe(device_t dev); 8265245Smsmithstatic int amr_pci_attach(device_t dev); 8365245Smsmithstatic int amr_pci_detach(device_t dev); 8465245Smsmithstatic int amr_pci_shutdown(device_t dev); 8565245Smsmithstatic int amr_pci_suspend(device_t dev); 8665245Smsmithstatic int amr_pci_resume(device_t dev); 8765245Smsmithstatic void amr_pci_intr(void *arg); 8865245Smsmithstatic void amr_pci_free(struct amr_softc *sc); 89174544Sscottlstatic void amr_sglist_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error); 9065245Smsmithstatic int amr_sglist_map(struct amr_softc *sc); 9165245Smsmithstatic int amr_setup_mbox(struct amr_softc *sc); 92174544Sscottlstatic int amr_ccb_map(struct amr_softc *sc); 9351974Smsmith 94153409Sscottlstatic u_int amr_force_sg32 = 0; 95153409SscottlTUNABLE_INT("hw.amr.force_sg32", &amr_force_sg32); 96153409SscottlSYSCTL_DECL(_hw_amr); 97153409SscottlSYSCTL_UINT(_hw_amr, OID_AUTO, force_sg32, CTLFLAG_RDTUN, &amr_force_sg32, 0, 98153409Sscottl "Force the AMR driver to use 32bit scatter gather"); 99153409Sscottl 10051974Smsmithstatic device_method_t amr_methods[] = { 10151974Smsmith /* Device interface */ 10251974Smsmith DEVMETHOD(device_probe, amr_pci_probe), 10351974Smsmith DEVMETHOD(device_attach, amr_pci_attach), 10465245Smsmith DEVMETHOD(device_detach, amr_pci_detach), 10565245Smsmith DEVMETHOD(device_shutdown, amr_pci_shutdown), 10665245Smsmith DEVMETHOD(device_suspend, amr_pci_suspend), 10765245Smsmith DEVMETHOD(device_resume, amr_pci_resume), 10851974Smsmith 109227843Smarius DEVMETHOD_END 11051974Smsmith}; 11151974Smsmith 11251974Smsmithstatic driver_t amr_pci_driver = { 11351974Smsmith "amr", 11451974Smsmith amr_methods, 11551974Smsmith sizeof(struct amr_softc) 11651974Smsmith}; 11751974Smsmith 11889055Smsmithstatic devclass_t amr_devclass; 11951974SmsmithDRIVER_MODULE(amr, pci, amr_pci_driver, amr_devclass, 0, 0); 120165102SmjacobMODULE_DEPEND(amr, pci, 1, 1, 1); 121165102SmjacobMODULE_DEPEND(amr, cam, 1, 1, 1); 12251974Smsmith 123153409Sscottlstatic struct amr_ident 12451974Smsmith{ 12551974Smsmith int vendor; 12651974Smsmith int device; 127153409Sscottl int flags; 128153409Sscottl#define AMR_ID_PROBE_SIG (1<<0) /* generic i960RD, check signature */ 129153409Sscottl#define AMR_ID_DO_SG64 (1<<1) 130153409Sscottl#define AMR_ID_QUARTZ (1<<2) 13151974Smsmith} amr_device_ids[] = { 13251974Smsmith {0x101e, 0x9010, 0}, 13351974Smsmith {0x101e, 0x9060, 0}, 134153409Sscottl {0x8086, 0x1960, AMR_ID_QUARTZ | AMR_ID_PROBE_SIG}, 135153409Sscottl {0x101e, 0x1960, AMR_ID_QUARTZ}, 136155223Sps {0x1000, 0x1960, AMR_ID_QUARTZ | AMR_ID_DO_SG64 | AMR_ID_PROBE_SIG}, 137153409Sscottl {0x1000, 0x0407, AMR_ID_QUARTZ | AMR_ID_DO_SG64}, 138153409Sscottl {0x1000, 0x0408, AMR_ID_QUARTZ | AMR_ID_DO_SG64}, 139153409Sscottl {0x1000, 0x0409, AMR_ID_QUARTZ | AMR_ID_DO_SG64}, 140153409Sscottl {0x1028, 0x000e, AMR_ID_QUARTZ | AMR_ID_DO_SG64 | AMR_ID_PROBE_SIG}, /* perc4/di i960 */ 141153409Sscottl {0x1028, 0x000f, AMR_ID_QUARTZ | AMR_ID_DO_SG64}, /* perc4/di Verde*/ 142153409Sscottl {0x1028, 0x0013, AMR_ID_QUARTZ | AMR_ID_DO_SG64}, /* perc4/di */ 14351974Smsmith {0, 0, 0} 14451974Smsmith}; 145105419Semoore 146153409Sscottlstatic struct amr_ident * 147153409Sscottlamr_find_ident(device_t dev) 14851974Smsmith{ 149153409Sscottl struct amr_ident *id; 150153409Sscottl int sig; 15151974Smsmith 152153409Sscottl for (id = amr_device_ids; id->vendor != 0; id++) { 153153409Sscottl if ((pci_get_vendor(dev) == id->vendor) && 154153409Sscottl (pci_get_device(dev) == id->device)) { 15551974Smsmith 15651974Smsmith /* do we need to test for a signature? */ 157153409Sscottl if (id->flags & AMR_ID_PROBE_SIG) { 15870285Smsmith sig = pci_read_config(dev, AMR_CFG_SIG, 2); 15970285Smsmith if ((sig != AMR_SIGNATURE_1) && (sig != AMR_SIGNATURE_2)) 16070285Smsmith continue; 16170285Smsmith } 162153409Sscottl return (id); 16351974Smsmith } 16451974Smsmith } 165153409Sscottl return (NULL); 166153409Sscottl} 167153409Sscottl 168153409Sscottlstatic int 169153409Sscottlamr_pci_probe(device_t dev) 170153409Sscottl{ 171153409Sscottl 172153409Sscottl debug_called(1); 173153409Sscottl 174153409Sscottl if (amr_find_ident(dev) != NULL) { 175153409Sscottl device_set_desc(dev, LSI_DESC_PCI); 176153409Sscottl return(BUS_PROBE_DEFAULT); 177153409Sscottl } 17851974Smsmith return(ENXIO); 17951974Smsmith} 18051974Smsmith 18151974Smsmithstatic int 18251974Smsmithamr_pci_attach(device_t dev) 18351974Smsmith{ 18451974Smsmith struct amr_softc *sc; 185153409Sscottl struct amr_ident *id; 18651974Smsmith int rid, rtype, error; 18751974Smsmith 18865245Smsmith debug_called(1); 18951974Smsmith 19051974Smsmith /* 19151974Smsmith * Initialise softc. 19251974Smsmith */ 19351974Smsmith sc = device_get_softc(dev); 19451974Smsmith bzero(sc, sizeof(*sc)); 19551974Smsmith sc->amr_dev = dev; 19651974Smsmith 19765245Smsmith /* assume failure is 'not configured' */ 19865245Smsmith error = ENXIO; 19965245Smsmith 20051974Smsmith /* 20165245Smsmith * Determine board type. 20251974Smsmith */ 203153409Sscottl if ((id = amr_find_ident(dev)) == NULL) 204153409Sscottl return (ENXIO); 205153409Sscottl 206153409Sscottl if (id->flags & AMR_ID_QUARTZ) { 20765245Smsmith sc->amr_type |= AMR_TYPE_QUARTZ; 20851974Smsmith } 20951974Smsmith 210153409Sscottl if ((amr_force_sg32 == 0) && (id->flags & AMR_ID_DO_SG64) && 211153409Sscottl (sizeof(vm_paddr_t) > 4)) { 212153409Sscottl device_printf(dev, "Using 64-bit DMA\n"); 213153409Sscottl sc->amr_type |= AMR_TYPE_SG64; 214153409Sscottl } 215153409Sscottl 21658883Smsmith /* force the busmaster enable bit on */ 217254263Sscottl pci_enable_busmaster(dev); 21858883Smsmith 21951974Smsmith /* 22051974Smsmith * Allocate the PCI register window. 22151974Smsmith */ 222119690Sjhb rid = PCIR_BAR(0); 22365245Smsmith rtype = AMR_IS_QUARTZ(sc) ? SYS_RES_MEMORY : SYS_RES_IOPORT; 224127135Snjl sc->amr_reg = bus_alloc_resource_any(dev, rtype, &rid, RF_ACTIVE); 22551974Smsmith if (sc->amr_reg == NULL) { 22665245Smsmith device_printf(sc->amr_dev, "can't allocate register window\n"); 22765245Smsmith goto out; 22851974Smsmith } 22951974Smsmith sc->amr_btag = rman_get_bustag(sc->amr_reg); 23051974Smsmith sc->amr_bhandle = rman_get_bushandle(sc->amr_reg); 23151974Smsmith 23251974Smsmith /* 23365245Smsmith * Allocate and connect our interrupt. 23465245Smsmith */ 23565245Smsmith rid = 0; 236127135Snjl sc->amr_irq = bus_alloc_resource_any(sc->amr_dev, SYS_RES_IRQ, &rid, 237127135Snjl RF_SHAREABLE | RF_ACTIVE); 23865245Smsmith if (sc->amr_irq == NULL) { 23965245Smsmith device_printf(sc->amr_dev, "can't allocate interrupt\n"); 24065245Smsmith goto out; 24165245Smsmith } 242153409Sscottl if (bus_setup_intr(sc->amr_dev, sc->amr_irq, 243166901Spiso INTR_TYPE_BIO | INTR_ENTROPY | INTR_MPSAFE, NULL, amr_pci_intr, 244153409Sscottl sc, &sc->amr_intr)) { 24565245Smsmith device_printf(sc->amr_dev, "can't set up interrupt\n"); 24665245Smsmith goto out; 24765245Smsmith } 24865245Smsmith 24965245Smsmith debug(2, "interrupt attached"); 25065245Smsmith 25165245Smsmith /* assume failure is 'out of memory' */ 25265245Smsmith error = ENOMEM; 25365245Smsmith 25465245Smsmith /* 25551974Smsmith * Allocate the parent bus DMA tag appropriate for PCI. 25651974Smsmith */ 257232854Sscottl if (bus_dma_tag_create(bus_get_dma_tag(dev), /* PCI parent */ 258153409Sscottl 1, 0, /* alignment,boundary */ 259153409Sscottl AMR_IS_SG64(sc) ? 260153409Sscottl BUS_SPACE_MAXADDR : 26165245Smsmith BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 26265245Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 26365245Smsmith NULL, NULL, /* filter, filterarg */ 26465245Smsmith MAXBSIZE, AMR_NSEG, /* maxsize, nsegments */ 26565245Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 266138422Sscottl 0, /* flags */ 267117126Sscottl NULL, NULL, /* lockfunc, lockarg */ 26865245Smsmith &sc->amr_parent_dmat)) { 26965245Smsmith device_printf(dev, "can't allocate parent DMA tag\n"); 27065245Smsmith goto out; 27165245Smsmith } 27265245Smsmith 27365245Smsmith /* 27465245Smsmith * Create DMA tag for mapping buffers into controller-addressable space. 27565245Smsmith */ 27665245Smsmith if (bus_dma_tag_create(sc->amr_parent_dmat, /* parent */ 277153409Sscottl 1, 0, /* alignment,boundary */ 278138422Sscottl BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 27965245Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 28065245Smsmith NULL, NULL, /* filter, filterarg */ 28165245Smsmith MAXBSIZE, AMR_NSEG, /* maxsize, nsegments */ 282138422Sscottl MAXBSIZE, /* maxsegsize */ 283174544Sscottl 0, /* flags */ 284153409Sscottl busdma_lock_mutex, /* lockfunc */ 285153409Sscottl &sc->amr_list_lock, /* lockarg */ 28665245Smsmith &sc->amr_buffer_dmat)) { 28765245Smsmith device_printf(sc->amr_dev, "can't allocate buffer DMA tag\n"); 28865245Smsmith goto out; 28965245Smsmith } 29065245Smsmith 291153409Sscottl if (bus_dma_tag_create(sc->amr_parent_dmat, /* parent */ 292153409Sscottl 1, 0, /* alignment,boundary */ 293153409Sscottl BUS_SPACE_MAXADDR, /* lowaddr */ 294153409Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 295153409Sscottl NULL, NULL, /* filter, filterarg */ 296153409Sscottl MAXBSIZE, AMR_NSEG, /* maxsize, nsegments */ 297153409Sscottl MAXBSIZE, /* maxsegsize */ 298174544Sscottl 0, /* flags */ 299153409Sscottl busdma_lock_mutex, /* lockfunc */ 300153409Sscottl &sc->amr_list_lock, /* lockarg */ 301153409Sscottl &sc->amr_buffer64_dmat)) { 302153409Sscottl device_printf(sc->amr_dev, "can't allocate buffer DMA tag\n"); 303153409Sscottl goto out; 304153409Sscottl } 305153409Sscottl 30665245Smsmith debug(2, "dma tag done"); 30765245Smsmith 30865245Smsmith /* 30965245Smsmith * Allocate and set up mailbox in a bus-visible fashion. 31065245Smsmith */ 311153409Sscottl mtx_init(&sc->amr_list_lock, "AMR List Lock", NULL, MTX_DEF); 312153409Sscottl mtx_init(&sc->amr_hw_lock, "AMR HW Lock", NULL, MTX_DEF); 31365245Smsmith if ((error = amr_setup_mbox(sc)) != 0) 31465245Smsmith goto out; 31565245Smsmith 31665245Smsmith debug(2, "mailbox setup"); 31765245Smsmith 31865245Smsmith /* 31965245Smsmith * Build the scatter/gather buffers. 32065245Smsmith */ 321232255Skevlo if ((error = amr_sglist_map(sc)) != 0) 32265245Smsmith goto out; 32365245Smsmith debug(2, "s/g list mapped"); 32465245Smsmith 325232255Skevlo if ((error = amr_ccb_map(sc)) != 0) 326174544Sscottl goto out; 327174544Sscottl debug(2, "ccb mapped"); 328174544Sscottl 329174544Sscottl 33065245Smsmith /* 33165245Smsmith * Do bus-independant initialisation, bring controller online. 33265245Smsmith */ 33365245Smsmith error = amr_attach(sc); 33465245Smsmith 33565245Smsmithout: 33665245Smsmith if (error) 33765245Smsmith amr_pci_free(sc); 33865245Smsmith return(error); 33965245Smsmith} 34065245Smsmith 34165245Smsmith/******************************************************************************** 34265245Smsmith * Disconnect from the controller completely, in preparation for unload. 34365245Smsmith */ 34465245Smsmithstatic int 34565245Smsmithamr_pci_detach(device_t dev) 34665245Smsmith{ 34765245Smsmith struct amr_softc *sc = device_get_softc(dev); 34865245Smsmith int error; 34965245Smsmith 35065245Smsmith debug_called(1); 35165245Smsmith 35265245Smsmith if (sc->amr_state & AMR_STATE_OPEN) 35365245Smsmith return(EBUSY); 35465245Smsmith 35565245Smsmith if ((error = amr_pci_shutdown(dev))) 35665245Smsmith return(error); 35765245Smsmith 35865245Smsmith amr_pci_free(sc); 35965245Smsmith 36065245Smsmith return(0); 36165245Smsmith} 36265245Smsmith 36365245Smsmith/******************************************************************************** 36465245Smsmith * Bring the controller down to a dormant state and detach all child devices. 36565245Smsmith * 36665245Smsmith * This function is called before detach, system shutdown, or before performing 36765245Smsmith * an operation which may add or delete system disks. (Call amr_startup to 36865245Smsmith * resume normal operation.) 36965245Smsmith * 37065245Smsmith * Note that we can assume that the bioq on the controller is empty, as we won't 37165245Smsmith * allow shutdown if any device is open. 37265245Smsmith */ 37365245Smsmithstatic int 37465245Smsmithamr_pci_shutdown(device_t dev) 37565245Smsmith{ 37665245Smsmith struct amr_softc *sc = device_get_softc(dev); 377152119Sscottl int i,error; 37865245Smsmith 37965245Smsmith debug_called(1); 38065245Smsmith 38165245Smsmith /* mark ourselves as in-shutdown */ 38265245Smsmith sc->amr_state |= AMR_STATE_SHUTDOWN; 38365245Smsmith 38465245Smsmith 38565245Smsmith /* flush controller */ 38665245Smsmith device_printf(sc->amr_dev, "flushing cache..."); 38765245Smsmith printf("%s\n", amr_flush(sc) ? "failed" : "done"); 38865245Smsmith 389107756Semoore error = 0; 390107756Semoore 391107756Semoore /* delete all our child devices */ 392107756Semoore for(i = 0 ; i < AMR_MAXLD; i++) { 393107756Semoore if( sc->amr_drive[i].al_disk != 0) { 394107756Semoore if((error = device_delete_child(sc->amr_dev,sc->amr_drive[i].al_disk)) != 0) 395107756Semoore goto shutdown_out; 396107756Semoore sc->amr_drive[i].al_disk = 0; 397107756Semoore } 398107756Semoore } 399107756Semoore 40065245Smsmith /* XXX disable interrupts? */ 401107756Semoore 402107756Semooreshutdown_out: 403107756Semoore return(error); 40465245Smsmith} 40565245Smsmith 40665245Smsmith/******************************************************************************** 40765245Smsmith * Bring the controller to a quiescent state, ready for system suspend. 40865245Smsmith */ 40965245Smsmithstatic int 41065245Smsmithamr_pci_suspend(device_t dev) 41165245Smsmith{ 41265245Smsmith struct amr_softc *sc = device_get_softc(dev); 41365245Smsmith 41465245Smsmith debug_called(1); 41565245Smsmith 41665245Smsmith sc->amr_state |= AMR_STATE_SUSPEND; 41765245Smsmith 41865245Smsmith /* flush controller */ 41965245Smsmith device_printf(sc->amr_dev, "flushing cache..."); 42065245Smsmith printf("%s\n", amr_flush(sc) ? "failed" : "done"); 42165245Smsmith 42265245Smsmith /* XXX disable interrupts? */ 42365245Smsmith 42465245Smsmith return(0); 42565245Smsmith} 42665245Smsmith 42765245Smsmith/******************************************************************************** 42865245Smsmith * Bring the controller back to a state ready for operation. 42965245Smsmith */ 43065245Smsmithstatic int 43165245Smsmithamr_pci_resume(device_t dev) 43265245Smsmith{ 43365245Smsmith struct amr_softc *sc = device_get_softc(dev); 43465245Smsmith 43565245Smsmith debug_called(1); 43665245Smsmith 43765245Smsmith sc->amr_state &= ~AMR_STATE_SUSPEND; 43865245Smsmith 43965245Smsmith /* XXX enable interrupts? */ 44065245Smsmith 44165245Smsmith return(0); 44265245Smsmith} 44365245Smsmith 44465245Smsmith/******************************************************************************* 44565245Smsmith * Take an interrupt, or be poked by other code to look for interrupt-worthy 44665245Smsmith * status. 44765245Smsmith */ 44865245Smsmithstatic void 44965245Smsmithamr_pci_intr(void *arg) 45065245Smsmith{ 45165245Smsmith struct amr_softc *sc = (struct amr_softc *)arg; 45265245Smsmith 453174544Sscottl debug_called(3); 45465245Smsmith 45565245Smsmith /* collect finished commands, queue anything waiting */ 45665245Smsmith amr_done(sc); 45765245Smsmith} 45865245Smsmith 45965245Smsmith/******************************************************************************** 46065245Smsmith * Free all of the resources associated with (sc) 46165245Smsmith * 46265245Smsmith * Should not be called if the controller is active. 46365245Smsmith */ 46465245Smsmithstatic void 46565245Smsmithamr_pci_free(struct amr_softc *sc) 46665245Smsmith{ 467174185Sscottl void *p; 468153409Sscottl 46965245Smsmith debug_called(1); 47065245Smsmith 47165245Smsmith amr_free(sc); 47265245Smsmith 47365245Smsmith /* destroy data-transfer DMA tag */ 47465245Smsmith if (sc->amr_buffer_dmat) 47565245Smsmith bus_dma_tag_destroy(sc->amr_buffer_dmat); 476153409Sscottl if (sc->amr_buffer64_dmat) 477153409Sscottl bus_dma_tag_destroy(sc->amr_buffer64_dmat); 47865245Smsmith 479174544Sscottl /* free and destroy DMA memory and tag for passthrough pool */ 480174544Sscottl if (sc->amr_ccb) 481174544Sscottl bus_dmamem_free(sc->amr_ccb_dmat, sc->amr_ccb, sc->amr_ccb_dmamap); 482174544Sscottl if (sc->amr_ccb_dmat) 483174544Sscottl bus_dma_tag_destroy(sc->amr_ccb_dmat); 484174544Sscottl 48565245Smsmith /* free and destroy DMA memory and tag for s/g lists */ 48665245Smsmith if (sc->amr_sgtable) 48765245Smsmith bus_dmamem_free(sc->amr_sg_dmat, sc->amr_sgtable, sc->amr_sg_dmamap); 48865245Smsmith if (sc->amr_sg_dmat) 48965245Smsmith bus_dma_tag_destroy(sc->amr_sg_dmat); 49065245Smsmith 49165245Smsmith /* free and destroy DMA memory and tag for mailbox */ 492155317Simp p = (void *)(uintptr_t)(volatile void *)sc->amr_mailbox64; 49365245Smsmith if (sc->amr_mailbox) { 494153409Sscottl bus_dmamem_free(sc->amr_mailbox_dmat, p, sc->amr_mailbox_dmamap); 49565245Smsmith } 496106225Semoore if (sc->amr_mailbox_dmat) 497106225Semoore bus_dma_tag_destroy(sc->amr_mailbox_dmat); 49865245Smsmith 49965245Smsmith /* disconnect the interrupt handler */ 50065245Smsmith if (sc->amr_intr) 50165245Smsmith bus_teardown_intr(sc->amr_dev, sc->amr_irq, sc->amr_intr); 50265245Smsmith if (sc->amr_irq != NULL) 50365245Smsmith bus_release_resource(sc->amr_dev, SYS_RES_IRQ, 0, sc->amr_irq); 50465245Smsmith 50565245Smsmith /* destroy the parent DMA tag */ 50665245Smsmith if (sc->amr_parent_dmat) 50765245Smsmith bus_dma_tag_destroy(sc->amr_parent_dmat); 50865245Smsmith 50965245Smsmith /* release the register window mapping */ 51065245Smsmith if (sc->amr_reg != NULL) 51165245Smsmith bus_release_resource(sc->amr_dev, 51265245Smsmith AMR_IS_QUARTZ(sc) ? SYS_RES_MEMORY : SYS_RES_IOPORT, 513119690Sjhb PCIR_BAR(0), sc->amr_reg); 51465245Smsmith} 51565245Smsmith 51665245Smsmith/******************************************************************************** 51765245Smsmith * Allocate and map the scatter/gather table in bus space. 51865245Smsmith */ 51965245Smsmithstatic void 520174544Sscottlamr_sglist_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 52165245Smsmith{ 522174544Sscottl uint32_t *addr; 52365245Smsmith 52465245Smsmith debug_called(1); 52565245Smsmith 526174544Sscottl addr = arg; 527174544Sscottl *addr = segs[0].ds_addr; 52865245Smsmith} 52965245Smsmith 53065245Smsmithstatic int 53165245Smsmithamr_sglist_map(struct amr_softc *sc) 53265245Smsmith{ 53365245Smsmith size_t segsize; 534155317Simp void *p; 53565245Smsmith int error; 53665245Smsmith 53765245Smsmith debug_called(1); 53865245Smsmith 53965245Smsmith /* 54065245Smsmith * Create a single tag describing a region large enough to hold all of 54165245Smsmith * the s/g lists we will need. 54265245Smsmith * 543153409Sscottl * Note that we could probably use AMR_LIMITCMD here, but that may become 544153409Sscottl * tunable. 54565245Smsmith */ 546153409Sscottl if (AMR_IS_SG64(sc)) 547153409Sscottl segsize = sizeof(struct amr_sg64entry) * AMR_NSEG * AMR_MAXCMD; 548153409Sscottl else 549153409Sscottl segsize = sizeof(struct amr_sgentry) * AMR_NSEG * AMR_MAXCMD; 550153409Sscottl 55165245Smsmith error = bus_dma_tag_create(sc->amr_parent_dmat, /* parent */ 552174544Sscottl 512, 0, /* alignment,boundary */ 553138422Sscottl BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 55451974Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 55551974Smsmith NULL, NULL, /* filter, filterarg */ 55665245Smsmith segsize, 1, /* maxsize, nsegments */ 55751974Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 55865245Smsmith 0, /* flags */ 559153409Sscottl NULL, NULL, /* lockfunc, lockarg */ 56065245Smsmith &sc->amr_sg_dmat); 56151974Smsmith if (error != 0) { 56265245Smsmith device_printf(sc->amr_dev, "can't allocate scatter/gather DMA tag\n"); 56351974Smsmith return(ENOMEM); 56451974Smsmith } 56551974Smsmith 56651974Smsmith /* 56765245Smsmith * Allocate enough s/g maps for all commands and permanently map them into 56865245Smsmith * controller-visible space. 56965245Smsmith * 57065245Smsmith * XXX this assumes we can get enough space for all the s/g maps in one 571153409Sscottl * contiguous slab. We may need to switch to a more complex arrangement 572153409Sscottl * where we allocate in smaller chunks and keep a lookup table from slot 573153409Sscottl * to bus address. 57465245Smsmith * 575153409Sscottl * XXX HACK ALERT: at least some controllers don't like the s/g memory 576153409Sscottl * being allocated below 0x2000. We leak some memory if 577153409Sscottl * we get some below this mark and allocate again. We 578153409Sscottl * should be able to avoid this with the tag setup, but 579153409Sscottl * that does't seem to work. 58051974Smsmith */ 58165245Smsmithretry: 582153409Sscottl error = bus_dmamem_alloc(sc->amr_sg_dmat, (void **)&p, BUS_DMA_NOWAIT, &sc->amr_sg_dmamap); 58365245Smsmith if (error) { 58465245Smsmith device_printf(sc->amr_dev, "can't allocate s/g table\n"); 58565245Smsmith return(ENOMEM); 58651974Smsmith } 587174544Sscottl bus_dmamap_load(sc->amr_sg_dmat, sc->amr_sg_dmamap, p, segsize, amr_sglist_helper, &sc->amr_sgbusaddr, 0); 58865245Smsmith if (sc->amr_sgbusaddr < 0x2000) { 58965245Smsmith debug(1, "s/g table too low (0x%x), reallocating\n", sc->amr_sgbusaddr); 59065245Smsmith goto retry; 59165245Smsmith } 592153409Sscottl 593153409Sscottl if (AMR_IS_SG64(sc)) 594153409Sscottl sc->amr_sg64table = (struct amr_sg64entry *)p; 595153409Sscottl sc->amr_sgtable = (struct amr_sgentry *)p; 596153409Sscottl 59765245Smsmith return(0); 59865245Smsmith} 59965245Smsmith 60065245Smsmith/******************************************************************************** 60165245Smsmith * Allocate and set up mailbox areas for the controller (sc) 60265245Smsmith * 603174544Sscottl * The basic mailbox structure should be 16-byte aligned. 60465245Smsmith */ 60565245Smsmithstatic int 60665245Smsmithamr_setup_mbox(struct amr_softc *sc) 60765245Smsmith{ 60865245Smsmith int error; 609155317Simp void *p; 610174544Sscottl uint32_t baddr; 61165245Smsmith 61265245Smsmith debug_called(1); 61365245Smsmith 61451974Smsmith /* 61565245Smsmith * Create a single tag describing a region large enough to hold the entire 61665245Smsmith * mailbox. 61751974Smsmith */ 61865245Smsmith error = bus_dma_tag_create(sc->amr_parent_dmat, /* parent */ 619153409Sscottl 16, 0, /* alignment,boundary */ 620138422Sscottl BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 62165245Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 62265245Smsmith NULL, NULL, /* filter, filterarg */ 623153409Sscottl sizeof(struct amr_mailbox64), /* maxsize */ 624153409Sscottl 1, /* nsegments */ 62565245Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 62665245Smsmith 0, /* flags */ 627153409Sscottl NULL, NULL, /* lockfunc, lockarg */ 62865245Smsmith &sc->amr_mailbox_dmat); 62965245Smsmith if (error != 0) { 63065245Smsmith device_printf(sc->amr_dev, "can't allocate mailbox tag\n"); 63165245Smsmith return(ENOMEM); 63265245Smsmith } 63365245Smsmith 63465245Smsmith /* 63565245Smsmith * Allocate the mailbox structure and permanently map it into 63665245Smsmith * controller-visible space. 63765245Smsmith */ 638106225Semoore error = bus_dmamem_alloc(sc->amr_mailbox_dmat, (void **)&p, BUS_DMA_NOWAIT, 63965245Smsmith &sc->amr_mailbox_dmamap); 64065245Smsmith if (error) { 64165245Smsmith device_printf(sc->amr_dev, "can't allocate mailbox memory\n"); 64265245Smsmith return(ENOMEM); 64365245Smsmith } 644106225Semoore bus_dmamap_load(sc->amr_mailbox_dmat, sc->amr_mailbox_dmamap, p, 645174544Sscottl sizeof(struct amr_mailbox64), amr_sglist_helper, &baddr, 0); 64665245Smsmith /* 64765245Smsmith * Conventional mailbox is inside the mailbox64 region. 64865245Smsmith */ 649174544Sscottl /* save physical base of the basic mailbox structure */ 650174544Sscottl sc->amr_mailboxphys = baddr + offsetof(struct amr_mailbox64, mb); 65165245Smsmith bzero(p, sizeof(struct amr_mailbox64)); 652153409Sscottl sc->amr_mailbox64 = (struct amr_mailbox64 *)p; 653153409Sscottl sc->amr_mailbox = &sc->amr_mailbox64->mb; 65465245Smsmith 65551974Smsmith return(0); 65651974Smsmith} 657174544Sscottl 658174544Sscottlstatic int 659174544Sscottlamr_ccb_map(struct amr_softc *sc) 660174544Sscottl{ 661174544Sscottl int ccbsize, error; 662174544Sscottl 663174544Sscottl /* 664174544Sscottl * Passthrough and Extended passthrough structures will share the same 665174544Sscottl * memory. 666174544Sscottl */ 667174544Sscottl ccbsize = sizeof(union amr_ccb) * AMR_MAXCMD; 668174544Sscottl error = bus_dma_tag_create(sc->amr_parent_dmat, /* parent */ 669174544Sscottl 128, 0, /* alignment,boundary */ 670174544Sscottl BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 671174544Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 672174544Sscottl NULL, NULL, /* filter, filterarg */ 673174544Sscottl ccbsize, /* maxsize */ 674174544Sscottl 1, /* nsegments */ 675174544Sscottl ccbsize, /* maxsegsize */ 676174544Sscottl 0, /* flags */ 677174544Sscottl NULL, NULL, /* lockfunc, lockarg */ 678174544Sscottl &sc->amr_ccb_dmat); 679174544Sscottl if (error != 0) { 680174544Sscottl device_printf(sc->amr_dev, "can't allocate ccb tag\n"); 681174544Sscottl return (ENOMEM); 682174544Sscottl } 683174544Sscottl 684174544Sscottl error = bus_dmamem_alloc(sc->amr_ccb_dmat, (void **)&sc->amr_ccb, 685174544Sscottl BUS_DMA_NOWAIT, &sc->amr_ccb_dmamap); 686174544Sscottl if (error) { 687174544Sscottl device_printf(sc->amr_dev, "can't allocate ccb memory\n"); 688174544Sscottl return (ENOMEM); 689174544Sscottl } 690174544Sscottl bus_dmamap_load(sc->amr_ccb_dmat, sc->amr_ccb_dmamap, sc->amr_ccb, 691174544Sscottl ccbsize, amr_sglist_helper, &sc->amr_ccb_busaddr, 0); 692174544Sscottl bzero(sc->amr_ccb, ccbsize); 693174544Sscottl 694174544Sscottl return (0); 695174544Sscottl} 696174544Sscottl 697