1 /* 2 * PCI Express Hot Plug Controller Driver 3 * 4 * Copyright (C) 1995,2001 Compaq Computer Corporation 5 * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) 6 * Copyright (C) 2001 IBM Corp. 7 * Copyright (C) 2003-2004 Intel Corporation 8 * 9 * All rights reserved. 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or (at 14 * your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, but 17 * WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 19 * NON INFRINGEMENT. See the GNU General Public License for more 20 * details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 25 * 26 * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com> 27 * 28 */ 29 30 #include <linux/module.h> 31 #include <linux/kernel.h> 32 #include <linux/types.h> 33 #include <linux/pci.h> 34 #include "../pci.h" 35 #include "pciehp.h" 36 37 static void program_hpp_type0(struct pci_dev *dev, struct hpp_type0 *hpp) 38 { 39 u16 pci_cmd, pci_bctl; 40 41 if (hpp->revision > 1) { 42 printk(KERN_WARNING "%s: Rev.%d type0 record not supported\n", 43 __FUNCTION__, hpp->revision); 44 return; 45 } 46 47 pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, hpp->cache_line_size); 48 pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpp->latency_timer); 49 pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); 50 if (hpp->enable_serr) 51 pci_cmd |= PCI_COMMAND_SERR; 52 else 53 pci_cmd &= ~PCI_COMMAND_SERR; 54 if (hpp->enable_perr) 55 pci_cmd |= PCI_COMMAND_PARITY; 56 else 57 pci_cmd &= ~PCI_COMMAND_PARITY; 58 pci_write_config_word(dev, PCI_COMMAND, pci_cmd); 59 60 /* Program bridge control value */ 61 if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { 62 pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 63 hpp->latency_timer); 64 pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); 65 if (hpp->enable_serr) 66 pci_bctl |= PCI_BRIDGE_CTL_SERR; 67 else 68 pci_bctl &= ~PCI_BRIDGE_CTL_SERR; 69 if (hpp->enable_perr) 70 pci_bctl |= PCI_BRIDGE_CTL_PARITY; 71 else 72 pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; 73 pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl); 74 } 75 } 76 77 static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp) 78 { 79 int pos; 80 u16 reg16; 81 u32 reg32; 82 83 if (hpp->revision > 1) { 84 printk(KERN_WARNING "%s: Rev.%d type2 record not supported\n", 85 __FUNCTION__, hpp->revision); 86 return; 87 } 88 89 /* Find PCI Express capability */ 90 pos = pci_find_capability(dev, PCI_CAP_ID_EXP); 91 if (!pos) 92 return; 93 94 /* Initialize Device Control Register */ 95 pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, ®16); 96 reg16 = (reg16 & hpp->pci_exp_devctl_and) | hpp->pci_exp_devctl_or; 97 pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, reg16); 98 99 /* Initialize Link Control Register */ 100 if (dev->subordinate) { 101 pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, ®16); 102 reg16 = (reg16 & hpp->pci_exp_lnkctl_and) 103 | hpp->pci_exp_lnkctl_or; 104 pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, reg16); 105 } 106 107 /* Find Advanced Error Reporting Enhanced Capability */ 108 pos = 256; 109 do { 110 pci_read_config_dword(dev, pos, ®32); 111 if (PCI_EXT_CAP_ID(reg32) == PCI_EXT_CAP_ID_ERR) 112 break; 113 } while ((pos = PCI_EXT_CAP_NEXT(reg32))); 114 if (!pos) 115 return; 116 117 /* Initialize Uncorrectable Error Mask Register */ 118 pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, ®32); 119 reg32 = (reg32 & hpp->unc_err_mask_and) | hpp->unc_err_mask_or; 120 pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, reg32); 121 122 /* Initialize Uncorrectable Error Severity Register */ 123 pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, ®32); 124 reg32 = (reg32 & hpp->unc_err_sever_and) | hpp->unc_err_sever_or; 125 pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, reg32); 126 127 /* Initialize Correctable Error Mask Register */ 128 pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®32); 129 reg32 = (reg32 & hpp->cor_err_mask_and) | hpp->cor_err_mask_or; 130 pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg32); 131 132 /* Initialize Advanced Error Capabilities and Control Register */ 133 pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32); 134 reg32 = (reg32 & hpp->adv_err_cap_and) | hpp->adv_err_cap_or; 135 pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32); 136 137 /* 138 * FIXME: The following two registers are not supported yet. 139 * 140 * o Secondary Uncorrectable Error Severity Register 141 * o Secondary Uncorrectable Error Mask Register 142 */ 143 } 144 145 static void program_fw_provided_values(struct pci_dev *dev) 146 { 147 struct pci_dev *cdev; 148 struct hotplug_params hpp; 149 150 /* Program hpp values for this device */ 151 if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL || 152 (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && 153 (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) 154 return; 155 156 if (pciehp_get_hp_params_from_firmware(dev, &hpp)) { 157 printk(KERN_WARNING "%s: Could not get hotplug parameters\n", 158 __FUNCTION__); 159 return; 160 } 161 162 if (hpp.t2) 163 program_hpp_type2(dev, hpp.t2); 164 if (hpp.t0) 165 program_hpp_type0(dev, hpp.t0); 166 167 /* Program child devices */ 168 if (dev->subordinate) { 169 list_for_each_entry(cdev, &dev->subordinate->devices, 170 bus_list) 171 program_fw_provided_values(cdev); 172 } 173 } 174 175 static int pciehp_add_bridge(struct pci_dev *dev) 176 { 177 struct pci_bus *parent = dev->bus; 178 int pass, busnr, start = parent->secondary; 179 int end = parent->subordinate; 180 181 for (busnr = start; busnr <= end; busnr++) { 182 if (!pci_find_bus(pci_domain_nr(parent), busnr)) 183 break; 184 } 185 if (busnr-- > end) { 186 err("No bus number available for hot-added bridge %s\n", 187 pci_name(dev)); 188 return -1; 189 } 190 for (pass = 0; pass < 2; pass++) 191 busnr = pci_scan_bridge(parent, dev, busnr, pass); 192 if (!dev->subordinate) 193 return -1; 194 pci_bus_size_bridges(dev->subordinate); 195 pci_bus_assign_resources(parent); 196 pci_enable_bridges(parent); 197 pci_bus_add_devices(parent); 198 return 0; 199 } 200 201 int pciehp_configure_device(struct slot *p_slot) 202 { 203 struct pci_dev *dev; 204 struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; 205 int num, fn; 206 207 dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0)); 208 if (dev) { 209 err("Device %s already exists at %x:%x, cannot hot-add\n", 210 pci_name(dev), p_slot->bus, p_slot->device); 211 pci_dev_put(dev); 212 return -EINVAL; 213 } 214 215 num = pci_scan_slot(parent, PCI_DEVFN(p_slot->device, 0)); 216 if (num == 0) { 217 err("No new device found\n"); 218 return -ENODEV; 219 } 220 221 for (fn = 0; fn < 8; fn++) { 222 dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, fn)); 223 if (!dev) 224 continue; 225 if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { 226 err("Cannot hot-add display device %s\n", 227 pci_name(dev)); 228 pci_dev_put(dev); 229 continue; 230 } 231 if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || 232 (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) { 233 pciehp_add_bridge(dev); 234 } 235 program_fw_provided_values(dev); 236 pci_dev_put(dev); 237 } 238 239 pci_bus_assign_resources(parent); 240 pci_bus_add_devices(parent); 241 return 0; 242 } 243 244 int pciehp_unconfigure_device(struct slot *p_slot) 245 { 246 int ret, rc = 0; 247 int j; 248 u8 bctl = 0; 249 u8 presence = 0; 250 struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; 251 252 dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, 253 p_slot->device); 254 255 for (j=0; j<8 ; j++) { 256 struct pci_dev* temp = pci_get_slot(parent, 257 (p_slot->device << 3) | j); 258 if (!temp) 259 continue; 260 if ((temp->class >> 16) == PCI_BASE_CLASS_DISPLAY) { 261 err("Cannot remove display device %s\n", 262 pci_name(temp)); 263 pci_dev_put(temp); 264 continue; 265 } 266 if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { 267 ret = p_slot->hpc_ops->get_adapter_status(p_slot, 268 &presence); 269 if (!ret && presence) { 270 pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, 271 &bctl); 272 if (bctl & PCI_BRIDGE_CTL_VGA) { 273 err("Cannot remove display device %s\n", 274 pci_name(temp)); 275 pci_dev_put(temp); 276 continue; 277 } 278 } 279 } 280 pci_remove_bus_device(temp); 281 pci_dev_put(temp); 282 } 283 /* 284 * Some PCI Express root ports require fixup after hot-plug operation. 285 */ 286 if (pcie_mch_quirk) 287 pci_fixup_device(pci_fixup_final, p_slot->ctrl->pci_dev); 288 289 return rc; 290 } 291 292