1/* 2 * Copyright (C) 1995,2001 Compaq Computer Corporation 3 * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) 4 * Copyright (C) 2001 IBM Corp. 5 * Copyright (C) 2003-2004 Intel Corporation 6 * (c) Copyright 2009 Hewlett-Packard Development Company, L.P. 7 * 8 * All rights reserved. 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or (at 13 * your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, but 16 * WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 18 * NON INFRINGEMENT. See the GNU General Public License for more 19 * details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24 */ 25 26#include <linux/pci.h> 27#include <linux/pci_hotplug.h> 28 29static struct hpp_type0 pci_default_type0 = { 30 .revision = 1, 31 .cache_line_size = 8, 32 .latency_timer = 0x40, 33 .enable_serr = 0, 34 .enable_perr = 0, 35}; 36 37static void program_hpp_type0(struct pci_dev *dev, struct hpp_type0 *hpp) 38{ 39 u16 pci_cmd, pci_bctl; 40 41 if (!hpp) { 42 /* 43 * Perhaps we *should* use default settings for PCIe, but 44 * pciehp didn't, so we won't either. 45 */ 46 if (pci_is_pcie(dev)) 47 return; 48 dev_info(&dev->dev, "using default PCI settings\n"); 49 hpp = &pci_default_type0; 50 } 51 52 if (hpp->revision > 1) { 53 dev_warn(&dev->dev, 54 "PCI settings rev %d not supported; using defaults\n", 55 hpp->revision); 56 hpp = &pci_default_type0; 57 } 58 59 pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, hpp->cache_line_size); 60 pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpp->latency_timer); 61 pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); 62 if (hpp->enable_serr) 63 pci_cmd |= PCI_COMMAND_SERR; 64 else 65 pci_cmd &= ~PCI_COMMAND_SERR; 66 if (hpp->enable_perr) 67 pci_cmd |= PCI_COMMAND_PARITY; 68 else 69 pci_cmd &= ~PCI_COMMAND_PARITY; 70 pci_write_config_word(dev, PCI_COMMAND, pci_cmd); 71 72 /* Program bridge control value */ 73 if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { 74 pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 75 hpp->latency_timer); 76 pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); 77 if (hpp->enable_serr) 78 pci_bctl |= PCI_BRIDGE_CTL_SERR; 79 else 80 pci_bctl &= ~PCI_BRIDGE_CTL_SERR; 81 if (hpp->enable_perr) 82 pci_bctl |= PCI_BRIDGE_CTL_PARITY; 83 else 84 pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; 85 pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl); 86 } 87} 88 89static void program_hpp_type1(struct pci_dev *dev, struct hpp_type1 *hpp) 90{ 91 if (hpp) 92 dev_warn(&dev->dev, "PCI-X settings not supported\n"); 93} 94 95static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp) 96{ 97 int pos; 98 u16 reg16; 99 u32 reg32; 100 101 if (!hpp) 102 return; 103 104 /* Find PCI Express capability */ 105 pos = pci_pcie_cap(dev); 106 if (!pos) 107 return; 108 109 if (hpp->revision > 1) { 110 dev_warn(&dev->dev, "PCIe settings rev %d not supported\n", 111 hpp->revision); 112 return; 113 } 114 115 /* Initialize Device Control Register */ 116 pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, ®16); 117 reg16 = (reg16 & hpp->pci_exp_devctl_and) | hpp->pci_exp_devctl_or; 118 pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, reg16); 119 120 /* Initialize Link Control Register */ 121 if (dev->subordinate) { 122 pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, ®16); 123 reg16 = (reg16 & hpp->pci_exp_lnkctl_and) 124 | hpp->pci_exp_lnkctl_or; 125 pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, reg16); 126 } 127 128 /* Find Advanced Error Reporting Enhanced Capability */ 129 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); 130 if (!pos) 131 return; 132 133 /* Initialize Uncorrectable Error Mask Register */ 134 pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, ®32); 135 reg32 = (reg32 & hpp->unc_err_mask_and) | hpp->unc_err_mask_or; 136 pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, reg32); 137 138 /* Initialize Uncorrectable Error Severity Register */ 139 pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, ®32); 140 reg32 = (reg32 & hpp->unc_err_sever_and) | hpp->unc_err_sever_or; 141 pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, reg32); 142 143 /* Initialize Correctable Error Mask Register */ 144 pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®32); 145 reg32 = (reg32 & hpp->cor_err_mask_and) | hpp->cor_err_mask_or; 146 pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg32); 147 148 /* Initialize Advanced Error Capabilities and Control Register */ 149 pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32); 150 reg32 = (reg32 & hpp->adv_err_cap_and) | hpp->adv_err_cap_or; 151 pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32); 152 153} 154 155void pci_configure_slot(struct pci_dev *dev) 156{ 157 struct pci_dev *cdev; 158 struct hotplug_params hpp; 159 int ret; 160 161 if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL || 162 (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && 163 (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) 164 return; 165 166 memset(&hpp, 0, sizeof(hpp)); 167 ret = pci_get_hp_params(dev, &hpp); 168 if (ret) 169 dev_warn(&dev->dev, "no hotplug settings from platform\n"); 170 171 program_hpp_type2(dev, hpp.t2); 172 program_hpp_type1(dev, hpp.t1); 173 program_hpp_type0(dev, hpp.t0); 174 175 if (dev->subordinate) { 176 list_for_each_entry(cdev, &dev->subordinate->devices, 177 bus_list) 178 pci_configure_slot(cdev); 179 } 180} 181EXPORT_SYMBOL_GPL(pci_configure_slot); 182