xref: /freebsd/sys/dev/aic7xxx/ahd_pci.c (revision 098ca2bda93c701c5331d4e6aace072495b4caaa)
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 
34aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
35aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$");
36aad970f1SDavid E. O'Brien 
3717d24755SJustin T. Gibbs #include <dev/aic7xxx/aic79xx_osm.h>
3817d24755SJustin T. Gibbs 
3917d24755SJustin T. Gibbs static int ahd_pci_probe(device_t dev);
4017d24755SJustin T. Gibbs static int ahd_pci_attach(device_t dev);
4117d24755SJustin T. Gibbs 
4217d24755SJustin T. Gibbs static device_method_t ahd_pci_device_methods[] = {
4317d24755SJustin T. Gibbs 	/* Device interface */
4417d24755SJustin T. Gibbs 	DEVMETHOD(device_probe,		ahd_pci_probe),
4517d24755SJustin T. Gibbs 	DEVMETHOD(device_attach,	ahd_pci_attach),
4617d24755SJustin T. Gibbs 	DEVMETHOD(device_detach,	ahd_detach),
4717d24755SJustin T. Gibbs 	{ 0, 0 }
4817d24755SJustin T. Gibbs };
4917d24755SJustin T. Gibbs 
5017d24755SJustin T. Gibbs static driver_t ahd_pci_driver = {
5117d24755SJustin T. Gibbs 	"ahd",
5217d24755SJustin T. Gibbs 	ahd_pci_device_methods,
5317d24755SJustin T. Gibbs 	sizeof(struct ahd_softc)
5417d24755SJustin T. Gibbs };
5517d24755SJustin T. Gibbs 
5617d24755SJustin T. Gibbs static devclass_t ahd_devclass;
5717d24755SJustin T. Gibbs 
5817d24755SJustin T. Gibbs DRIVER_MODULE(ahd, pci, ahd_pci_driver, ahd_devclass, 0, 0);
59347934faSWarner Losh DRIVER_MODULE(ahd, cardbus, ahd_pci_driver, ahd_devclass, 0, 0);
6017d24755SJustin T. Gibbs MODULE_DEPEND(ahd_pci, ahd, 1, 1, 1);
6117d24755SJustin T. Gibbs MODULE_VERSION(ahd_pci, 1);
6217d24755SJustin T. Gibbs 
6317d24755SJustin T. Gibbs static int
6417d24755SJustin T. Gibbs ahd_pci_probe(device_t dev)
6517d24755SJustin T. Gibbs {
6617d24755SJustin T. Gibbs 	struct	ahd_pci_identity *entry;
6717d24755SJustin T. Gibbs 
6817d24755SJustin T. Gibbs 	entry = ahd_find_pci_device(dev);
6917d24755SJustin T. Gibbs 	if (entry != NULL) {
7017d24755SJustin T. Gibbs 		device_set_desc(dev, entry->name);
7117d24755SJustin T. Gibbs 		return (0);
7217d24755SJustin T. Gibbs 	}
7317d24755SJustin T. Gibbs 	return (ENXIO);
7417d24755SJustin T. Gibbs }
7517d24755SJustin T. Gibbs 
7617d24755SJustin T. Gibbs static int
7717d24755SJustin T. Gibbs ahd_pci_attach(device_t dev)
7817d24755SJustin T. Gibbs {
7917d24755SJustin T. Gibbs 	struct	 ahd_pci_identity *entry;
8017d24755SJustin T. Gibbs 	struct	 ahd_softc *ahd;
8117d24755SJustin T. Gibbs 	char	*name;
8217d24755SJustin T. Gibbs 	int	 error;
8317d24755SJustin T. Gibbs 
8417d24755SJustin T. Gibbs 	entry = ahd_find_pci_device(dev);
8517d24755SJustin T. Gibbs 	if (entry == NULL)
8617d24755SJustin T. Gibbs 		return (ENXIO);
8717d24755SJustin T. Gibbs 
8817d24755SJustin T. Gibbs 	/*
8917d24755SJustin T. Gibbs 	 * Allocate a softc for this card and
9017d24755SJustin T. Gibbs 	 * set it up for attachment by our
9117d24755SJustin T. Gibbs 	 * common detect routine.
9217d24755SJustin T. Gibbs 	 */
9317d24755SJustin T. Gibbs 	name = malloc(strlen(device_get_nameunit(dev)) + 1, M_DEVBUF, M_NOWAIT);
9417d24755SJustin T. Gibbs 	if (name == NULL)
9517d24755SJustin T. Gibbs 		return (ENOMEM);
9617d24755SJustin T. Gibbs 	strcpy(name, device_get_nameunit(dev));
9717d24755SJustin T. Gibbs 	ahd = ahd_alloc(dev, name);
9817d24755SJustin T. Gibbs 	if (ahd == NULL)
9917d24755SJustin T. Gibbs 		return (ENOMEM);
10017d24755SJustin T. Gibbs 
10117d24755SJustin T. Gibbs 	ahd_set_unit(ahd, device_get_unit(dev));
10217d24755SJustin T. Gibbs 
10317d24755SJustin T. Gibbs 	/*
10417d24755SJustin T. Gibbs 	 * Should we bother disabling 39Bit addressing
10517d24755SJustin T. Gibbs 	 * based on installed memory?
10617d24755SJustin T. Gibbs 	 */
10717d24755SJustin T. Gibbs 	if (sizeof(bus_addr_t) > 4)
10817d24755SJustin T. Gibbs                 ahd->flags |= AHD_39BIT_ADDRESSING;
10917d24755SJustin T. Gibbs 
11017d24755SJustin T. Gibbs 	/* Allocate a dmatag for our SCB DMA maps */
11117d24755SJustin T. Gibbs 	/* XXX Should be a child of the PCI bus dma tag */
112b3b25f2cSJustin T. Gibbs 	error = aic_dma_tag_create(ahd, /*parent*/NULL, /*alignment*/1,
11317d24755SJustin T. Gibbs 				   /*boundary*/0,
11417d24755SJustin T. Gibbs 				   (ahd->flags & AHD_39BIT_ADDRESSING)
115b3b25f2cSJustin T. Gibbs 				   ? 0x7FFFFFFFFF
11617d24755SJustin T. Gibbs 				   : BUS_SPACE_MAXADDR_32BIT,
11717d24755SJustin T. Gibbs 				   /*highaddr*/BUS_SPACE_MAXADDR,
11817d24755SJustin T. Gibbs 				   /*filter*/NULL, /*filterarg*/NULL,
1191c754048SScott Long 				   /*maxsize*/BUS_SPACE_MAXSIZE_32BIT,
1201c754048SScott Long 				   /*nsegments*/AHD_NSEG,
12117d24755SJustin T. Gibbs 				   /*maxsegsz*/AHD_MAXTRANSFER_SIZE,
1228270490aSJustin T. Gibbs 				   /*flags*/0,
12317d24755SJustin T. Gibbs 				   &ahd->parent_dmat);
12417d24755SJustin T. Gibbs 
12517d24755SJustin T. Gibbs 	if (error != 0) {
12617d24755SJustin T. Gibbs 		printf("ahd_pci_attach: Could not allocate DMA tag "
12717d24755SJustin T. Gibbs 		       "- error %d\n", error);
12817d24755SJustin T. Gibbs 		ahd_free(ahd);
12917d24755SJustin T. Gibbs 		return (ENOMEM);
13017d24755SJustin T. Gibbs 	}
13117d24755SJustin T. Gibbs 	ahd->dev_softc = dev;
13217d24755SJustin T. Gibbs 	error = ahd_pci_config(ahd, entry);
13317d24755SJustin T. Gibbs 	if (error != 0) {
13417d24755SJustin T. Gibbs 		ahd_free(ahd);
13517d24755SJustin T. Gibbs 		return (error);
13617d24755SJustin T. Gibbs 	}
13717d24755SJustin T. Gibbs 
13817d24755SJustin T. Gibbs 	ahd_attach(ahd);
13917d24755SJustin T. Gibbs 	return (0);
14017d24755SJustin T. Gibbs }
14117d24755SJustin T. Gibbs 
14217d24755SJustin T. Gibbs int
14317d24755SJustin T. Gibbs ahd_pci_map_registers(struct ahd_softc *ahd)
14417d24755SJustin T. Gibbs {
14517d24755SJustin T. Gibbs 	struct	resource *regs;
14617d24755SJustin T. Gibbs 	struct	resource *regs2;
14717d24755SJustin T. Gibbs 	u_int	command;
14817d24755SJustin T. Gibbs 	int	regs_type;
14917d24755SJustin T. Gibbs 	int	regs_id;
15017d24755SJustin T. Gibbs 	int	regs_id2;
15197cae63dSScott Long 	int	allow_memio;
15217d24755SJustin T. Gibbs 
153b3b25f2cSJustin T. Gibbs 	command = aic_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/1);
15417d24755SJustin T. Gibbs 	regs = NULL;
15517d24755SJustin T. Gibbs 	regs2 = NULL;
15617d24755SJustin T. Gibbs 	regs_type = 0;
15717d24755SJustin T. Gibbs 	regs_id = 0;
15897cae63dSScott Long 
15997cae63dSScott Long 	/* Retrieve the per-device 'allow_memio' hint */
16097cae63dSScott Long 	if (resource_int_value(device_get_name(ahd->dev_softc),
16197cae63dSScott Long 			       device_get_unit(ahd->dev_softc),
16297cae63dSScott Long 			       "allow_memio", &allow_memio) != 0) {
16397cae63dSScott Long 		if (bootverbose)
16497cae63dSScott Long 			device_printf(ahd->dev_softc,
16597cae63dSScott Long 				      "Defaulting to MEMIO on\n");
16697cae63dSScott Long 	}
16797cae63dSScott Long 
168ccbe423cSJustin T. Gibbs 	if ((command & PCIM_CMD_MEMEN) != 0
16997cae63dSScott Long 	 && (ahd->bugs & AHD_PCIX_MMAPIO_BUG) == 0
17097cae63dSScott Long 	 && allow_memio != 0) {
17117d24755SJustin T. Gibbs 
17217d24755SJustin T. Gibbs 		regs_type = SYS_RES_MEMORY;
17317d24755SJustin T. Gibbs 		regs_id = AHD_PCI_MEMADDR;
1745f96beb9SNate Lawson 		regs = bus_alloc_resource_any(ahd->dev_softc, regs_type,
1755f96beb9SNate Lawson 					      &regs_id, RF_ACTIVE);
17617d24755SJustin T. Gibbs 		if (regs != NULL) {
17717d24755SJustin T. Gibbs 			int error;
17817d24755SJustin T. Gibbs 
17917d24755SJustin T. Gibbs 			ahd->tags[0] = rman_get_bustag(regs);
18017d24755SJustin T. Gibbs 			ahd->bshs[0] = rman_get_bushandle(regs);
18117d24755SJustin T. Gibbs 			ahd->tags[1] = ahd->tags[0];
18217d24755SJustin T. Gibbs 			error = bus_space_subregion(ahd->tags[0], ahd->bshs[0],
18317d24755SJustin T. Gibbs 						    /*offset*/0x100,
18417d24755SJustin T. Gibbs 						    /*size*/0x100,
18517d24755SJustin T. Gibbs 						    &ahd->bshs[1]);
18617d24755SJustin T. Gibbs 			/*
18717d24755SJustin T. Gibbs 			 * Do a quick test to see if memory mapped
18817d24755SJustin T. Gibbs 			 * I/O is functioning correctly.
18917d24755SJustin T. Gibbs 			 */
190add68794SScott Long 			if (error != 0
191add68794SScott Long 			 || ahd_pci_test_register_access(ahd) != 0) {
19217d24755SJustin T. Gibbs 				device_printf(ahd->dev_softc,
19317d24755SJustin T. Gibbs 				       "PCI Device %d:%d:%d failed memory "
19417d24755SJustin T. Gibbs 				       "mapped test.  Using PIO.\n",
195b3b25f2cSJustin T. Gibbs 				       aic_get_pci_bus(ahd->dev_softc),
196b3b25f2cSJustin T. Gibbs 				       aic_get_pci_slot(ahd->dev_softc),
197b3b25f2cSJustin T. Gibbs 				       aic_get_pci_function(ahd->dev_softc));
19817d24755SJustin T. Gibbs 				bus_release_resource(ahd->dev_softc, regs_type,
19917d24755SJustin T. Gibbs 						     regs_id, regs);
20017d24755SJustin T. Gibbs 				regs = NULL;
20117d24755SJustin T. Gibbs 			} else {
20217d24755SJustin T. Gibbs 				command &= ~PCIM_CMD_PORTEN;
203b3b25f2cSJustin T. Gibbs 				aic_pci_write_config(ahd->dev_softc,
20417d24755SJustin T. Gibbs 						     PCIR_COMMAND,
20517d24755SJustin T. Gibbs 						     command, /*bytes*/1);
20617d24755SJustin T. Gibbs 			}
20717d24755SJustin T. Gibbs 		}
20817d24755SJustin T. Gibbs 	}
20917d24755SJustin T. Gibbs 	if (regs == NULL && (command & PCIM_CMD_PORTEN) != 0) {
21017d24755SJustin T. Gibbs 		regs_type = SYS_RES_IOPORT;
21117d24755SJustin T. Gibbs 		regs_id = AHD_PCI_IOADDR0;
2125f96beb9SNate Lawson 		regs = bus_alloc_resource_any(ahd->dev_softc, regs_type,
2135f96beb9SNate Lawson 					      &regs_id, RF_ACTIVE);
21417d24755SJustin T. Gibbs 		if (regs == NULL) {
21517d24755SJustin T. Gibbs 			device_printf(ahd->dev_softc,
21617d24755SJustin T. Gibbs 				      "can't allocate register resources\n");
21717d24755SJustin T. Gibbs 			return (ENOMEM);
21817d24755SJustin T. Gibbs 		}
21917d24755SJustin T. Gibbs 		ahd->tags[0] = rman_get_bustag(regs);
22017d24755SJustin T. Gibbs 		ahd->bshs[0] = rman_get_bushandle(regs);
22117d24755SJustin T. Gibbs 
22217d24755SJustin T. Gibbs 		/* And now the second BAR */
22317d24755SJustin T. Gibbs 		regs_id2 = AHD_PCI_IOADDR1;
2245f96beb9SNate Lawson 		regs2 = bus_alloc_resource_any(ahd->dev_softc, regs_type,
2255f96beb9SNate Lawson 					       &regs_id2, RF_ACTIVE);
22617d24755SJustin T. Gibbs 		if (regs2 == NULL) {
22717d24755SJustin T. Gibbs 			device_printf(ahd->dev_softc,
22817d24755SJustin T. Gibbs 				      "can't allocate register resources\n");
22917d24755SJustin T. Gibbs 			return (ENOMEM);
23017d24755SJustin T. Gibbs 		}
23117d24755SJustin T. Gibbs 		ahd->tags[1] = rman_get_bustag(regs2);
23217d24755SJustin T. Gibbs 		ahd->bshs[1] = rman_get_bushandle(regs2);
23317d24755SJustin T. Gibbs 		command &= ~PCIM_CMD_MEMEN;
234b3b25f2cSJustin T. Gibbs 		aic_pci_write_config(ahd->dev_softc, PCIR_COMMAND,
23517d24755SJustin T. Gibbs 				     command, /*bytes*/1);
23617d24755SJustin T. Gibbs 		ahd->platform_data->regs_res_type[1] = regs_type;
23717d24755SJustin T. Gibbs 		ahd->platform_data->regs_res_id[1] = regs_id2;
23817d24755SJustin T. Gibbs 		ahd->platform_data->regs[1] = regs2;
23917d24755SJustin T. Gibbs 	}
24017d24755SJustin T. Gibbs 	ahd->platform_data->regs_res_type[0] = regs_type;
24117d24755SJustin T. Gibbs 	ahd->platform_data->regs_res_id[0] = regs_id;
24217d24755SJustin T. Gibbs 	ahd->platform_data->regs[0] = regs;
24317d24755SJustin T. Gibbs 	return (0);
24417d24755SJustin T. Gibbs }
24517d24755SJustin T. Gibbs 
24617d24755SJustin T. Gibbs int
24717d24755SJustin T. Gibbs ahd_pci_map_int(struct ahd_softc *ahd)
24817d24755SJustin T. Gibbs {
24917d24755SJustin T. Gibbs 	int zero;
25017d24755SJustin T. Gibbs 
25117d24755SJustin T. Gibbs 	zero = 0;
25217d24755SJustin T. Gibbs 	ahd->platform_data->irq =
2535f96beb9SNate Lawson 	    bus_alloc_resource_any(ahd->dev_softc, SYS_RES_IRQ, &zero,
2545f96beb9SNate Lawson 				   RF_ACTIVE | RF_SHAREABLE);
25517d24755SJustin T. Gibbs 	if (ahd->platform_data->irq == NULL)
25617d24755SJustin T. Gibbs 		return (ENOMEM);
25717d24755SJustin T. Gibbs 	ahd->platform_data->irq_res_type = SYS_RES_IRQ;
25817d24755SJustin T. Gibbs 	return (ahd_map_int(ahd));
25917d24755SJustin T. Gibbs }
260