xref: /freebsd-src/sys/dev/aic7xxx/ahc_pci.c (revision c733dc7a6f866eeae0ac7762e6f1dee22e24c4d3)
1098ca2bdSWarner Losh /*-
2717d4247SJustin T. Gibbs  * FreeBSD, PCI product support functions
34530878eSJustin T. Gibbs  *
464a3876fSJustin T. Gibbs  * Copyright (c) 1995-2001 Justin T. Gibbs
54530878eSJustin T. Gibbs  * All rights reserved.
64530878eSJustin T. Gibbs  *
74530878eSJustin T. Gibbs  * Redistribution and use in source and binary forms, with or without
84530878eSJustin T. Gibbs  * modification, are permitted provided that the following conditions
94530878eSJustin T. Gibbs  * are met:
104530878eSJustin T. Gibbs  * 1. Redistributions of source code must retain the above copyright
114530878eSJustin T. Gibbs  *    notice, this list of conditions, and the following disclaimer,
124530878eSJustin T. Gibbs  *    without modification, immediately at the beginning of the file.
134530878eSJustin T. Gibbs  * 2. The name of the author may not be used to endorse or promote products
144530878eSJustin T. Gibbs  *    derived from this software without specific prior written permission.
154530878eSJustin T. Gibbs  *
16aa6dfd9dSJustin T. Gibbs  * Alternatively, this software may be distributed under the terms of the
17aa6dfd9dSJustin T. Gibbs  * GNU Public License ("GPL").
184530878eSJustin T. Gibbs  *
194530878eSJustin T. Gibbs  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
204530878eSJustin T. Gibbs  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
214530878eSJustin T. Gibbs  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
224530878eSJustin T. Gibbs  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
234530878eSJustin T. Gibbs  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
244530878eSJustin T. Gibbs  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
254530878eSJustin T. Gibbs  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
264530878eSJustin T. Gibbs  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
274530878eSJustin T. Gibbs  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
284530878eSJustin T. Gibbs  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
294530878eSJustin T. Gibbs  * SUCH DAMAGE.
304530878eSJustin T. Gibbs  *
31b3b25f2cSJustin T. Gibbs  * $Id: //depot/aic7xxx/freebsd/dev/aic7xxx/ahc_pci.c#19 $
324530878eSJustin T. Gibbs  */
334530878eSJustin T. Gibbs 
348f214efcSJustin T. Gibbs #include <dev/aic7xxx/aic7xxx_osm.h>
354530878eSJustin T. Gibbs 
361d283093SJustin T. Gibbs static int ahc_pci_probe(device_t dev);
371d283093SJustin T. Gibbs static int ahc_pci_attach(device_t dev);
384530878eSJustin T. Gibbs 
398f214efcSJustin T. Gibbs static device_method_t ahc_pci_device_methods[] = {
401d283093SJustin T. Gibbs 	/* Device interface */
411d283093SJustin T. Gibbs 	DEVMETHOD(device_probe,		ahc_pci_probe),
421d283093SJustin T. Gibbs 	DEVMETHOD(device_attach,	ahc_pci_attach),
4356a7c4a8SJustin T. Gibbs 	DEVMETHOD(device_detach,	ahc_detach),
441d283093SJustin T. Gibbs 	{ 0, 0 }
454530878eSJustin T. Gibbs };
464530878eSJustin T. Gibbs 
471d283093SJustin T. Gibbs static driver_t ahc_pci_driver = {
48c57c56c4SScott Long 	"ahc",
498f214efcSJustin T. Gibbs 	ahc_pci_device_methods,
501d283093SJustin T. Gibbs 	sizeof(struct ahc_softc)
511d283093SJustin T. Gibbs };
524530878eSJustin T. Gibbs 
5343fb772cSJohn Baldwin DRIVER_MODULE(ahc_pci, pci, ahc_pci_driver, 0, 0);
5458fb7d8eSJustin T. Gibbs MODULE_DEPEND(ahc_pci, ahc, 1, 1, 1);
5558fb7d8eSJustin T. Gibbs MODULE_VERSION(ahc_pci, 1);
561d283093SJustin T. Gibbs 
57923dc21bSJustin T. Gibbs static int
ahc_pci_probe(device_t dev)58923dc21bSJustin T. Gibbs ahc_pci_probe(device_t dev)
59923dc21bSJustin T. Gibbs {
60923dc21bSJustin T. Gibbs 	struct	ahc_pci_identity *entry;
61923dc21bSJustin T. Gibbs 
62923dc21bSJustin T. Gibbs 	entry = ahc_find_pci_device(dev);
63923dc21bSJustin T. Gibbs 	if (entry != NULL) {
64168d6886SJustin T. Gibbs 		device_set_desc(dev, entry->name);
65494f3ca1SWarner Losh 		return (BUS_PROBE_DEFAULT);
661d283093SJustin T. Gibbs 	}
671d283093SJustin T. Gibbs 	return (ENXIO);
684530878eSJustin T. Gibbs }
694530878eSJustin T. Gibbs 
701d283093SJustin T. Gibbs static int
ahc_pci_attach(device_t dev)711d283093SJustin T. Gibbs ahc_pci_attach(device_t dev)
724530878eSJustin T. Gibbs {
73923dc21bSJustin T. Gibbs 	struct	 ahc_pci_identity *entry;
744530878eSJustin T. Gibbs 	struct	 ahc_softc *ahc;
75717d4247SJustin T. Gibbs 	char	*name;
764530878eSJustin T. Gibbs 	int	 error;
774530878eSJustin T. Gibbs 
78923dc21bSJustin T. Gibbs 	entry = ahc_find_pci_device(dev);
79923dc21bSJustin T. Gibbs 	if (entry == NULL)
80923dc21bSJustin T. Gibbs 		return (ENXIO);
814530878eSJustin T. Gibbs 
82717d4247SJustin T. Gibbs 	/*
83717d4247SJustin T. Gibbs 	 * Allocate a softc for this card and
84717d4247SJustin T. Gibbs 	 * set it up for attachment by our
85717d4247SJustin T. Gibbs 	 * common detect routine.
86717d4247SJustin T. Gibbs 	 */
87717d4247SJustin T. Gibbs 	name = malloc(strlen(device_get_nameunit(dev)) + 1, M_DEVBUF, M_NOWAIT);
88717d4247SJustin T. Gibbs 	if (name == NULL)
891d283093SJustin T. Gibbs 		return (ENOMEM);
90717d4247SJustin T. Gibbs 	strcpy(name, device_get_nameunit(dev));
9156a7c4a8SJustin T. Gibbs 	ahc = ahc_alloc(dev, name);
92717d4247SJustin T. Gibbs 	if (ahc == NULL)
93717d4247SJustin T. Gibbs 		return (ENOMEM);
944530878eSJustin T. Gibbs 
95a5847d5cSJustin T. Gibbs 	ahc_set_unit(ahc, device_get_unit(dev));
96a5847d5cSJustin T. Gibbs 
97cd036e89SJustin T. Gibbs 	/*
98cd036e89SJustin T. Gibbs 	 * Should we bother disabling 39Bit addressing
99cd036e89SJustin T. Gibbs 	 * based on installed memory?
100cd036e89SJustin T. Gibbs 	 */
101cd036e89SJustin T. Gibbs 	if (sizeof(bus_addr_t) > 4)
102cd036e89SJustin T. Gibbs                 ahc->flags |= AHC_39BIT_ADDRESSING;
103cd036e89SJustin T. Gibbs 
1044530878eSJustin T. Gibbs 	/* Allocate a dmatag for our SCB DMA maps */
105378f231eSJohn-Mark Gurney 	error = aic_dma_tag_create(ahc, /*parent*/bus_get_dma_tag(dev),
106378f231eSJohn-Mark Gurney 				   /*alignment*/1, /*boundary*/0,
107cd036e89SJustin T. Gibbs 				   (ahc->flags & AHC_39BIT_ADDRESSING)
10876bfe7b1SDag-Erling Smørgrav 				   ? 0x7FFFFFFFFFLL
109cd036e89SJustin T. Gibbs 				   : BUS_SPACE_MAXADDR_32BIT,
1104530878eSJustin T. Gibbs 				   /*highaddr*/BUS_SPACE_MAXADDR,
1114530878eSJustin T. Gibbs 				   /*filter*/NULL, /*filterarg*/NULL,
1121c754048SScott Long 				   /*maxsize*/BUS_SPACE_MAXSIZE_32BIT,
1131c754048SScott Long 				   /*nsegments*/AHC_NSEG,
1144530878eSJustin T. Gibbs 				   /*maxsegsz*/AHC_MAXTRANSFER_SIZE,
1158270490aSJustin T. Gibbs 				   /*flags*/0,
116717d4247SJustin T. Gibbs 				   &ahc->parent_dmat);
1174530878eSJustin T. Gibbs 
1184530878eSJustin T. Gibbs 	if (error != 0) {
1191d283093SJustin T. Gibbs 		printf("ahc_pci_attach: Could not allocate DMA tag "
1201d283093SJustin T. Gibbs 		       "- error %d\n", error);
1214530878eSJustin T. Gibbs 		ahc_free(ahc);
1221d283093SJustin T. Gibbs 		return (ENOMEM);
1234530878eSJustin T. Gibbs 	}
124717d4247SJustin T. Gibbs 	ahc->dev_softc = dev;
125717d4247SJustin T. Gibbs 	error = ahc_pci_config(ahc, entry);
126717d4247SJustin T. Gibbs 	if (error != 0) {
1274530878eSJustin T. Gibbs 		ahc_free(ahc);
128717d4247SJustin T. Gibbs 		return (error);
1294530878eSJustin T. Gibbs 	}
1304530878eSJustin T. Gibbs 
1314530878eSJustin T. Gibbs 	ahc_attach(ahc);
1321d283093SJustin T. Gibbs 	return (0);
1334530878eSJustin T. Gibbs }
1344530878eSJustin T. Gibbs 
135717d4247SJustin T. Gibbs int
ahc_pci_map_registers(struct ahc_softc * ahc)136717d4247SJustin T. Gibbs ahc_pci_map_registers(struct ahc_softc *ahc)
13777dd8468SJustin T. Gibbs {
138717d4247SJustin T. Gibbs 	struct	resource *regs;
139717d4247SJustin T. Gibbs 	int	regs_type;
140717d4247SJustin T. Gibbs 	int	regs_id;
141*c733dc7aSHP van Braam 	int	allow_memio = 1;
14277dd8468SJustin T. Gibbs 
143717d4247SJustin T. Gibbs 	regs = NULL;
144717d4247SJustin T. Gibbs 	regs_type = 0;
145717d4247SJustin T. Gibbs 	regs_id = 0;
14624dd01c6SScott Long 
14724dd01c6SScott Long 	/* Retrieve the per-device 'allow_memio' hint */
14824dd01c6SScott Long 	if (resource_int_value(device_get_name(ahc->dev_softc),
14924dd01c6SScott Long 			       device_get_unit(ahc->dev_softc),
15024dd01c6SScott Long 			       "allow_memio", &allow_memio) != 0) {
15124dd01c6SScott Long 		if (bootverbose)
15224dd01c6SScott Long 			device_printf(ahc->dev_softc, "Defaulting to MEMIO ");
153*c733dc7aSHP van Braam #if defined(AHC_ALLOW_MEMIO) && (AHC_ALLOW_MEMIO == 0)
15424dd01c6SScott Long 		if (bootverbose)
15524dd01c6SScott Long 			printf("off\n");
15624dd01c6SScott Long 		allow_memio = 0;
157*c733dc7aSHP van Braam #else
158*c733dc7aSHP van Braam 		if (bootverbose)
159*c733dc7aSHP van Braam 			printf("on\n");
160*c733dc7aSHP van Braam 		allow_memio = 1;
16124dd01c6SScott Long #endif
16224dd01c6SScott Long 	}
16324dd01c6SScott Long 
164c68534f1SScott Long 	if (allow_memio != 0) {
165717d4247SJustin T. Gibbs 		regs_type = SYS_RES_MEMORY;
166717d4247SJustin T. Gibbs 		regs_id = AHC_PCI_MEMADDR;
1675f96beb9SNate Lawson 		regs = bus_alloc_resource_any(ahc->dev_softc, regs_type,
1685f96beb9SNate Lawson 					      &regs_id, RF_ACTIVE);
169717d4247SJustin T. Gibbs 		if (regs != NULL) {
170717d4247SJustin T. Gibbs 			ahc->tag = rman_get_bustag(regs);
171717d4247SJustin T. Gibbs 			ahc->bsh = rman_get_bushandle(regs);
17277dd8468SJustin T. Gibbs 
17377dd8468SJustin T. Gibbs 			/*
174717d4247SJustin T. Gibbs 			 * Do a quick test to see if memory mapped
175717d4247SJustin T. Gibbs 			 * I/O is functioning correctly.
17677dd8468SJustin T. Gibbs 			 */
17724dd01c6SScott Long 			if (ahc_pci_test_register_access(ahc) != 0) {
178717d4247SJustin T. Gibbs 				device_printf(ahc->dev_softc,
179717d4247SJustin T. Gibbs 				       "PCI Device %d:%d:%d failed memory "
180717d4247SJustin T. Gibbs 				       "mapped test.  Using PIO.\n",
181b3b25f2cSJustin T. Gibbs 				       aic_get_pci_bus(ahc->dev_softc),
182b3b25f2cSJustin T. Gibbs 				       aic_get_pci_slot(ahc->dev_softc),
183b3b25f2cSJustin T. Gibbs 				       aic_get_pci_function(ahc->dev_softc));
184717d4247SJustin T. Gibbs 				bus_release_resource(ahc->dev_softc, regs_type,
185717d4247SJustin T. Gibbs 						     regs_id, regs);
186717d4247SJustin T. Gibbs 				regs = NULL;
18777dd8468SJustin T. Gibbs 			}
18877dd8468SJustin T. Gibbs 		}
18977dd8468SJustin T. Gibbs 	}
19024dd01c6SScott Long 
191c68534f1SScott Long 	if (regs == NULL) {
192717d4247SJustin T. Gibbs 		regs_type = SYS_RES_IOPORT;
193717d4247SJustin T. Gibbs 		regs_id = AHC_PCI_IOADDR;
1945f96beb9SNate Lawson 		regs = bus_alloc_resource_any(ahc->dev_softc, regs_type,
1955f96beb9SNate Lawson 					      &regs_id, RF_ACTIVE);
196cd036e89SJustin T. Gibbs 		if (regs != NULL) {
197717d4247SJustin T. Gibbs 			ahc->tag = rman_get_bustag(regs);
198717d4247SJustin T. Gibbs 			ahc->bsh = rman_get_bushandle(regs);
199b3b25f2cSJustin T. Gibbs 			if (ahc_pci_test_register_access(ahc) != 0) {
200b3b25f2cSJustin T. Gibbs 				device_printf(ahc->dev_softc,
201b3b25f2cSJustin T. Gibbs 				       "PCI Device %d:%d:%d failed I/O "
202b3b25f2cSJustin T. Gibbs 				       "mapped test.\n",
203b3b25f2cSJustin T. Gibbs 				       aic_get_pci_bus(ahc->dev_softc),
204b3b25f2cSJustin T. Gibbs 				       aic_get_pci_slot(ahc->dev_softc),
205b3b25f2cSJustin T. Gibbs 				       aic_get_pci_function(ahc->dev_softc));
206b3b25f2cSJustin T. Gibbs 				bus_release_resource(ahc->dev_softc, regs_type,
207b3b25f2cSJustin T. Gibbs 						     regs_id, regs);
208b3b25f2cSJustin T. Gibbs 				regs = NULL;
20977dd8468SJustin T. Gibbs 			}
2100e300effSMatt Jacob 		}
211b3b25f2cSJustin T. Gibbs 	}
212717d4247SJustin T. Gibbs 	if (regs == NULL) {
213717d4247SJustin T. Gibbs 		device_printf(ahc->dev_softc,
214717d4247SJustin T. Gibbs 			      "can't allocate register resources\n");
215717d4247SJustin T. Gibbs 		return (ENOMEM);
216168d6886SJustin T. Gibbs 	}
217cd036e89SJustin T. Gibbs 	ahc->platform_data->regs_res_type = regs_type;
218cd036e89SJustin T. Gibbs 	ahc->platform_data->regs_res_id = regs_id;
219cd036e89SJustin T. Gibbs 	ahc->platform_data->regs = regs;
220168d6886SJustin T. Gibbs 	return (0);
221168d6886SJustin T. Gibbs }
222