ahc_pci.c revision 123019
117680Spst/* 239300Sfenner * FreeBSD, PCI product support functions 317680Spst * 417680Spst * Copyright (c) 1995-2001 Justin T. Gibbs 517680Spst * All rights reserved. 617680Spst * 717680Spst * Redistribution and use in source and binary forms, with or without 817680Spst * modification, are permitted provided that the following conditions 917680Spst * are met: 1017680Spst * 1. Redistributions of source code must retain the above copyright 1117680Spst * notice, this list of conditions, and the following disclaimer, 1217680Spst * without modification, immediately at the beginning of the file. 1317680Spst * 2. The name of the author may not be used to endorse or promote products 1417680Spst * derived from this software without specific prior written permission. 1517680Spst * 1617680Spst * Alternatively, this software may be distributed under the terms of the 1717680Spst * GNU Public License ("GPL"). 1817680Spst * 1917680Spst * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2056896Sfenner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2156896Sfenner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2217680Spst * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2317680Spst * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2417680Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25127675Sbms * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26214478Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2717680Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2817680Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2956896Sfenner * SUCH DAMAGE. 3056896Sfenner * 3156896Sfenner * $Id: ahc_pci.c,v 1.58 2003/11/03 09:22:16 dfr Exp $ 3256896Sfenner */ 33127675Sbms 3417680Spst#include <sys/cdefs.h> 3575118Sfenner__FBSDID("$FreeBSD: head/sys/dev/aic7xxx/ahc_pci.c 123019 2003-11-28 05:28:29Z imp $"); 3617680Spst 3717680Spst#include <dev/aic7xxx/aic7xxx_osm.h> 3856896Sfenner 3917680Spst#define AHC_PCI_IOADDR PCIR_BAR(0) /* I/O Address */ 4017680Spst#define AHC_PCI_MEMADDR PCIR_BAR(1) /* Mem I/O Address */ 4117680Spst 4217680Spststatic int ahc_pci_probe(device_t dev); 4317680Spststatic int ahc_pci_attach(device_t dev); 4498527Sfenner 4598527Sfennerstatic device_method_t ahc_pci_device_methods[] = { 4617680Spst /* Device interface */ 4717680Spst DEVMETHOD(device_probe, ahc_pci_probe), 4817680Spst DEVMETHOD(device_attach, ahc_pci_attach), 4917680Spst DEVMETHOD(device_detach, ahc_detach), 5098527Sfenner { 0, 0 } 5117680Spst}; 5298527Sfenner 5398527Sfennerstatic driver_t ahc_pci_driver = { 5417680Spst "ahc", 5517680Spst ahc_pci_device_methods, 5617680Spst sizeof(struct ahc_softc) 5717680Spst}; 5817680Spst 59127675SbmsDRIVER_MODULE(ahc_pci, pci, ahc_pci_driver, ahc_devclass, 0, 0); 6017680SpstDRIVER_MODULE(ahc_pci, cardbus, ahc_pci_driver, ahc_devclass, 0, 0); 6117680SpstMODULE_DEPEND(ahc_pci, ahc, 1, 1, 1); 6217680SpstMODULE_VERSION(ahc_pci, 1); 6398527Sfenner 6498527Sfennerstatic int 65127675Sbmsahc_pci_probe(device_t dev) 6698527Sfenner{ 67127675Sbms struct ahc_pci_identity *entry; 68127675Sbms 6975118Sfenner entry = ahc_find_pci_device(dev); 7075118Sfenner if (entry != NULL) { 7175118Sfenner device_set_desc(dev, entry->name); 7275118Sfenner return (0); 7375118Sfenner } 7498527Sfenner return (ENXIO); 7598527Sfenner} 7675118Sfenner 7775118Sfennerstatic int 7875118Sfennerahc_pci_attach(device_t dev) 7975118Sfenner{ 8075118Sfenner struct ahc_pci_identity *entry; 8175118Sfenner struct ahc_softc *ahc; 8298527Sfenner char *name; 8398527Sfenner int error; 8417680Spst 8517680Spst entry = ahc_find_pci_device(dev); 8617680Spst if (entry == NULL) 8717680Spst return (ENXIO); 8817680Spst 8917680Spst /* 9017680Spst * Allocate a softc for this card and 9175118Sfenner * set it up for attachment by our 9217680Spst * common detect routine. 9375118Sfenner */ 9475118Sfenner name = malloc(strlen(device_get_nameunit(dev)) + 1, M_DEVBUF, M_NOWAIT); 9575118Sfenner if (name == NULL) 9675118Sfenner return (ENOMEM); 9798527Sfenner strcpy(name, device_get_nameunit(dev)); 9875118Sfenner ahc = ahc_alloc(dev, name); 9975118Sfenner if (ahc == NULL) 10075118Sfenner return (ENOMEM); 10175118Sfenner 102127675Sbms ahc_set_unit(ahc, device_get_unit(dev)); 10375118Sfenner 10475118Sfenner /* 10575118Sfenner * Should we bother disabling 39Bit addressing 106127675Sbms * based on installed memory? 107127675Sbms */ 10875118Sfenner if (sizeof(bus_addr_t) > 4) 109127675Sbms ahc->flags |= AHC_39BIT_ADDRESSING; 110127675Sbms 111127675Sbms /* Allocate a dmatag for our SCB DMA maps */ 11275118Sfenner /* XXX Should be a child of the PCI bus dma tag */ 11375118Sfenner error = bus_dma_tag_create(/*parent*/NULL, /*alignment*/1, 11475118Sfenner /*boundary*/0, 115127675Sbms (ahc->flags & AHC_39BIT_ADDRESSING) 11675118Sfenner ? 0x7FFFFFFFFFLL 11775118Sfenner : BUS_SPACE_MAXADDR_32BIT, 11875118Sfenner /*highaddr*/BUS_SPACE_MAXADDR, 11975118Sfenner /*filter*/NULL, /*filterarg*/NULL, 120127675Sbms /*maxsize*/BUS_SPACE_MAXSIZE_32BIT, 121127675Sbms /*nsegments*/AHC_NSEG, 122127675Sbms /*maxsegsz*/AHC_MAXTRANSFER_SIZE, 123127675Sbms /*flags*/0, 12475118Sfenner /*lockfunc*/busdma_lock_mutex, 12575118Sfenner /*lockarg*/&Giant, 12675118Sfenner &ahc->parent_dmat); 12775118Sfenner 12875118Sfenner if (error != 0) { 12917680Spst printf("ahc_pci_attach: Could not allocate DMA tag " 13017680Spst "- error %d\n", error); 13198527Sfenner ahc_free(ahc); 13275118Sfenner return (ENOMEM); 13375118Sfenner } 13475118Sfenner ahc->dev_softc = dev; 13575118Sfenner error = ahc_pci_config(ahc, entry); 136147904Ssam if (error != 0) { 137147904Ssam ahc_free(ahc); 13875118Sfenner return (error); 139147904Ssam } 14098527Sfenner 14175118Sfenner ahc_attach(ahc); 14275118Sfenner return (0); 14375118Sfenner} 14475118Sfenner 14517680Spstint 14675118Sfennerahc_pci_map_registers(struct ahc_softc *ahc) 14775118Sfenner{ 14875118Sfenner struct resource *regs; 149251158Sdelphij u_int command; 15075118Sfenner int regs_type; 15175118Sfenner int regs_id; 15275118Sfenner int allow_memio; 15375118Sfenner 15475118Sfenner command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1); 15575118Sfenner regs = NULL; 15675118Sfenner regs_type = 0; 15775118Sfenner regs_id = 0; 15875118Sfenner 159127675Sbms /* Retrieve the per-device 'allow_memio' hint */ 16075118Sfenner if (resource_int_value(device_get_name(ahc->dev_softc), 16198527Sfenner device_get_unit(ahc->dev_softc), 16275118Sfenner "allow_memio", &allow_memio) != 0) { 16375118Sfenner if (bootverbose) 16475118Sfenner device_printf(ahc->dev_softc, "Defaulting to MEMIO "); 16517680Spst#ifdef AHC_ALLOW_MEMIO 16675118Sfenner if (bootverbose) 16775118Sfenner printf("on\n"); 16875118Sfenner allow_memio = 1; 16917680Spst#else 17017680Spst if (bootverbose) 17117680Spst printf("off\n"); 17275118Sfenner allow_memio = 0; 17375118Sfenner#endif 17475118Sfenner } 17575118Sfenner 17698527Sfenner if ((allow_memio != 0) && (command & PCIM_CMD_MEMEN) != 0) { 17798527Sfenner 17817680Spst regs_type = SYS_RES_MEMORY; 179127675Sbms regs_id = AHC_PCI_MEMADDR; 18075118Sfenner regs = bus_alloc_resource(ahc->dev_softc, regs_type, 18198527Sfenner ®s_id, 0, ~0, 1, RF_ACTIVE); 18298527Sfenner if (regs != NULL) { 18317680Spst ahc->tag = rman_get_bustag(regs); 18475118Sfenner ahc->bsh = rman_get_bushandle(regs); 18575118Sfenner 18675118Sfenner /* 18775118Sfenner * Do a quick test to see if memory mapped 18875118Sfenner * I/O is functioning correctly. 18975118Sfenner */ 19075118Sfenner if (ahc_pci_test_register_access(ahc) != 0) { 19175118Sfenner device_printf(ahc->dev_softc, 19275118Sfenner "PCI Device %d:%d:%d failed memory " 19375118Sfenner "mapped test. Using PIO.\n", 19475118Sfenner ahc_get_pci_bus(ahc->dev_softc), 19575118Sfenner ahc_get_pci_slot(ahc->dev_softc), 19617680Spst ahc_get_pci_function(ahc->dev_softc)); 19717680Spst bus_release_resource(ahc->dev_softc, regs_type, 19875118Sfenner regs_id, regs); 19975118Sfenner regs = NULL; 20075118Sfenner } else { 20175118Sfenner command &= ~PCIM_CMD_PORTEN; 20298527Sfenner ahc_pci_write_config(ahc->dev_softc, 20398527Sfenner PCIR_COMMAND, 20475118Sfenner command, /*bytes*/1); 20575118Sfenner } 20675118Sfenner } 20775118Sfenner } 20875118Sfenner 20975118Sfenner if (regs == NULL && (command & PCIM_CMD_PORTEN) != 0) { 21075118Sfenner regs_type = SYS_RES_IOPORT; 21175118Sfenner regs_id = AHC_PCI_IOADDR; 21298527Sfenner regs = bus_alloc_resource(ahc->dev_softc, regs_type, 21375118Sfenner ®s_id, 0, ~0, 1, RF_ACTIVE); 21475118Sfenner if (regs != NULL) { 21575118Sfenner ahc->tag = rman_get_bustag(regs); 21675118Sfenner ahc->bsh = rman_get_bushandle(regs); 21717680Spst command &= ~PCIM_CMD_MEMEN; 218127675Sbms ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, 21975118Sfenner command, /*bytes*/1); 22098527Sfenner } 22198527Sfenner } 22217680Spst if (regs == NULL) { 22375118Sfenner device_printf(ahc->dev_softc, 22417680Spst "can't allocate register resources\n"); 22575118Sfenner return (ENOMEM); 22617680Spst } 22717680Spst ahc->platform_data->regs_res_type = regs_type; 22817680Spst ahc->platform_data->regs_res_id = regs_id; 22917680Spst ahc->platform_data->regs = regs; 23017680Spst return (0); 23117680Spst} 23217680Spst 23317680Spstint 234127675Sbmsahc_pci_map_int(struct ahc_softc *ahc) 23517680Spst{ 23617680Spst int zero; 23717680Spst 23898527Sfenner zero = 0; 23998527Sfenner ahc->platform_data->irq = 24017680Spst bus_alloc_resource(ahc->dev_softc, SYS_RES_IRQ, &zero, 24198527Sfenner 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 24298527Sfenner if (ahc->platform_data->irq == NULL) { 24317680Spst device_printf(ahc->dev_softc, 24417680Spst "bus_alloc_resource() failed to allocate IRQ\n"); 24517680Spst return (ENOMEM); 246127675Sbms } 24798527Sfenner ahc->platform_data->irq_res_type = SYS_RES_IRQ; 248127675Sbms return (ahc_map_int(ahc)); 249127675Sbms} 250127675Sbms 251127675Sbmsvoid 252127675Sbmsahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state) 253127675Sbms{ 254127675Sbms uint32_t cap; 255127675Sbms u_int cap_offset; 256127675Sbms 257127675Sbms /* 258127675Sbms * Traverse the capability list looking for 259127675Sbms * the power management capability. 260127675Sbms */ 261127675Sbms cap = 0; 262127675Sbms cap_offset = ahc_pci_read_config(ahc->dev_softc, 263127675Sbms PCIR_CAP_PTR, /*bytes*/1); 264127675Sbms while (cap_offset != 0) { 265127675Sbms 266127675Sbms cap = ahc_pci_read_config(ahc->dev_softc, 267127675Sbms cap_offset, /*bytes*/4); 268127675Sbms if ((cap & 0xFF) == 1 269127675Sbms && ((cap >> 16) & 0x3) > 0) { 27017680Spst uint32_t pm_control; 271127675Sbms 272127675Sbms pm_control = ahc_pci_read_config(ahc->dev_softc, 273127675Sbms cap_offset + 4, 274127675Sbms /*bytes*/2); 275127675Sbms pm_control &= ~0x3; 276127675Sbms pm_control |= new_state; 277127675Sbms ahc_pci_write_config(ahc->dev_softc, 278127675Sbms cap_offset + 4, 279127675Sbms pm_control, /*bytes*/2); 280127675Sbms break; 281127675Sbms } 282127675Sbms cap_offset = (cap >> 8) & 0xFF; 283172686Smlaier } 284172686Smlaier} 285127675Sbms