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 __func__, 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 __func__, 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 = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); 109 if (!pos) 110 return; 111 112 /* Initialize Uncorrectable Error Mask Register */ 113 pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, ®32); 114 reg32 = (reg32 & hpp->unc_err_mask_and) | hpp->unc_err_mask_or; 115 pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, reg32); 116 117 /* Initialize Uncorrectable Error Severity Register */ 118 pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, ®32); 119 reg32 = (reg32 & hpp->unc_err_sever_and) | hpp->unc_err_sever_or; 120 pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, reg32); 121 122 /* Initialize Correctable Error Mask Register */ 123 pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®32); 124 reg32 = (reg32 & hpp->cor_err_mask_and) | hpp->cor_err_mask_or; 125 pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg32); 126 127 /* Initialize Advanced Error Capabilities and Control Register */ 128 pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32); 129 reg32 = (reg32 & hpp->adv_err_cap_and) | hpp->adv_err_cap_or; 130 pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32); 131 132 /* 133 * FIXME: The following two registers are not supported yet. 134 * 135 * o Secondary Uncorrectable Error Severity Register 136 * o Secondary Uncorrectable Error Mask Register 137 */ 138 } 139 140 static void program_fw_provided_values(struct pci_dev *dev) 141 { 142 struct pci_dev *cdev; 143 struct hotplug_params hpp; 144 145 /* Program hpp values for this device */ 146 if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL || 147 (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && 148 (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) 149 return; 150 151 if (pciehp_get_hp_params_from_firmware(dev, &hpp)) { 152 printk(KERN_WARNING "%s: Could not get hotplug parameters\n", 153 __func__); 154 return; 155 } 156 157 if (hpp.t2) 158 program_hpp_type2(dev, hpp.t2); 159 if (hpp.t0) 160 program_hpp_type0(dev, hpp.t0); 161 162 /* Program child devices */ 163 if (dev->subordinate) { 164 list_for_each_entry(cdev, &dev->subordinate->devices, 165 bus_list) 166 program_fw_provided_values(cdev); 167 } 168 } 169 170 static int __ref pciehp_add_bridge(struct pci_dev *dev) 171 { 172 struct pci_bus *parent = dev->bus; 173 int pass, busnr, start = parent->secondary; 174 int end = parent->subordinate; 175 176 for (busnr = start; busnr <= end; busnr++) { 177 if (!pci_find_bus(pci_domain_nr(parent), busnr)) 178 break; 179 } 180 if (busnr-- > end) { 181 err("No bus number available for hot-added bridge %s\n", 182 pci_name(dev)); 183 return -1; 184 } 185 for (pass = 0; pass < 2; pass++) 186 busnr = pci_scan_bridge(parent, dev, busnr, pass); 187 if (!dev->subordinate) 188 return -1; 189 pci_bus_size_bridges(dev->subordinate); 190 pci_bus_assign_resources(parent); 191 pci_enable_bridges(parent); 192 pci_bus_add_devices(parent); 193 return 0; 194 } 195 196 int pciehp_configure_device(struct slot *p_slot) 197 { 198 struct pci_dev *dev; 199 struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; 200 int num, fn; 201 202 dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0)); 203 if (dev) { 204 err("Device %s already exists at %x:%x, cannot hot-add\n", 205 pci_name(dev), p_slot->bus, p_slot->device); 206 pci_dev_put(dev); 207 return -EINVAL; 208 } 209 210 num = pci_scan_slot(parent, PCI_DEVFN(p_slot->device, 0)); 211 if (num == 0) { 212 err("No new device found\n"); 213 return -ENODEV; 214 } 215 216 for (fn = 0; fn < 8; fn++) { 217 dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, fn)); 218 if (!dev) 219 continue; 220 if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { 221 err("Cannot hot-add display device %s\n", 222 pci_name(dev)); 223 pci_dev_put(dev); 224 continue; 225 } 226 if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || 227 (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) { 228 pciehp_add_bridge(dev); 229 } 230 program_fw_provided_values(dev); 231 pci_dev_put(dev); 232 } 233 234 pci_bus_assign_resources(parent); 235 pci_bus_add_devices(parent); 236 return 0; 237 } 238 239 int pciehp_unconfigure_device(struct slot *p_slot) 240 { 241 int ret, rc = 0; 242 int j; 243 u8 bctl = 0; 244 u8 presence = 0; 245 struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; 246 u16 command; 247 248 dbg("%s: bus/dev = %x/%x\n", __func__, p_slot->bus, 249 p_slot->device); 250 ret = p_slot->hpc_ops->get_adapter_status(p_slot, &presence); 251 if (ret) 252 presence = 0; 253 254 for (j = 0; j < 8; j++) { 255 struct pci_dev* temp = pci_get_slot(parent, 256 (p_slot->device << 3) | j); 257 if (!temp) 258 continue; 259 if ((temp->class >> 16) == PCI_BASE_CLASS_DISPLAY) { 260 err("Cannot remove display device %s\n", 261 pci_name(temp)); 262 pci_dev_put(temp); 263 continue; 264 } 265 if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) { 266 pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl); 267 if (bctl & PCI_BRIDGE_CTL_VGA) { 268 err("Cannot remove display device %s\n", 269 pci_name(temp)); 270 pci_dev_put(temp); 271 continue; 272 } 273 } 274 pci_remove_bus_device(temp); 275 /* 276 * Ensure that no new Requests will be generated from 277 * the device. 278 */ 279 if (presence) { 280 pci_read_config_word(temp, PCI_COMMAND, &command); 281 command &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_SERR); 282 command |= PCI_COMMAND_INTX_DISABLE; 283 pci_write_config_word(temp, PCI_COMMAND, command); 284 } 285 pci_dev_put(temp); 286 } 287 /* 288 * Some PCI Express root ports require fixup after hot-plug operation. 289 */ 290 if (pcie_mch_quirk) 291 pci_fixup_device(pci_fixup_final, p_slot->ctrl->pci_dev); 292 293 return rc; 294 } 295