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 ®s_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 ®s_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