1139749Simp/*-
265942Sgibbs * FreeBSD, PCI product support functions
339222Sgibbs *
471717Sgibbs * Copyright (c) 1995-2001 Justin T. Gibbs
539222Sgibbs * All rights reserved.
639222Sgibbs *
739222Sgibbs * Redistribution and use in source and binary forms, with or without
839222Sgibbs * modification, are permitted provided that the following conditions
939222Sgibbs * are met:
1039222Sgibbs * 1. Redistributions of source code must retain the above copyright
1139222Sgibbs *    notice, this list of conditions, and the following disclaimer,
1239222Sgibbs *    without modification, immediately at the beginning of the file.
1339222Sgibbs * 2. The name of the author may not be used to endorse or promote products
1439222Sgibbs *    derived from this software without specific prior written permission.
1539222Sgibbs *
1663457Sgibbs * Alternatively, this software may be distributed under the terms of the
1763457Sgibbs * GNU Public License ("GPL").
1839222Sgibbs *
1939222Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2039222Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2139222Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2239222Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2339222Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2439222Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2539222Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2639222Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2739222Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2839222Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2939222Sgibbs * SUCH DAMAGE.
3039222Sgibbs *
31123579Sgibbs * $Id: //depot/aic7xxx/freebsd/dev/aic7xxx/ahc_pci.c#19 $
3239222Sgibbs */
3339222Sgibbs
34119418Sobrien#include <sys/cdefs.h>
35119418Sobrien__FBSDID("$FreeBSD$");
36119418Sobrien
3795378Sgibbs#include <dev/aic7xxx/aic7xxx_osm.h>
3839222Sgibbs
3945969Sgibbsstatic int ahc_pci_probe(device_t dev);
4045969Sgibbsstatic int ahc_pci_attach(device_t dev);
4139222Sgibbs
4295378Sgibbsstatic device_method_t ahc_pci_device_methods[] = {
4345969Sgibbs	/* Device interface */
4445969Sgibbs	DEVMETHOD(device_probe,		ahc_pci_probe),
4545969Sgibbs	DEVMETHOD(device_attach,	ahc_pci_attach),
4670204Sgibbs	DEVMETHOD(device_detach,	ahc_detach),
4745969Sgibbs	{ 0, 0 }
4845969Sgibbs};
4945969Sgibbs
5045969Sgibbsstatic driver_t ahc_pci_driver = {
51103811Sscottl	"ahc",
5295378Sgibbs	ahc_pci_device_methods,
5345969Sgibbs	sizeof(struct ahc_softc)
5439222Sgibbs};
5539222Sgibbs
56103811SscottlDRIVER_MODULE(ahc_pci, pci, ahc_pci_driver, ahc_devclass, 0, 0);
5776634SgibbsMODULE_DEPEND(ahc_pci, ahc, 1, 1, 1);
5876634SgibbsMODULE_VERSION(ahc_pci, 1);
5945969Sgibbs
6047275Sgibbsstatic int
6147275Sgibbsahc_pci_probe(device_t dev)
6247275Sgibbs{
6365942Sgibbs	struct	ahc_pci_identity *entry;
6447275Sgibbs
6547275Sgibbs	entry = ahc_find_pci_device(dev);
6647275Sgibbs	if (entry != NULL) {
6747275Sgibbs		device_set_desc(dev, entry->name);
68143164Simp		return (BUS_PROBE_DEFAULT);
6947275Sgibbs	}
7045969Sgibbs	return (ENXIO);
7139222Sgibbs}
7239222Sgibbs
7345969Sgibbsstatic int
7445969Sgibbsahc_pci_attach(device_t dev)
7539222Sgibbs{
7665942Sgibbs	struct	 ahc_pci_identity *entry;
7765942Sgibbs	struct	 ahc_softc *ahc;
7865942Sgibbs	char	*name;
7965942Sgibbs	int	 error;
8039222Sgibbs
8147275Sgibbs	entry = ahc_find_pci_device(dev);
8247275Sgibbs	if (entry == NULL)
8347275Sgibbs		return (ENXIO);
8439222Sgibbs
8565942Sgibbs	/*
8665942Sgibbs	 * Allocate a softc for this card and
8765942Sgibbs	 * set it up for attachment by our
8865942Sgibbs	 * common detect routine.
8965942Sgibbs	 */
9065942Sgibbs	name = malloc(strlen(device_get_nameunit(dev)) + 1, M_DEVBUF, M_NOWAIT);
9165942Sgibbs	if (name == NULL)
9245969Sgibbs		return (ENOMEM);
9365942Sgibbs	strcpy(name, device_get_nameunit(dev));
9470204Sgibbs	ahc = ahc_alloc(dev, name);
9565942Sgibbs	if (ahc == NULL)
9665942Sgibbs		return (ENOMEM);
9739222Sgibbs
9871390Sgibbs	ahc_set_unit(ahc, device_get_unit(dev));
9971390Sgibbs
10079874Sgibbs	/*
10179874Sgibbs	 * Should we bother disabling 39Bit addressing
10279874Sgibbs	 * based on installed memory?
10379874Sgibbs	 */
10479874Sgibbs	if (sizeof(bus_addr_t) > 4)
10579874Sgibbs                ahc->flags |= AHC_39BIT_ADDRESSING;
10679874Sgibbs
10739222Sgibbs	/* Allocate a dmatag for our SCB DMA maps */
108161928Sjmg	error = aic_dma_tag_create(ahc, /*parent*/bus_get_dma_tag(dev),
109161928Sjmg				   /*alignment*/1, /*boundary*/0,
11079874Sgibbs				   (ahc->flags & AHC_39BIT_ADDRESSING)
111121421Sdes				   ? 0x7FFFFFFFFFLL
11279874Sgibbs				   : BUS_SPACE_MAXADDR_32BIT,
11339222Sgibbs				   /*highaddr*/BUS_SPACE_MAXADDR,
11439222Sgibbs				   /*filter*/NULL, /*filterarg*/NULL,
115108479Sscottl				   /*maxsize*/BUS_SPACE_MAXSIZE_32BIT,
116108479Sscottl				   /*nsegments*/AHC_NSEG,
11739222Sgibbs				   /*maxsegsz*/AHC_MAXTRANSFER_SIZE,
118114618Sgibbs				   /*flags*/0,
11965942Sgibbs				   &ahc->parent_dmat);
12039222Sgibbs
12139222Sgibbs	if (error != 0) {
12245969Sgibbs		printf("ahc_pci_attach: Could not allocate DMA tag "
12345969Sgibbs		       "- error %d\n", error);
12439222Sgibbs		ahc_free(ahc);
12545969Sgibbs		return (ENOMEM);
12639222Sgibbs	}
12765942Sgibbs	ahc->dev_softc = dev;
12865942Sgibbs	error = ahc_pci_config(ahc, entry);
12965942Sgibbs	if (error != 0) {
13039222Sgibbs		ahc_free(ahc);
13165942Sgibbs		return (error);
13239222Sgibbs	}
13339222Sgibbs
13445969Sgibbs	ahc_attach(ahc);
13545969Sgibbs	return (0);
13639222Sgibbs}
13739222Sgibbs
13865942Sgibbsint
13965942Sgibbsahc_pci_map_registers(struct ahc_softc *ahc)
14055580Sgibbs{
14165942Sgibbs	struct	resource *regs;
14265942Sgibbs	int	regs_type;
14365942Sgibbs	int	regs_id;
144107418Sscottl	int	allow_memio;
14555580Sgibbs
14665942Sgibbs	regs = NULL;
14765942Sgibbs	regs_type = 0;
14865942Sgibbs	regs_id = 0;
149107418Sscottl
150107418Sscottl	/* Retrieve the per-device 'allow_memio' hint */
151107418Sscottl	if (resource_int_value(device_get_name(ahc->dev_softc),
152107418Sscottl			       device_get_unit(ahc->dev_softc),
153107418Sscottl			       "allow_memio", &allow_memio) != 0) {
154107418Sscottl		if (bootverbose)
155107418Sscottl			device_printf(ahc->dev_softc, "Defaulting to MEMIO ");
15666269Sgibbs#ifdef AHC_ALLOW_MEMIO
157107418Sscottl		if (bootverbose)
158107418Sscottl			printf("on\n");
159107418Sscottl		allow_memio = 1;
160107418Sscottl#else
161107418Sscottl		if (bootverbose)
162107418Sscottl			printf("off\n");
163107418Sscottl		allow_memio = 0;
164107418Sscottl#endif
165107418Sscottl	}
16670204Sgibbs
167254263Sscottl	if (allow_memio != 0) {
168107418Sscottl
16965942Sgibbs		regs_type = SYS_RES_MEMORY;
17065942Sgibbs		regs_id = AHC_PCI_MEMADDR;
171127135Snjl		regs = bus_alloc_resource_any(ahc->dev_softc, regs_type,
172127135Snjl					      &regs_id, RF_ACTIVE);
17365942Sgibbs		if (regs != NULL) {
17465942Sgibbs			ahc->tag = rman_get_bustag(regs);
17565942Sgibbs			ahc->bsh = rman_get_bushandle(regs);
17655580Sgibbs
17763457Sgibbs			/*
17865942Sgibbs			 * Do a quick test to see if memory mapped
17965942Sgibbs			 * I/O is functioning correctly.
18063457Sgibbs			 */
181107418Sscottl			if (ahc_pci_test_register_access(ahc) != 0) {
18265942Sgibbs				device_printf(ahc->dev_softc,
18365942Sgibbs				       "PCI Device %d:%d:%d failed memory "
18465942Sgibbs				       "mapped test.  Using PIO.\n",
185123579Sgibbs				       aic_get_pci_bus(ahc->dev_softc),
186123579Sgibbs				       aic_get_pci_slot(ahc->dev_softc),
187123579Sgibbs				       aic_get_pci_function(ahc->dev_softc));
18865942Sgibbs				bus_release_resource(ahc->dev_softc, regs_type,
18965942Sgibbs						     regs_id, regs);
19065942Sgibbs				regs = NULL;
19139222Sgibbs			}
19239222Sgibbs		}
19339222Sgibbs	}
194107418Sscottl
195254263Sscottl	if (regs == NULL) {
19665942Sgibbs		regs_type = SYS_RES_IOPORT;
19765942Sgibbs		regs_id = AHC_PCI_IOADDR;
198127135Snjl		regs = bus_alloc_resource_any(ahc->dev_softc, regs_type,
199127135Snjl					      &regs_id, RF_ACTIVE);
20079874Sgibbs		if (regs != NULL) {
20178555Smjacob			ahc->tag = rman_get_bustag(regs);
20278555Smjacob			ahc->bsh = rman_get_bushandle(regs);
203123579Sgibbs			if (ahc_pci_test_register_access(ahc) != 0) {
204123579Sgibbs				device_printf(ahc->dev_softc,
205123579Sgibbs				       "PCI Device %d:%d:%d failed I/O "
206123579Sgibbs				       "mapped test.\n",
207123579Sgibbs				       aic_get_pci_bus(ahc->dev_softc),
208123579Sgibbs				       aic_get_pci_slot(ahc->dev_softc),
209123579Sgibbs				       aic_get_pci_function(ahc->dev_softc));
210123579Sgibbs				bus_release_resource(ahc->dev_softc, regs_type,
211123579Sgibbs						     regs_id, regs);
212123579Sgibbs				regs = NULL;
213123579Sgibbs			}
21478555Smjacob		}
21563457Sgibbs	}
21665942Sgibbs	if (regs == NULL) {
21765942Sgibbs		device_printf(ahc->dev_softc,
21865942Sgibbs			      "can't allocate register resources\n");
21965942Sgibbs		return (ENOMEM);
22039222Sgibbs	}
22179874Sgibbs	ahc->platform_data->regs_res_type = regs_type;
22279874Sgibbs	ahc->platform_data->regs_res_id = regs_id;
22379874Sgibbs	ahc->platform_data->regs = regs;
22447192Sgibbs	return (0);
22547192Sgibbs}
226