18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Linux driver attachment glue for PCI based controllers. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2000-2001 Adaptec Inc. 58c2ecf20Sopenharmony_ci * All rights reserved. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 88c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 98c2ecf20Sopenharmony_ci * are met: 108c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 118c2ecf20Sopenharmony_ci * notice, this list of conditions, and the following disclaimer, 128c2ecf20Sopenharmony_ci * without modification. 138c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce at minimum a disclaimer 148c2ecf20Sopenharmony_ci * substantially similar to the "NO WARRANTY" disclaimer below 158c2ecf20Sopenharmony_ci * ("Disclaimer") and any redistribution must be conditioned upon 168c2ecf20Sopenharmony_ci * including a substantially similar Disclaimer requirement for further 178c2ecf20Sopenharmony_ci * binary redistribution. 188c2ecf20Sopenharmony_ci * 3. Neither the names of the above-listed copyright holders nor the names 198c2ecf20Sopenharmony_ci * of any contributors may be used to endorse or promote products derived 208c2ecf20Sopenharmony_ci * from this software without specific prior written permission. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the 238c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free 248c2ecf20Sopenharmony_ci * Software Foundation. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * NO WARRANTY 278c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 288c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 298c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 308c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 318c2ecf20Sopenharmony_ci * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 328c2ecf20Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 338c2ecf20Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 348c2ecf20Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 358c2ecf20Sopenharmony_ci * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 368c2ecf20Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 378c2ecf20Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGES. 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#47 $ 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#include "aic7xxx_osm.h" 438c2ecf20Sopenharmony_ci#include "aic7xxx_pci.h" 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* Define the macro locally since it's different for different class of chips. 468c2ecf20Sopenharmony_ci*/ 478c2ecf20Sopenharmony_ci#define ID(x) ID_C(x, PCI_CLASS_STORAGE_SCSI) 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic const struct pci_device_id ahc_linux_pci_id_table[] = { 508c2ecf20Sopenharmony_ci /* aic7850 based controllers */ 518c2ecf20Sopenharmony_ci ID(ID_AHA_2902_04_10_15_20C_30C), 528c2ecf20Sopenharmony_ci /* aic7860 based controllers */ 538c2ecf20Sopenharmony_ci ID(ID_AHA_2930CU), 548c2ecf20Sopenharmony_ci ID(ID_AHA_1480A & ID_DEV_VENDOR_MASK), 558c2ecf20Sopenharmony_ci ID(ID_AHA_2940AU_0 & ID_DEV_VENDOR_MASK), 568c2ecf20Sopenharmony_ci ID(ID_AHA_2940AU_CN & ID_DEV_VENDOR_MASK), 578c2ecf20Sopenharmony_ci ID(ID_AHA_2930C_VAR & ID_DEV_VENDOR_MASK), 588c2ecf20Sopenharmony_ci /* aic7870 based controllers */ 598c2ecf20Sopenharmony_ci ID(ID_AHA_2940), 608c2ecf20Sopenharmony_ci ID(ID_AHA_3940), 618c2ecf20Sopenharmony_ci ID(ID_AHA_398X), 628c2ecf20Sopenharmony_ci ID(ID_AHA_2944), 638c2ecf20Sopenharmony_ci ID(ID_AHA_3944), 648c2ecf20Sopenharmony_ci ID(ID_AHA_4944), 658c2ecf20Sopenharmony_ci /* aic7880 based controllers */ 668c2ecf20Sopenharmony_ci ID(ID_AHA_2940U & ID_DEV_VENDOR_MASK), 678c2ecf20Sopenharmony_ci ID(ID_AHA_3940U & ID_DEV_VENDOR_MASK), 688c2ecf20Sopenharmony_ci ID(ID_AHA_2944U & ID_DEV_VENDOR_MASK), 698c2ecf20Sopenharmony_ci ID(ID_AHA_3944U & ID_DEV_VENDOR_MASK), 708c2ecf20Sopenharmony_ci ID(ID_AHA_398XU & ID_DEV_VENDOR_MASK), 718c2ecf20Sopenharmony_ci ID(ID_AHA_4944U & ID_DEV_VENDOR_MASK), 728c2ecf20Sopenharmony_ci ID(ID_AHA_2930U & ID_DEV_VENDOR_MASK), 738c2ecf20Sopenharmony_ci ID(ID_AHA_2940U_PRO & ID_DEV_VENDOR_MASK), 748c2ecf20Sopenharmony_ci ID(ID_AHA_2940U_CN & ID_DEV_VENDOR_MASK), 758c2ecf20Sopenharmony_ci /* aic7890 based controllers */ 768c2ecf20Sopenharmony_ci ID(ID_AHA_2930U2), 778c2ecf20Sopenharmony_ci ID(ID_AHA_2940U2B), 788c2ecf20Sopenharmony_ci ID(ID_AHA_2940U2_OEM), 798c2ecf20Sopenharmony_ci ID(ID_AHA_2940U2), 808c2ecf20Sopenharmony_ci ID(ID_AHA_2950U2B), 818c2ecf20Sopenharmony_ci ID16(ID_AIC7890_ARO & ID_AIC7895_ARO_MASK), 828c2ecf20Sopenharmony_ci ID(ID_AAA_131U2), 838c2ecf20Sopenharmony_ci /* aic7890 based controllers */ 848c2ecf20Sopenharmony_ci ID(ID_AHA_29160), 858c2ecf20Sopenharmony_ci ID(ID_AHA_29160_CPQ), 868c2ecf20Sopenharmony_ci ID(ID_AHA_29160N), 878c2ecf20Sopenharmony_ci ID(ID_AHA_29160C), 888c2ecf20Sopenharmony_ci ID(ID_AHA_29160B), 898c2ecf20Sopenharmony_ci ID(ID_AHA_19160B), 908c2ecf20Sopenharmony_ci ID(ID_AIC7892_ARO), 918c2ecf20Sopenharmony_ci /* aic7892 based controllers */ 928c2ecf20Sopenharmony_ci ID(ID_AHA_2940U_DUAL), 938c2ecf20Sopenharmony_ci ID(ID_AHA_3940AU), 948c2ecf20Sopenharmony_ci ID(ID_AHA_3944AU), 958c2ecf20Sopenharmony_ci ID(ID_AIC7895_ARO), 968c2ecf20Sopenharmony_ci ID(ID_AHA_3950U2B_0), 978c2ecf20Sopenharmony_ci ID(ID_AHA_3950U2B_1), 988c2ecf20Sopenharmony_ci ID(ID_AHA_3950U2D_0), 998c2ecf20Sopenharmony_ci ID(ID_AHA_3950U2D_1), 1008c2ecf20Sopenharmony_ci ID(ID_AIC7896_ARO), 1018c2ecf20Sopenharmony_ci /* aic7899 based controllers */ 1028c2ecf20Sopenharmony_ci ID(ID_AHA_3960D), 1038c2ecf20Sopenharmony_ci ID(ID_AHA_3960D_CPQ), 1048c2ecf20Sopenharmony_ci ID(ID_AIC7899_ARO), 1058c2ecf20Sopenharmony_ci /* Generic chip probes for devices we don't know exactly. */ 1068c2ecf20Sopenharmony_ci ID(ID_AIC7850 & ID_DEV_VENDOR_MASK), 1078c2ecf20Sopenharmony_ci ID(ID_AIC7855 & ID_DEV_VENDOR_MASK), 1088c2ecf20Sopenharmony_ci ID(ID_AIC7859 & ID_DEV_VENDOR_MASK), 1098c2ecf20Sopenharmony_ci ID(ID_AIC7860 & ID_DEV_VENDOR_MASK), 1108c2ecf20Sopenharmony_ci ID(ID_AIC7870 & ID_DEV_VENDOR_MASK), 1118c2ecf20Sopenharmony_ci ID(ID_AIC7880 & ID_DEV_VENDOR_MASK), 1128c2ecf20Sopenharmony_ci ID16(ID_AIC7890 & ID_9005_GENERIC_MASK), 1138c2ecf20Sopenharmony_ci ID16(ID_AIC7892 & ID_9005_GENERIC_MASK), 1148c2ecf20Sopenharmony_ci ID(ID_AIC7895 & ID_DEV_VENDOR_MASK), 1158c2ecf20Sopenharmony_ci ID16(ID_AIC7896 & ID_9005_GENERIC_MASK), 1168c2ecf20Sopenharmony_ci ID16(ID_AIC7899 & ID_9005_GENERIC_MASK), 1178c2ecf20Sopenharmony_ci ID(ID_AIC7810 & ID_DEV_VENDOR_MASK), 1188c2ecf20Sopenharmony_ci ID(ID_AIC7815 & ID_DEV_VENDOR_MASK), 1198c2ecf20Sopenharmony_ci { 0 } 1208c2ecf20Sopenharmony_ci}; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, ahc_linux_pci_id_table); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 1258c2ecf20Sopenharmony_cistatic int 1268c2ecf20Sopenharmony_ciahc_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct ahc_softc *ahc = pci_get_drvdata(pdev); 1298c2ecf20Sopenharmony_ci int rc; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if ((rc = ahc_suspend(ahc))) 1328c2ecf20Sopenharmony_ci return rc; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci pci_save_state(pdev); 1358c2ecf20Sopenharmony_ci pci_disable_device(pdev); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (mesg.event & PM_EVENT_SLEEP) 1388c2ecf20Sopenharmony_ci pci_set_power_state(pdev, PCI_D3hot); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci return rc; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic int 1448c2ecf20Sopenharmony_ciahc_linux_pci_dev_resume(struct pci_dev *pdev) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci struct ahc_softc *ahc = pci_get_drvdata(pdev); 1478c2ecf20Sopenharmony_ci int rc; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci pci_set_power_state(pdev, PCI_D0); 1508c2ecf20Sopenharmony_ci pci_restore_state(pdev); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if ((rc = pci_enable_device(pdev))) { 1538c2ecf20Sopenharmony_ci dev_printk(KERN_ERR, &pdev->dev, 1548c2ecf20Sopenharmony_ci "failed to enable device after resume (%d)\n", rc); 1558c2ecf20Sopenharmony_ci return rc; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci pci_set_master(pdev); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci ahc_pci_resume(ahc); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return (ahc_resume(ahc)); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci#endif 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic void 1678c2ecf20Sopenharmony_ciahc_linux_pci_dev_remove(struct pci_dev *pdev) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct ahc_softc *ahc = pci_get_drvdata(pdev); 1708c2ecf20Sopenharmony_ci u_long s; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (ahc->platform_data && ahc->platform_data->host) 1738c2ecf20Sopenharmony_ci scsi_remove_host(ahc->platform_data->host); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci ahc_lock(ahc, &s); 1768c2ecf20Sopenharmony_ci ahc_intr_enable(ahc, FALSE); 1778c2ecf20Sopenharmony_ci ahc_unlock(ahc, &s); 1788c2ecf20Sopenharmony_ci ahc_free(ahc); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic void 1828c2ecf20Sopenharmony_ciahc_linux_pci_inherit_flags(struct ahc_softc *ahc) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct pci_dev *pdev = ahc->dev_softc, *master_pdev; 1858c2ecf20Sopenharmony_ci unsigned int master_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci master_pdev = pci_get_slot(pdev->bus, master_devfn); 1888c2ecf20Sopenharmony_ci if (master_pdev) { 1898c2ecf20Sopenharmony_ci struct ahc_softc *master = pci_get_drvdata(master_pdev); 1908c2ecf20Sopenharmony_ci if (master) { 1918c2ecf20Sopenharmony_ci ahc->flags &= ~AHC_BIOS_ENABLED; 1928c2ecf20Sopenharmony_ci ahc->flags |= master->flags & AHC_BIOS_ENABLED; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci ahc->flags &= ~AHC_PRIMARY_CHANNEL; 1958c2ecf20Sopenharmony_ci ahc->flags |= master->flags & AHC_PRIMARY_CHANNEL; 1968c2ecf20Sopenharmony_ci } else 1978c2ecf20Sopenharmony_ci printk(KERN_ERR "aic7xxx: no multichannel peer found!\n"); 1988c2ecf20Sopenharmony_ci pci_dev_put(master_pdev); 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic int 2038c2ecf20Sopenharmony_ciahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci char buf[80]; 2068c2ecf20Sopenharmony_ci const uint64_t mask_39bit = 0x7FFFFFFFFFULL; 2078c2ecf20Sopenharmony_ci struct ahc_softc *ahc; 2088c2ecf20Sopenharmony_ci ahc_dev_softc_t pci; 2098c2ecf20Sopenharmony_ci const struct ahc_pci_identity *entry; 2108c2ecf20Sopenharmony_ci char *name; 2118c2ecf20Sopenharmony_ci int error; 2128c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci pci = pdev; 2158c2ecf20Sopenharmony_ci entry = ahc_find_pci_device(pci); 2168c2ecf20Sopenharmony_ci if (entry == NULL) 2178c2ecf20Sopenharmony_ci return (-ENODEV); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* 2208c2ecf20Sopenharmony_ci * Allocate a softc for this card and 2218c2ecf20Sopenharmony_ci * set it up for attachment by our 2228c2ecf20Sopenharmony_ci * common detect routine. 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_ci sprintf(buf, "ahc_pci:%d:%d:%d", 2258c2ecf20Sopenharmony_ci ahc_get_pci_bus(pci), 2268c2ecf20Sopenharmony_ci ahc_get_pci_slot(pci), 2278c2ecf20Sopenharmony_ci ahc_get_pci_function(pci)); 2288c2ecf20Sopenharmony_ci name = kstrdup(buf, GFP_ATOMIC); 2298c2ecf20Sopenharmony_ci if (name == NULL) 2308c2ecf20Sopenharmony_ci return (-ENOMEM); 2318c2ecf20Sopenharmony_ci ahc = ahc_alloc(NULL, name); 2328c2ecf20Sopenharmony_ci if (ahc == NULL) 2338c2ecf20Sopenharmony_ci return (-ENOMEM); 2348c2ecf20Sopenharmony_ci if (pci_enable_device(pdev)) { 2358c2ecf20Sopenharmony_ci ahc_free(ahc); 2368c2ecf20Sopenharmony_ci return (-ENODEV); 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci pci_set_master(pdev); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (sizeof(dma_addr_t) > 4 2418c2ecf20Sopenharmony_ci && ahc->features & AHC_LARGE_SCBS 2428c2ecf20Sopenharmony_ci && dma_set_mask(dev, mask_39bit) == 0 2438c2ecf20Sopenharmony_ci && dma_get_required_mask(dev) > DMA_BIT_MASK(32)) { 2448c2ecf20Sopenharmony_ci ahc->flags |= AHC_39BIT_ADDRESSING; 2458c2ecf20Sopenharmony_ci } else { 2468c2ecf20Sopenharmony_ci if (dma_set_mask(dev, DMA_BIT_MASK(32))) { 2478c2ecf20Sopenharmony_ci ahc_free(ahc); 2488c2ecf20Sopenharmony_ci printk(KERN_WARNING "aic7xxx: No suitable DMA available.\n"); 2498c2ecf20Sopenharmony_ci return (-ENODEV); 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci ahc->dev_softc = pci; 2538c2ecf20Sopenharmony_ci ahc->dev = &pci->dev; 2548c2ecf20Sopenharmony_ci error = ahc_pci_config(ahc, entry); 2558c2ecf20Sopenharmony_ci if (error != 0) { 2568c2ecf20Sopenharmony_ci ahc_free(ahc); 2578c2ecf20Sopenharmony_ci return (-error); 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* 2618c2ecf20Sopenharmony_ci * Second Function PCI devices need to inherit some 2628c2ecf20Sopenharmony_ci * settings from function 0. 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_ci if ((ahc->features & AHC_MULTI_FUNC) && PCI_FUNC(pdev->devfn) != 0) 2658c2ecf20Sopenharmony_ci ahc_linux_pci_inherit_flags(ahc); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, ahc); 2688c2ecf20Sopenharmony_ci ahc_linux_register_host(ahc, &aic7xxx_driver_template); 2698c2ecf20Sopenharmony_ci return (0); 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci/******************************* PCI Routines *********************************/ 2738c2ecf20Sopenharmony_ciuint32_t 2748c2ecf20Sopenharmony_ciahc_pci_read_config(ahc_dev_softc_t pci, int reg, int width) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci switch (width) { 2778c2ecf20Sopenharmony_ci case 1: 2788c2ecf20Sopenharmony_ci { 2798c2ecf20Sopenharmony_ci uint8_t retval; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci pci_read_config_byte(pci, reg, &retval); 2828c2ecf20Sopenharmony_ci return (retval); 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci case 2: 2858c2ecf20Sopenharmony_ci { 2868c2ecf20Sopenharmony_ci uint16_t retval; 2878c2ecf20Sopenharmony_ci pci_read_config_word(pci, reg, &retval); 2888c2ecf20Sopenharmony_ci return (retval); 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci case 4: 2918c2ecf20Sopenharmony_ci { 2928c2ecf20Sopenharmony_ci uint32_t retval; 2938c2ecf20Sopenharmony_ci pci_read_config_dword(pci, reg, &retval); 2948c2ecf20Sopenharmony_ci return (retval); 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci default: 2978c2ecf20Sopenharmony_ci panic("ahc_pci_read_config: Read size too big"); 2988c2ecf20Sopenharmony_ci /* NOTREACHED */ 2998c2ecf20Sopenharmony_ci return (0); 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_civoid 3048c2ecf20Sopenharmony_ciahc_pci_write_config(ahc_dev_softc_t pci, int reg, uint32_t value, int width) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci switch (width) { 3078c2ecf20Sopenharmony_ci case 1: 3088c2ecf20Sopenharmony_ci pci_write_config_byte(pci, reg, value); 3098c2ecf20Sopenharmony_ci break; 3108c2ecf20Sopenharmony_ci case 2: 3118c2ecf20Sopenharmony_ci pci_write_config_word(pci, reg, value); 3128c2ecf20Sopenharmony_ci break; 3138c2ecf20Sopenharmony_ci case 4: 3148c2ecf20Sopenharmony_ci pci_write_config_dword(pci, reg, value); 3158c2ecf20Sopenharmony_ci break; 3168c2ecf20Sopenharmony_ci default: 3178c2ecf20Sopenharmony_ci panic("ahc_pci_write_config: Write size too big"); 3188c2ecf20Sopenharmony_ci /* NOTREACHED */ 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic struct pci_driver aic7xxx_pci_driver = { 3248c2ecf20Sopenharmony_ci .name = "aic7xxx", 3258c2ecf20Sopenharmony_ci .probe = ahc_linux_pci_dev_probe, 3268c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 3278c2ecf20Sopenharmony_ci .suspend = ahc_linux_pci_dev_suspend, 3288c2ecf20Sopenharmony_ci .resume = ahc_linux_pci_dev_resume, 3298c2ecf20Sopenharmony_ci#endif 3308c2ecf20Sopenharmony_ci .remove = ahc_linux_pci_dev_remove, 3318c2ecf20Sopenharmony_ci .id_table = ahc_linux_pci_id_table 3328c2ecf20Sopenharmony_ci}; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ciint 3358c2ecf20Sopenharmony_ciahc_linux_pci_init(void) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci return pci_register_driver(&aic7xxx_pci_driver); 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_civoid 3418c2ecf20Sopenharmony_ciahc_linux_pci_exit(void) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci pci_unregister_driver(&aic7xxx_pci_driver); 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic int 3478c2ecf20Sopenharmony_ciahc_linux_pci_reserve_io_region(struct ahc_softc *ahc, resource_size_t *base) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci if (aic7xxx_allow_memio == 0) 3508c2ecf20Sopenharmony_ci return (ENOMEM); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci *base = pci_resource_start(ahc->dev_softc, 0); 3538c2ecf20Sopenharmony_ci if (*base == 0) 3548c2ecf20Sopenharmony_ci return (ENOMEM); 3558c2ecf20Sopenharmony_ci if (!request_region(*base, 256, "aic7xxx")) 3568c2ecf20Sopenharmony_ci return (ENOMEM); 3578c2ecf20Sopenharmony_ci return (0); 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic int 3618c2ecf20Sopenharmony_ciahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc, 3628c2ecf20Sopenharmony_ci resource_size_t *bus_addr, 3638c2ecf20Sopenharmony_ci uint8_t __iomem **maddr) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci resource_size_t start; 3668c2ecf20Sopenharmony_ci int error; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci error = 0; 3698c2ecf20Sopenharmony_ci start = pci_resource_start(ahc->dev_softc, 1); 3708c2ecf20Sopenharmony_ci if (start != 0) { 3718c2ecf20Sopenharmony_ci *bus_addr = start; 3728c2ecf20Sopenharmony_ci if (!request_mem_region(start, 0x1000, "aic7xxx")) 3738c2ecf20Sopenharmony_ci error = ENOMEM; 3748c2ecf20Sopenharmony_ci if (error == 0) { 3758c2ecf20Sopenharmony_ci *maddr = ioremap(start, 256); 3768c2ecf20Sopenharmony_ci if (*maddr == NULL) { 3778c2ecf20Sopenharmony_ci error = ENOMEM; 3788c2ecf20Sopenharmony_ci release_mem_region(start, 0x1000); 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci } else 3828c2ecf20Sopenharmony_ci error = ENOMEM; 3838c2ecf20Sopenharmony_ci return (error); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ciint 3878c2ecf20Sopenharmony_ciahc_pci_map_registers(struct ahc_softc *ahc) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci uint32_t command; 3908c2ecf20Sopenharmony_ci resource_size_t base; 3918c2ecf20Sopenharmony_ci uint8_t __iomem *maddr; 3928c2ecf20Sopenharmony_ci int error; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /* 3958c2ecf20Sopenharmony_ci * If its allowed, we prefer memory mapped access. 3968c2ecf20Sopenharmony_ci */ 3978c2ecf20Sopenharmony_ci command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 4); 3988c2ecf20Sopenharmony_ci command &= ~(PCIM_CMD_PORTEN|PCIM_CMD_MEMEN); 3998c2ecf20Sopenharmony_ci base = 0; 4008c2ecf20Sopenharmony_ci maddr = NULL; 4018c2ecf20Sopenharmony_ci error = ahc_linux_pci_reserve_mem_region(ahc, &base, &maddr); 4028c2ecf20Sopenharmony_ci if (error == 0) { 4038c2ecf20Sopenharmony_ci ahc->platform_data->mem_busaddr = base; 4048c2ecf20Sopenharmony_ci ahc->tag = BUS_SPACE_MEMIO; 4058c2ecf20Sopenharmony_ci ahc->bsh.maddr = maddr; 4068c2ecf20Sopenharmony_ci ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, 4078c2ecf20Sopenharmony_ci command | PCIM_CMD_MEMEN, 4); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci /* 4108c2ecf20Sopenharmony_ci * Do a quick test to see if memory mapped 4118c2ecf20Sopenharmony_ci * I/O is functioning correctly. 4128c2ecf20Sopenharmony_ci */ 4138c2ecf20Sopenharmony_ci if (ahc_pci_test_register_access(ahc) != 0) { 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci printk("aic7xxx: PCI Device %d:%d:%d " 4168c2ecf20Sopenharmony_ci "failed memory mapped test. Using PIO.\n", 4178c2ecf20Sopenharmony_ci ahc_get_pci_bus(ahc->dev_softc), 4188c2ecf20Sopenharmony_ci ahc_get_pci_slot(ahc->dev_softc), 4198c2ecf20Sopenharmony_ci ahc_get_pci_function(ahc->dev_softc)); 4208c2ecf20Sopenharmony_ci iounmap(maddr); 4218c2ecf20Sopenharmony_ci release_mem_region(ahc->platform_data->mem_busaddr, 4228c2ecf20Sopenharmony_ci 0x1000); 4238c2ecf20Sopenharmony_ci ahc->bsh.maddr = NULL; 4248c2ecf20Sopenharmony_ci maddr = NULL; 4258c2ecf20Sopenharmony_ci } else 4268c2ecf20Sopenharmony_ci command |= PCIM_CMD_MEMEN; 4278c2ecf20Sopenharmony_ci } else { 4288c2ecf20Sopenharmony_ci printk("aic7xxx: PCI%d:%d:%d MEM region 0x%llx " 4298c2ecf20Sopenharmony_ci "unavailable. Cannot memory map device.\n", 4308c2ecf20Sopenharmony_ci ahc_get_pci_bus(ahc->dev_softc), 4318c2ecf20Sopenharmony_ci ahc_get_pci_slot(ahc->dev_softc), 4328c2ecf20Sopenharmony_ci ahc_get_pci_function(ahc->dev_softc), 4338c2ecf20Sopenharmony_ci (unsigned long long)base); 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* 4378c2ecf20Sopenharmony_ci * We always prefer memory mapped access. 4388c2ecf20Sopenharmony_ci */ 4398c2ecf20Sopenharmony_ci if (maddr == NULL) { 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci error = ahc_linux_pci_reserve_io_region(ahc, &base); 4428c2ecf20Sopenharmony_ci if (error == 0) { 4438c2ecf20Sopenharmony_ci ahc->tag = BUS_SPACE_PIO; 4448c2ecf20Sopenharmony_ci ahc->bsh.ioport = (u_long)base; 4458c2ecf20Sopenharmony_ci command |= PCIM_CMD_PORTEN; 4468c2ecf20Sopenharmony_ci } else { 4478c2ecf20Sopenharmony_ci printk("aic7xxx: PCI%d:%d:%d IO region 0x%llx[0..255] " 4488c2ecf20Sopenharmony_ci "unavailable. Cannot map device.\n", 4498c2ecf20Sopenharmony_ci ahc_get_pci_bus(ahc->dev_softc), 4508c2ecf20Sopenharmony_ci ahc_get_pci_slot(ahc->dev_softc), 4518c2ecf20Sopenharmony_ci ahc_get_pci_function(ahc->dev_softc), 4528c2ecf20Sopenharmony_ci (unsigned long long)base); 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4); 4568c2ecf20Sopenharmony_ci return (error); 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ciint 4608c2ecf20Sopenharmony_ciahc_pci_map_int(struct ahc_softc *ahc) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci int error; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci error = request_irq(ahc->dev_softc->irq, ahc_linux_isr, 4658c2ecf20Sopenharmony_ci IRQF_SHARED, "aic7xxx", ahc); 4668c2ecf20Sopenharmony_ci if (error == 0) 4678c2ecf20Sopenharmony_ci ahc->platform_data->irq = ahc->dev_softc->irq; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci return (-error); 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 472