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
ahd_pci_probe(device_t dev)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
ahd_pci_attach(device_t dev)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
ahd_pci_map_registers(struct ahd_softc * ahd)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 ®s_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 ®s_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 ®s_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
ahd_pci_map_int(struct ahd_softc * ahd)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