ahc_pci.c revision 161928
160812Sps/*-
2238730Sdelphij * FreeBSD, PCI product support functions
3238730Sdelphij *
4238730Sdelphij * Copyright (c) 1995-2001 Justin T. Gibbs
5238730Sdelphij * All rights reserved.
6238730Sdelphij *
7238730Sdelphij * Redistribution and use in source and binary forms, with or without
8238730Sdelphij * modification, are permitted provided that the following conditions
9238730Sdelphij * are met:
1060786Sps * 1. Redistributions of source code must retain the above copyright
1160786Sps *    notice, this list of conditions, and the following disclaimer,
1260786Sps *    without modification, immediately at the beginning of the file.
1360786Sps * 2. The name of the author may not be used to endorse or promote products
1460786Sps *    derived from this software without specific prior written permission.
1560786Sps *
1660786Sps * Alternatively, this software may be distributed under the terms of the
1789022Sps * GNU Public License ("GPL").
1889022Sps *
1989022Sps * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2060786Sps * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2160786Sps * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2260786Sps * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2360786Sps * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24161478Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2560786Sps * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2660786Sps * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2760786Sps * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2860786Sps * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2960786Sps * SUCH DAMAGE.
3060786Sps *
3160786Sps * $Id: //depot/aic7xxx/freebsd/dev/aic7xxx/ahc_pci.c#19 $
3260786Sps */
3360786Sps
3460786Sps#include <sys/cdefs.h>
3560786Sps__FBSDID("$FreeBSD: head/sys/dev/aic7xxx/ahc_pci.c 161928 2006-09-03 00:27:42Z jmg $");
3660786Sps
3760786Sps#include <dev/aic7xxx/aic7xxx_osm.h>
3860786Sps
39170259Sdelphijstatic int ahc_pci_probe(device_t dev);
40237613Sdelphijstatic int ahc_pci_attach(device_t dev);
4160786Sps
4260786Spsstatic device_method_t ahc_pci_device_methods[] = {
4360786Sps	/* Device interface */
4460786Sps	DEVMETHOD(device_probe,		ahc_pci_probe),
4560786Sps	DEVMETHOD(device_attach,	ahc_pci_attach),
4660786Sps	DEVMETHOD(device_detach,	ahc_detach),
4760786Sps	{ 0, 0 }
4860786Sps};
4960786Sps
5060786Spsstatic driver_t ahc_pci_driver = {
5160786Sps	"ahc",
5260786Sps	ahc_pci_device_methods,
5360786Sps	sizeof(struct ahc_softc)
5460786Sps};
5560786Sps
5663131SpsDRIVER_MODULE(ahc_pci, pci, ahc_pci_driver, ahc_devclass, 0, 0);
57170259SdelphijDRIVER_MODULE(ahc_pci, cardbus, ahc_pci_driver, ahc_devclass, 0, 0);
58170259SdelphijMODULE_DEPEND(ahc_pci, ahc, 1, 1, 1);
5960786SpsMODULE_VERSION(ahc_pci, 1);
6060786Sps
6160786Spsstatic int
6260786Spsahc_pci_probe(device_t dev)
6360786Sps{
6460786Sps	struct	ahc_pci_identity *entry;
65128348Stjr
66170259Sdelphij	entry = ahc_find_pci_device(dev);
67221715Sdelphij	if (entry != NULL) {
68221715Sdelphij		device_set_desc(dev, entry->name);
6960786Sps		return (BUS_PROBE_DEFAULT);
7060786Sps	}
7160786Sps	return (ENXIO);
72161478Sdelphij}
7360786Sps
7460786Spsstatic int
7560786Spsahc_pci_attach(device_t dev)
7660786Sps{
77221715Sdelphij	struct	 ahc_pci_identity *entry;
78221715Sdelphij	struct	 ahc_softc *ahc;
79221715Sdelphij	char	*name;
80221715Sdelphij	int	 error;
81221715Sdelphij
82221715Sdelphij	entry = ahc_find_pci_device(dev);
83221715Sdelphij	if (entry == NULL)
8460786Sps		return (ENXIO);
8560786Sps
8660786Sps	/*
87170259Sdelphij	 * Allocate a softc for this card and
8860786Sps	 * set it up for attachment by our
8960786Sps	 * common detect routine.
9060786Sps	 */
9160786Sps	name = malloc(strlen(device_get_nameunit(dev)) + 1, M_DEVBUF, M_NOWAIT);
9260786Sps	if (name == NULL)
9360786Sps		return (ENOMEM);
94191930Sdelphij	strcpy(name, device_get_nameunit(dev));
9560786Sps	ahc = ahc_alloc(dev, name);
96191930Sdelphij	if (ahc == NULL)
97170967Sdelphij		return (ENOMEM);
9860786Sps
9960786Sps	ahc_set_unit(ahc, device_get_unit(dev));
10060786Sps
10160786Sps	/*
10260786Sps	 * Should we bother disabling 39Bit addressing
10360786Sps	 * based on installed memory?
10460786Sps	 */
10560786Sps	if (sizeof(bus_addr_t) > 4)
10660786Sps                ahc->flags |= AHC_39BIT_ADDRESSING;
107237613Sdelphij
108237613Sdelphij	/* Allocate a dmatag for our SCB DMA maps */
10960786Sps	/* XXX Should be a child of the PCI bus dma tag */
11060786Sps	error = aic_dma_tag_create(ahc, /*parent*/bus_get_dma_tag(dev),
11160786Sps				   /*alignment*/1, /*boundary*/0,
112170259Sdelphij				   (ahc->flags & AHC_39BIT_ADDRESSING)
11360786Sps				   ? 0x7FFFFFFFFFLL
11460786Sps				   : BUS_SPACE_MAXADDR_32BIT,
11560786Sps				   /*highaddr*/BUS_SPACE_MAXADDR,
11660786Sps				   /*filter*/NULL, /*filterarg*/NULL,
11760786Sps				   /*maxsize*/BUS_SPACE_MAXSIZE_32BIT,
11860786Sps				   /*nsegments*/AHC_NSEG,
11960786Sps				   /*maxsegsz*/AHC_MAXTRANSFER_SIZE,
12060786Sps				   /*flags*/0,
12160786Sps				   &ahc->parent_dmat);
12260786Sps
12360786Sps	if (error != 0) {
12460786Sps		printf("ahc_pci_attach: Could not allocate DMA tag "
12560786Sps		       "- error %d\n", error);
12660786Sps		ahc_free(ahc);
12760786Sps		return (ENOMEM);
12860786Sps	}
12960786Sps	ahc->dev_softc = dev;
130191930Sdelphij	error = ahc_pci_config(ahc, entry);
131191930Sdelphij	if (error != 0) {
132191930Sdelphij		ahc_free(ahc);
133191930Sdelphij		return (error);
134191930Sdelphij	}
13560786Sps
13660786Sps	ahc_attach(ahc);
13760786Sps	return (0);
13860786Sps}
13960786Sps
140170259Sdelphijint
14160786Spsahc_pci_map_registers(struct ahc_softc *ahc)
14260786Sps{
14360786Sps	struct	resource *regs;
14460786Sps	u_int	command;
14560786Sps	int	regs_type;
14660786Sps	int	regs_id;
14760786Sps	int	allow_memio;
14860786Sps
14960786Sps	command = aic_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1);
15060786Sps	regs = NULL;
15160786Sps	regs_type = 0;
15260786Sps	regs_id = 0;
15360786Sps
154191930Sdelphij	/* Retrieve the per-device 'allow_memio' hint */
155191930Sdelphij	if (resource_int_value(device_get_name(ahc->dev_softc),
156191930Sdelphij			       device_get_unit(ahc->dev_softc),
157191930Sdelphij			       "allow_memio", &allow_memio) != 0) {
158191930Sdelphij		if (bootverbose)
15960786Sps			device_printf(ahc->dev_softc, "Defaulting to MEMIO ");
16060786Sps#ifdef AHC_ALLOW_MEMIO
16160786Sps		if (bootverbose)
16260786Sps			printf("on\n");
16360786Sps		allow_memio = 1;
16460786Sps#else
16560786Sps		if (bootverbose)
16660786Sps			printf("off\n");
16760786Sps		allow_memio = 0;
16860786Sps#endif
16960786Sps	}
17060786Sps
17160786Sps	if ((allow_memio != 0) && (command & PCIM_CMD_MEMEN) != 0) {
17260786Sps
17360786Sps		regs_type = SYS_RES_MEMORY;
17460786Sps		regs_id = AHC_PCI_MEMADDR;
17560786Sps		regs = bus_alloc_resource_any(ahc->dev_softc, regs_type,
17660786Sps					      &regs_id, RF_ACTIVE);
17760786Sps		if (regs != NULL) {
17860786Sps			ahc->tag = rman_get_bustag(regs);
17960786Sps			ahc->bsh = rman_get_bushandle(regs);
18060786Sps
181170259Sdelphij			/*
18260786Sps			 * Do a quick test to see if memory mapped
18360786Sps			 * I/O is functioning correctly.
18460786Sps			 */
18560786Sps			if (ahc_pci_test_register_access(ahc) != 0) {
18660786Sps				device_printf(ahc->dev_softc,
18760786Sps				       "PCI Device %d:%d:%d failed memory "
18860786Sps				       "mapped test.  Using PIO.\n",
18960786Sps				       aic_get_pci_bus(ahc->dev_softc),
19060786Sps				       aic_get_pci_slot(ahc->dev_softc),
19160786Sps				       aic_get_pci_function(ahc->dev_softc));
19260786Sps				bus_release_resource(ahc->dev_softc, regs_type,
19360786Sps						     regs_id, regs);
19460786Sps				regs = NULL;
19560786Sps			} else {
19660786Sps				command &= ~PCIM_CMD_PORTEN;
19760786Sps				aic_pci_write_config(ahc->dev_softc,
19860786Sps						     PCIR_COMMAND,
19960786Sps						     command, /*bytes*/1);
20060786Sps			}
20160786Sps		}
20260786Sps	}
20360786Sps
20460786Sps	if (regs == NULL && (command & PCIM_CMD_PORTEN) != 0) {
20560786Sps		regs_type = SYS_RES_IOPORT;
20660786Sps		regs_id = AHC_PCI_IOADDR;
20760786Sps		regs = bus_alloc_resource_any(ahc->dev_softc, regs_type,
20860786Sps					      &regs_id, RF_ACTIVE);
20960786Sps		if (regs != NULL) {
21060786Sps			ahc->tag = rman_get_bustag(regs);
21160786Sps			ahc->bsh = rman_get_bushandle(regs);
21260786Sps			if (ahc_pci_test_register_access(ahc) != 0) {
21360786Sps				device_printf(ahc->dev_softc,
21460786Sps				       "PCI Device %d:%d:%d failed I/O "
215128348Stjr				       "mapped test.\n",
21660786Sps				       aic_get_pci_bus(ahc->dev_softc),
217191930Sdelphij				       aic_get_pci_slot(ahc->dev_softc),
218191930Sdelphij				       aic_get_pci_function(ahc->dev_softc));
219191930Sdelphij				bus_release_resource(ahc->dev_softc, regs_type,
220191930Sdelphij						     regs_id, regs);
221191930Sdelphij				regs = NULL;
222191930Sdelphij			} else {
22360786Sps				command &= ~PCIM_CMD_MEMEN;
22460786Sps				aic_pci_write_config(ahc->dev_softc,
22560786Sps						     PCIR_COMMAND,
22660786Sps						     command, /*bytes*/1);
22760786Sps			}
22860786Sps		}
22960786Sps	}
23060786Sps	if (regs == NULL) {
23160786Sps		device_printf(ahc->dev_softc,
23260786Sps			      "can't allocate register resources\n");
23360786Sps		return (ENOMEM);
23460786Sps	}
23560786Sps	ahc->platform_data->regs_res_type = regs_type;
23660786Sps	ahc->platform_data->regs_res_id = regs_id;
237221715Sdelphij	ahc->platform_data->regs = regs;
238221715Sdelphij	return (0);
23960786Sps}
24060786Sps