ahc_pci.c revision 108479
1139749Simp/* 2193640Sariff * FreeBSD, PCI product support functions 3193640Sariff * 4193640Sariff * Copyright (c) 1995-2001 Justin T. Gibbs 5193640Sariff * All rights reserved. 650724Scg * 750724Scg * Redistribution and use in source and binary forms, with or without 850724Scg * modification, are permitted provided that the following conditions 950724Scg * are met: 1050724Scg * 1. Redistributions of source code must retain the above copyright 1150724Scg * notice, this list of conditions, and the following disclaimer, 1250724Scg * without modification, immediately at the beginning of the file. 1350724Scg * 2. The name of the author may not be used to endorse or promote products 1450724Scg * derived from this software without specific prior written permission. 1550724Scg * 1650724Scg * Alternatively, this software may be distributed under the terms of the 1750724Scg * GNU Public License ("GPL"). 1850724Scg * 1950724Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2050724Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2150724Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2250724Scg * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2350724Scg * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2450724Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2550724Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2650724Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2750724Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2850724Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2950724Scg * SUCH DAMAGE. 30147274Smarius * 31147274Smarius * $Id: //depot/aic7xxx/freebsd/dev/aic7xxx/ahc_pci.c#12 $ 32193640Sariff * 33193640Sariff * $FreeBSD: head/sys/dev/aic7xxx/ahc_pci.c 108479 2002-12-31 04:22:36Z scottl $ 34193640Sariff */ 35193640Sariff 3653465Scg#include <dev/aic7xxx/aic7xxx_osm.h> 37193640Sariff 3850724Scg#define AHC_PCI_IOADDR PCIR_MAPS /* I/O Address */ 3970134Scg#define AHC_PCI_MEMADDR (PCIR_MAPS + 4) /* Mem I/O Address */ 4070134Scg 4182180Scgstatic int ahc_pci_probe(device_t dev); 4282180Scgstatic int ahc_pci_attach(device_t dev); 43164614Sariff 44164614Sariffstatic device_method_t ahc_pci_device_methods[] = { 45164614Sariff /* Device interface */ 4683613Scg DEVMETHOD(device_probe, ahc_pci_probe), 47193640Sariff DEVMETHOD(device_attach, ahc_pci_attach), 48193640Sariff DEVMETHOD(device_detach, ahc_detach), 49193640Sariff { 0, 0 } 50193640Sariff}; 51164614Sariff 52164614Sariffstatic driver_t ahc_pci_driver = { 53164614Sariff "ahc", 5483613Scg ahc_pci_device_methods, 55164614Sariff sizeof(struct ahc_softc) 5683613Scg}; 5783613Scg 5883613ScgDRIVER_MODULE(ahc_pci, pci, ahc_pci_driver, ahc_devclass, 0, 0); 59164614SariffDRIVER_MODULE(ahc_pci, cardbus, ahc_pci_driver, ahc_devclass, 0, 0); 60170289SdwmaloneMODULE_DEPEND(ahc_pci, ahc, 1, 1, 1); 61168243SariffMODULE_VERSION(ahc_pci, 1); 62168243Sariff 63164614Sariffstatic int 6483613Scgahc_pci_probe(device_t dev) 6583613Scg{ 66164614Sariff struct ahc_pci_identity *entry; 6783613Scg 6883613Scg entry = ahc_find_pci_device(dev); 6983613Scg if (entry != NULL) { 70164614Sariff device_set_desc(dev, entry->name); 71164614Sariff return (0); 72164614Sariff } 7383613Scg return (ENXIO); 74164614Sariff} 75164614Sariff 76164614Sariffstatic int 77164614Sariffahc_pci_attach(device_t dev) 78164614Sariff{ 79164614Sariff struct ahc_pci_identity *entry; 80164614Sariff struct ahc_softc *ahc; 81164614Sariff char *name; 82164614Sariff int error; 83170289Sdwmalone 84168243Sariff entry = ahc_find_pci_device(dev); 85168243Sariff if (entry == NULL) 86164614Sariff return (ENXIO); 87164614Sariff 88164614Sariff /* 89164614Sariff * Allocate a softc for this card and 90164614Sariff * set it up for attachment by our 91164614Sariff * common detect routine. 92164614Sariff */ 93164614Sariff name = malloc(strlen(device_get_nameunit(dev)) + 1, M_DEVBUF, M_NOWAIT); 94164614Sariff if (name == NULL) 95164614Sariff return (ENOMEM); 96164614Sariff strcpy(name, device_get_nameunit(dev)); 97167645Sariff ahc = ahc_alloc(dev, name); 98168243Sariff if (ahc == NULL) 99167645Sariff return (ENOMEM); 100167645Sariff 101167645Sariff ahc_set_unit(ahc, device_get_unit(dev)); 102167645Sariff 103167645Sariff /* 104167645Sariff * Should we bother disabling 39Bit addressing 105167645Sariff * based on installed memory? 106170289Sdwmalone */ 107168243Sariff if (sizeof(bus_addr_t) > 4) 108168243Sariff ahc->flags |= AHC_39BIT_ADDRESSING; 109167645Sariff 110167645Sariff /* Allocate a dmatag for our SCB DMA maps */ 111167645Sariff /* XXX Should be a child of the PCI bus dma tag */ 112167645Sariff error = bus_dma_tag_create(/*parent*/NULL, /*alignment*/1, 113167645Sariff /*boundary*/0, 114167645Sariff (ahc->flags & AHC_39BIT_ADDRESSING) 115167645Sariff ? 0x7FFFFFFFFF 116167645Sariff : BUS_SPACE_MAXADDR_32BIT, 117167645Sariff /*highaddr*/BUS_SPACE_MAXADDR, 118168243Sariff /*filter*/NULL, /*filterarg*/NULL, 119167645Sariff /*maxsize*/BUS_SPACE_MAXSIZE_32BIT, 120167645Sariff /*nsegments*/AHC_NSEG, 121193640Sariff /*maxsegsz*/AHC_MAXTRANSFER_SIZE, 122193640Sariff /*flags*/BUS_DMA_ALLOCNOW, 123193640Sariff &ahc->parent_dmat); 124193640Sariff 125193640Sariff if (error != 0) { 126193640Sariff printf("ahc_pci_attach: Could not allocate DMA tag " 127214332Smav "- error %d\n", error); 128193640Sariff ahc_free(ahc); 129193640Sariff return (ENOMEM); 130193640Sariff } 131193640Sariff ahc->dev_softc = dev; 132193640Sariff error = ahc_pci_config(ahc, entry); 133193640Sariff if (error != 0) { 134193640Sariff ahc_free(ahc); 135193640Sariff return (error); 136193640Sariff } 137193640Sariff 138193640Sariff ahc_attach(ahc); 139193640Sariff return (0); 140193640Sariff} 141193640Sariff 142193640Sariffint 143193640Sariffahc_pci_map_registers(struct ahc_softc *ahc) 144193640Sariff{ 145193640Sariff struct resource *regs; 146193640Sariff u_int command; 147193640Sariff int regs_type; 148193640Sariff int regs_id; 149193640Sariff int allow_memio; 150193640Sariff 151193640Sariff command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1); 152193640Sariff regs = NULL; 153193640Sariff regs_type = 0; 154193640Sariff regs_id = 0; 155193640Sariff 156193640Sariff /* Retrieve the per-device 'allow_memio' hint */ 157193640Sariff if (resource_int_value(device_get_name(ahc->dev_softc), 158193640Sariff device_get_unit(ahc->dev_softc), 159193640Sariff "allow_memio", &allow_memio) != 0) { 160193640Sariff if (bootverbose) 161193640Sariff device_printf(ahc->dev_softc, "Defaulting to MEMIO "); 162193640Sariff#ifdef AHC_ALLOW_MEMIO 163193640Sariff if (bootverbose) 164193640Sariff printf("on\n"); 165193640Sariff allow_memio = 1; 166193640Sariff#else 167193640Sariff if (bootverbose) 168193640Sariff printf("off\n"); 169193640Sariff allow_memio = 0; 170193640Sariff#endif 171193640Sariff } 172193640Sariff 173193640Sariff if ((allow_memio != 0) && (command & PCIM_CMD_MEMEN) != 0) { 174193640Sariff 175193640Sariff regs_type = SYS_RES_MEMORY; 176193640Sariff regs_id = AHC_PCI_MEMADDR; 177193640Sariff regs = bus_alloc_resource(ahc->dev_softc, regs_type, 178193640Sariff ®s_id, 0, ~0, 1, RF_ACTIVE); 179193640Sariff if (regs != NULL) { 180193640Sariff ahc->tag = rman_get_bustag(regs); 181193640Sariff ahc->bsh = rman_get_bushandle(regs); 182193640Sariff 183193640Sariff /* 184193640Sariff * Do a quick test to see if memory mapped 185193640Sariff * I/O is functioning correctly. 186193640Sariff */ 187193640Sariff if (ahc_pci_test_register_access(ahc) != 0) { 188193640Sariff device_printf(ahc->dev_softc, 189193640Sariff "PCI Device %d:%d:%d failed memory " 190193640Sariff "mapped test. Using PIO.\n", 191193640Sariff ahc_get_pci_bus(ahc->dev_softc), 192193640Sariff ahc_get_pci_slot(ahc->dev_softc), 193193640Sariff ahc_get_pci_function(ahc->dev_softc)); 194193640Sariff bus_release_resource(ahc->dev_softc, regs_type, 195193640Sariff regs_id, regs); 196167645Sariff regs = NULL; 197167645Sariff } else { 198167645Sariff command &= ~PCIM_CMD_PORTEN; 199167645Sariff ahc_pci_write_config(ahc->dev_softc, 200167645Sariff PCIR_COMMAND, 201167645Sariff command, /*bytes*/1); 202167645Sariff } 203167645Sariff } 204167645Sariff } 205167645Sariff 206167645Sariff if (regs == NULL && (command & PCIM_CMD_PORTEN) != 0) { 207167645Sariff regs_type = SYS_RES_IOPORT; 208162588Snetchild regs_id = AHC_PCI_IOADDR; 209162588Snetchild regs = bus_alloc_resource(ahc->dev_softc, regs_type, 210162588Snetchild ®s_id, 0, ~0, 1, RF_ACTIVE); 211162588Snetchild if (regs != NULL) { 212162588Snetchild ahc->tag = rman_get_bustag(regs); 213162588Snetchild ahc->bsh = rman_get_bushandle(regs); 214162588Snetchild command &= ~PCIM_CMD_MEMEN; 215162588Snetchild ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, 216162588Snetchild command, /*bytes*/1); 217162588Snetchild } 218162588Snetchild } 219162588Snetchild if (regs == NULL) { 220162588Snetchild device_printf(ahc->dev_softc, 221162588Snetchild "can't allocate register resources\n"); 222162588Snetchild return (ENOMEM); 223162588Snetchild } 224201145Santoine ahc->platform_data->regs_res_type = regs_type; 225162588Snetchild ahc->platform_data->regs_res_id = regs_id; 22674763Scg ahc->platform_data->regs = regs; 227123156Smatk return (0); 22874763Scg} 229170815Sariff 230126367Struckmanint 231126367Struckmanahc_pci_map_int(struct ahc_softc *ahc) 232170815Sariff{ 233126367Struckman int zero; 234170161Sariff 235170161Sariff zero = 0; 236170815Sariff ahc->platform_data->irq = 237170161Sariff bus_alloc_resource(ahc->dev_softc, SYS_RES_IRQ, &zero, 238126367Struckman 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 239126367Struckman if (ahc->platform_data->irq == NULL) { 240170815Sariff device_printf(ahc->dev_softc, 241126367Struckman "bus_alloc_resource() failed to allocate IRQ\n"); 242170161Sariff return (ENOMEM); 243170161Sariff } 244170815Sariff ahc->platform_data->irq_res_type = SYS_RES_IRQ; 245126367Struckman return (ahc_map_int(ahc)); 246193640Sariff} 247193640Sariff 248126367Struckmanvoid 249126367Struckmanahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state) 250162588Snetchild{ 251170815Sariff uint32_t cap; 25274763Scg u_int cap_offset; 25350724Scg 25474763Scg /* 25574763Scg * Traverse the capability list looking for 25674763Scg * the power management capability. 257170815Sariff */ 258170815Sariff cap = 0; 259170815Sariff cap_offset = ahc_pci_read_config(ahc->dev_softc, 260170815Sariff PCIR_CAP_PTR, /*bytes*/1); 261170815Sariff while (cap_offset != 0) { 262170815Sariff 263170815Sariff cap = ahc_pci_read_config(ahc->dev_softc, 264170815Sariff cap_offset, /*bytes*/4); 26574763Scg if ((cap & 0xFF) == 1 26674763Scg && ((cap >> 16) & 0x3) > 0) { 26750724Scg uint32_t pm_control; 268162588Snetchild 269162588Snetchild pm_control = ahc_pci_read_config(ahc->dev_softc, 270162588Snetchild cap_offset + 4, 271162588Snetchild /*bytes*/2); 272162588Snetchild pm_control &= ~0x3; 273162588Snetchild pm_control |= new_state; 27450724Scg ahc_pci_write_config(ahc->dev_softc, 27574763Scg cap_offset + 4, 27650724Scg pm_control, /*bytes*/2); 27774763Scg break; 278193640Sariff } 27950724Scg cap_offset = (cap >> 8) & 0xFF; 28074763Scg } 281193640Sariff} 282193640Sariff