xref: /freebsd/sys/dev/aic7xxx/ahd_pci.c (revision 65971073d935e8314bff8bca26d1445e9e336fce)
1098ca2bdSWarner Losh /*-
217d24755SJustin T. Gibbs  * FreeBSD, PCI product support functions
317d24755SJustin T. Gibbs  *
417d24755SJustin T. Gibbs  * Copyright (c) 1995-2001 Justin T. Gibbs
517d24755SJustin T. Gibbs  * All rights reserved.
617d24755SJustin T. Gibbs  *
717d24755SJustin T. Gibbs  * Redistribution and use in source and binary forms, with or without
817d24755SJustin T. Gibbs  * modification, are permitted provided that the following conditions
917d24755SJustin T. Gibbs  * are met:
1017d24755SJustin T. Gibbs  * 1. Redistributions of source code must retain the above copyright
1117d24755SJustin T. Gibbs  *    notice, this list of conditions, and the following disclaimer,
1217d24755SJustin T. Gibbs  *    without modification, immediately at the beginning of the file.
1317d24755SJustin T. Gibbs  * 2. The name of the author may not be used to endorse or promote products
1417d24755SJustin T. Gibbs  *    derived from this software without specific prior written permission.
1517d24755SJustin T. Gibbs  *
1617d24755SJustin T. Gibbs  * Alternatively, this software may be distributed under the terms of the
1717d24755SJustin T. Gibbs  * GNU Public License ("GPL").
1817d24755SJustin T. Gibbs  *
1917d24755SJustin T. Gibbs  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2017d24755SJustin T. Gibbs  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2117d24755SJustin T. Gibbs  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2217d24755SJustin T. Gibbs  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2317d24755SJustin T. Gibbs  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2417d24755SJustin T. Gibbs  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2517d24755SJustin T. Gibbs  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2617d24755SJustin T. Gibbs  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2717d24755SJustin T. Gibbs  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2817d24755SJustin T. Gibbs  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2917d24755SJustin T. Gibbs  * SUCH DAMAGE.
3017d24755SJustin T. Gibbs  *
31b3b25f2cSJustin T. Gibbs  * $Id: //depot/aic7xxx/freebsd/dev/aic7xxx/ahd_pci.c#17 $
3217d24755SJustin T. Gibbs  */
3317d24755SJustin T. Gibbs 
3417d24755SJustin T. Gibbs #include <dev/aic7xxx/aic79xx_osm.h>
3517d24755SJustin T. Gibbs 
3617d24755SJustin T. Gibbs static int ahd_pci_probe(device_t dev);
3717d24755SJustin T. Gibbs static int ahd_pci_attach(device_t dev);
3817d24755SJustin T. Gibbs 
3917d24755SJustin T. Gibbs static device_method_t ahd_pci_device_methods[] = {
4017d24755SJustin T. Gibbs 	/* Device interface */
4117d24755SJustin T. Gibbs 	DEVMETHOD(device_probe,		ahd_pci_probe),
4217d24755SJustin T. Gibbs 	DEVMETHOD(device_attach,	ahd_pci_attach),
4317d24755SJustin T. Gibbs 	DEVMETHOD(device_detach,	ahd_detach),
4417d24755SJustin T. Gibbs 	{ 0, 0 }
4517d24755SJustin T. Gibbs };
4617d24755SJustin T. Gibbs 
4717d24755SJustin T. Gibbs static driver_t ahd_pci_driver = {
4817d24755SJustin T. Gibbs 	"ahd",
4917d24755SJustin T. Gibbs 	ahd_pci_device_methods,
5017d24755SJustin T. Gibbs 	sizeof(struct ahd_softc)
5117d24755SJustin T. Gibbs };
5217d24755SJustin T. Gibbs 
53*43fb772cSJohn Baldwin DRIVER_MODULE(ahd, pci, ahd_pci_driver, 0, 0);
5417d24755SJustin T. Gibbs MODULE_DEPEND(ahd_pci, ahd, 1, 1, 1);
5517d24755SJustin T. Gibbs MODULE_VERSION(ahd_pci, 1);
5617d24755SJustin T. Gibbs 
5717d24755SJustin T. Gibbs static int
5817d24755SJustin T. Gibbs ahd_pci_probe(device_t dev)
5917d24755SJustin T. Gibbs {
6017d24755SJustin T. Gibbs 	struct	ahd_pci_identity *entry;
6117d24755SJustin T. Gibbs 
6217d24755SJustin T. Gibbs 	entry = ahd_find_pci_device(dev);
6317d24755SJustin T. Gibbs 	if (entry != NULL) {
6417d24755SJustin T. Gibbs 		device_set_desc(dev, entry->name);
65494f3ca1SWarner Losh 		return (BUS_PROBE_DEFAULT);
6617d24755SJustin T. Gibbs 	}
6717d24755SJustin T. Gibbs 	return (ENXIO);
6817d24755SJustin T. Gibbs }
6917d24755SJustin T. Gibbs 
7017d24755SJustin T. Gibbs static int
7117d24755SJustin T. Gibbs ahd_pci_attach(device_t dev)
7217d24755SJustin T. Gibbs {
7317d24755SJustin T. Gibbs 	struct	 ahd_pci_identity *entry;
7417d24755SJustin T. Gibbs 	struct	 ahd_softc *ahd;
7517d24755SJustin T. Gibbs 	char	*name;
7617d24755SJustin T. Gibbs 	int	 error;
7717d24755SJustin T. Gibbs 
7817d24755SJustin T. Gibbs 	entry = ahd_find_pci_device(dev);
7917d24755SJustin T. Gibbs 	if (entry == NULL)
8017d24755SJustin T. Gibbs 		return (ENXIO);
8117d24755SJustin T. Gibbs 
8217d24755SJustin T. Gibbs 	/*
8317d24755SJustin T. Gibbs 	 * Allocate a softc for this card and
8417d24755SJustin T. Gibbs 	 * set it up for attachment by our
8517d24755SJustin T. Gibbs 	 * common detect routine.
8617d24755SJustin T. Gibbs 	 */
8717d24755SJustin T. Gibbs 	name = malloc(strlen(device_get_nameunit(dev)) + 1, M_DEVBUF, M_NOWAIT);
8817d24755SJustin T. Gibbs 	if (name == NULL)
8917d24755SJustin T. Gibbs 		return (ENOMEM);
9017d24755SJustin T. Gibbs 	strcpy(name, device_get_nameunit(dev));
9117d24755SJustin T. Gibbs 	ahd = ahd_alloc(dev, name);
9217d24755SJustin T. Gibbs 	if (ahd == NULL)
9317d24755SJustin T. Gibbs 		return (ENOMEM);
9417d24755SJustin T. Gibbs 
9517d24755SJustin T. Gibbs 	ahd_set_unit(ahd, device_get_unit(dev));
9617d24755SJustin T. Gibbs 
9717d24755SJustin T. Gibbs 	/*
9817d24755SJustin T. Gibbs 	 * Should we bother disabling 39Bit addressing
9917d24755SJustin T. Gibbs 	 * based on installed memory?
10017d24755SJustin T. Gibbs 	 */
10117d24755SJustin T. Gibbs 	if (sizeof(bus_addr_t) > 4)
10217d24755SJustin T. Gibbs                 ahd->flags |= AHD_39BIT_ADDRESSING;
10317d24755SJustin T. Gibbs 
10417d24755SJustin T. Gibbs 	/* Allocate a dmatag for our SCB DMA maps */
105378f231eSJohn-Mark Gurney 	error = aic_dma_tag_create(ahd, /*parent*/bus_get_dma_tag(dev),
106378f231eSJohn-Mark Gurney 				   /*alignment*/1, /*boundary*/0,
10717d24755SJustin T. Gibbs 				   (ahd->flags & AHD_39BIT_ADDRESSING)
108b3b25f2cSJustin T. Gibbs 				   ? 0x7FFFFFFFFF
10917d24755SJustin T. Gibbs 				   : BUS_SPACE_MAXADDR_32BIT,
11017d24755SJustin T. Gibbs 				   /*highaddr*/BUS_SPACE_MAXADDR,
11117d24755SJustin T. Gibbs 				   /*filter*/NULL, /*filterarg*/NULL,
1121c754048SScott Long 				   /*maxsize*/BUS_SPACE_MAXSIZE_32BIT,
1131c754048SScott Long 				   /*nsegments*/AHD_NSEG,
11417d24755SJustin T. Gibbs 				   /*maxsegsz*/AHD_MAXTRANSFER_SIZE,
1158270490aSJustin T. Gibbs 				   /*flags*/0,
11617d24755SJustin T. Gibbs 				   &ahd->parent_dmat);
11717d24755SJustin T. Gibbs 
11817d24755SJustin T. Gibbs 	if (error != 0) {
11917d24755SJustin T. Gibbs 		printf("ahd_pci_attach: Could not allocate DMA tag "
12017d24755SJustin T. Gibbs 		       "- error %d\n", error);
12117d24755SJustin T. Gibbs 		ahd_free(ahd);
12217d24755SJustin T. Gibbs 		return (ENOMEM);
12317d24755SJustin T. Gibbs 	}
12417d24755SJustin T. Gibbs 	ahd->dev_softc = dev;
12517d24755SJustin T. Gibbs 	error = ahd_pci_config(ahd, entry);
12617d24755SJustin T. Gibbs 	if (error != 0) {
12717d24755SJustin T. Gibbs 		ahd_free(ahd);
12817d24755SJustin T. Gibbs 		return (error);
12917d24755SJustin T. Gibbs 	}
13017d24755SJustin T. Gibbs 
131884015f6SAttilio Rao 	ahd_sysctl(ahd);
13217d24755SJustin T. Gibbs 	ahd_attach(ahd);
13317d24755SJustin T. Gibbs 	return (0);
13417d24755SJustin T. Gibbs }
13517d24755SJustin T. Gibbs 
13617d24755SJustin T. Gibbs int
13717d24755SJustin T. Gibbs ahd_pci_map_registers(struct ahd_softc *ahd)
13817d24755SJustin T. Gibbs {
13917d24755SJustin T. Gibbs 	struct	resource *regs;
14017d24755SJustin T. Gibbs 	struct	resource *regs2;
14117d24755SJustin T. Gibbs 	int	regs_type;
14217d24755SJustin T. Gibbs 	int	regs_id;
14317d24755SJustin T. Gibbs 	int	regs_id2;
14497cae63dSScott Long 	int	allow_memio;
14517d24755SJustin T. Gibbs 
14617d24755SJustin T. Gibbs 	regs = NULL;
14717d24755SJustin T. Gibbs 	regs2 = NULL;
14817d24755SJustin T. Gibbs 	regs_type = 0;
14917d24755SJustin T. Gibbs 	regs_id = 0;
15097cae63dSScott Long 
15197cae63dSScott Long 	/* Retrieve the per-device 'allow_memio' hint */
15297cae63dSScott Long 	if (resource_int_value(device_get_name(ahd->dev_softc),
15397cae63dSScott Long 			       device_get_unit(ahd->dev_softc),
15497cae63dSScott Long 			       "allow_memio", &allow_memio) != 0) {
15597cae63dSScott Long 		if (bootverbose)
15697cae63dSScott Long 			device_printf(ahd->dev_softc,
15797cae63dSScott Long 				      "Defaulting to MEMIO on\n");
1586bdc5bdfSJustin T. Gibbs 		allow_memio = 1;
15997cae63dSScott Long 	}
16097cae63dSScott Long 
161c68534f1SScott Long 	if ((ahd->bugs & AHD_PCIX_MMAPIO_BUG) == 0
16297cae63dSScott Long 	 && allow_memio != 0) {
16317d24755SJustin T. Gibbs 		regs_type = SYS_RES_MEMORY;
16417d24755SJustin T. Gibbs 		regs_id = AHD_PCI_MEMADDR;
1655f96beb9SNate Lawson 		regs = bus_alloc_resource_any(ahd->dev_softc, regs_type,
1665f96beb9SNate Lawson 					      &regs_id, RF_ACTIVE);
16717d24755SJustin T. Gibbs 		if (regs != NULL) {
16817d24755SJustin T. Gibbs 			int error;
16917d24755SJustin T. Gibbs 
17017d24755SJustin T. Gibbs 			ahd->tags[0] = rman_get_bustag(regs);
17117d24755SJustin T. Gibbs 			ahd->bshs[0] = rman_get_bushandle(regs);
17217d24755SJustin T. Gibbs 			ahd->tags[1] = ahd->tags[0];
17317d24755SJustin T. Gibbs 			error = bus_space_subregion(ahd->tags[0], ahd->bshs[0],
17417d24755SJustin T. Gibbs 						    /*offset*/0x100,
17517d24755SJustin T. Gibbs 						    /*size*/0x100,
17617d24755SJustin T. Gibbs 						    &ahd->bshs[1]);
17717d24755SJustin T. Gibbs 			/*
17817d24755SJustin T. Gibbs 			 * Do a quick test to see if memory mapped
17917d24755SJustin T. Gibbs 			 * I/O is functioning correctly.
18017d24755SJustin T. Gibbs 			 */
181add68794SScott Long 			if (error != 0
182add68794SScott Long 			 || ahd_pci_test_register_access(ahd) != 0) {
18317d24755SJustin T. Gibbs 				device_printf(ahd->dev_softc,
18417d24755SJustin T. Gibbs 				       "PCI Device %d:%d:%d failed memory "
18517d24755SJustin T. Gibbs 				       "mapped test.  Using PIO.\n",
186b3b25f2cSJustin T. Gibbs 				       aic_get_pci_bus(ahd->dev_softc),
187b3b25f2cSJustin T. Gibbs 				       aic_get_pci_slot(ahd->dev_softc),
188b3b25f2cSJustin T. Gibbs 				       aic_get_pci_function(ahd->dev_softc));
18917d24755SJustin T. Gibbs 				bus_release_resource(ahd->dev_softc, regs_type,
19017d24755SJustin T. Gibbs 						     regs_id, regs);
19117d24755SJustin T. Gibbs 				regs = NULL;
192884015f6SAttilio Rao 				AHD_CORRECTABLE_ERROR(ahd);
19317d24755SJustin T. Gibbs 			}
19417d24755SJustin T. Gibbs 		}
19517d24755SJustin T. Gibbs 	}
196c68534f1SScott Long 	if (regs == NULL) {
19717d24755SJustin T. Gibbs 		regs_type = SYS_RES_IOPORT;
19817d24755SJustin T. Gibbs 		regs_id = AHD_PCI_IOADDR0;
1995f96beb9SNate Lawson 		regs = bus_alloc_resource_any(ahd->dev_softc, regs_type,
2005f96beb9SNate Lawson 					      &regs_id, RF_ACTIVE);
20117d24755SJustin T. Gibbs 		if (regs == NULL) {
20217d24755SJustin T. Gibbs 			device_printf(ahd->dev_softc,
20317d24755SJustin T. Gibbs 				      "can't allocate register resources\n");
204884015f6SAttilio Rao 			AHD_UNCORRECTABLE_ERROR(ahd);
20517d24755SJustin T. Gibbs 			return (ENOMEM);
20617d24755SJustin T. Gibbs 		}
20717d24755SJustin T. Gibbs 		ahd->tags[0] = rman_get_bustag(regs);
20817d24755SJustin T. Gibbs 		ahd->bshs[0] = rman_get_bushandle(regs);
20917d24755SJustin T. Gibbs 
21017d24755SJustin T. Gibbs 		/* And now the second BAR */
21117d24755SJustin T. Gibbs 		regs_id2 = AHD_PCI_IOADDR1;
2125f96beb9SNate Lawson 		regs2 = bus_alloc_resource_any(ahd->dev_softc, regs_type,
2135f96beb9SNate Lawson 					       &regs_id2, RF_ACTIVE);
21417d24755SJustin T. Gibbs 		if (regs2 == NULL) {
21517d24755SJustin T. Gibbs 			device_printf(ahd->dev_softc,
21617d24755SJustin T. Gibbs 				      "can't allocate register resources\n");
217884015f6SAttilio Rao 			AHD_UNCORRECTABLE_ERROR(ahd);
21817d24755SJustin T. Gibbs 			return (ENOMEM);
21917d24755SJustin T. Gibbs 		}
22017d24755SJustin T. Gibbs 		ahd->tags[1] = rman_get_bustag(regs2);
22117d24755SJustin T. Gibbs 		ahd->bshs[1] = rman_get_bushandle(regs2);
22217d24755SJustin T. Gibbs 		ahd->platform_data->regs_res_type[1] = regs_type;
22317d24755SJustin T. Gibbs 		ahd->platform_data->regs_res_id[1] = regs_id2;
22417d24755SJustin T. Gibbs 		ahd->platform_data->regs[1] = regs2;
22517d24755SJustin T. Gibbs 	}
22617d24755SJustin T. Gibbs 	ahd->platform_data->regs_res_type[0] = regs_type;
22717d24755SJustin T. Gibbs 	ahd->platform_data->regs_res_id[0] = regs_id;
22817d24755SJustin T. Gibbs 	ahd->platform_data->regs[0] = regs;
22917d24755SJustin T. Gibbs 	return (0);
23017d24755SJustin T. Gibbs }
23117d24755SJustin T. Gibbs 
23217d24755SJustin T. Gibbs int
23317d24755SJustin T. Gibbs ahd_pci_map_int(struct ahd_softc *ahd)
23417d24755SJustin T. Gibbs {
23517d24755SJustin T. Gibbs 	int zero;
23617d24755SJustin T. Gibbs 
23717d24755SJustin T. Gibbs 	zero = 0;
23817d24755SJustin T. Gibbs 	ahd->platform_data->irq =
2395f96beb9SNate Lawson 	    bus_alloc_resource_any(ahd->dev_softc, SYS_RES_IRQ, &zero,
2405f96beb9SNate Lawson 				   RF_ACTIVE | RF_SHAREABLE);
24117d24755SJustin T. Gibbs 	if (ahd->platform_data->irq == NULL)
24217d24755SJustin T. Gibbs 		return (ENOMEM);
24317d24755SJustin T. Gibbs 	ahd->platform_data->irq_res_type = SYS_RES_IRQ;
24417d24755SJustin T. Gibbs 	return (ahd_map_int(ahd));
24517d24755SJustin T. Gibbs }
246