1 /* 2 * CompactPCI Hot Plug Driver PCI functions 3 * 4 * Copyright (C) 2002,2005 by SOMA Networks, Inc. 5 * 6 * All rights reserved. 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or (at 11 * your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 16 * NON INFRINGEMENT. See the GNU General Public License for more 17 * details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 * 23 * Send feedback to <scottm@somanetworks.com> 24 */ 25 26 #include <linux/module.h> 27 #include <linux/kernel.h> 28 #include <linux/pci.h> 29 #include <linux/pci_hotplug.h> 30 #include <linux/proc_fs.h> 31 #include "../pci.h" 32 #include "cpci_hotplug.h" 33 34 #define MY_NAME "cpci_hotplug" 35 36 extern int cpci_debug; 37 38 #define dbg(format, arg...) \ 39 do { \ 40 if (cpci_debug) \ 41 printk (KERN_DEBUG "%s: " format "\n", \ 42 MY_NAME , ## arg); \ 43 } while (0) 44 #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) 45 #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) 46 #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) 47 48 49 u8 cpci_get_attention_status(struct slot* slot) 50 { 51 int hs_cap; 52 u16 hs_csr; 53 54 hs_cap = pci_bus_find_capability(slot->bus, 55 slot->devfn, 56 PCI_CAP_ID_CHSWP); 57 if (!hs_cap) 58 return 0; 59 60 if (pci_bus_read_config_word(slot->bus, 61 slot->devfn, 62 hs_cap + 2, 63 &hs_csr)) 64 return 0; 65 66 return hs_csr & 0x0008 ? 1 : 0; 67 } 68 69 int cpci_set_attention_status(struct slot* slot, int status) 70 { 71 int hs_cap; 72 u16 hs_csr; 73 74 hs_cap = pci_bus_find_capability(slot->bus, 75 slot->devfn, 76 PCI_CAP_ID_CHSWP); 77 if (!hs_cap) 78 return 0; 79 if (pci_bus_read_config_word(slot->bus, 80 slot->devfn, 81 hs_cap + 2, 82 &hs_csr)) 83 return 0; 84 if (status) 85 hs_csr |= HS_CSR_LOO; 86 else 87 hs_csr &= ~HS_CSR_LOO; 88 if (pci_bus_write_config_word(slot->bus, 89 slot->devfn, 90 hs_cap + 2, 91 hs_csr)) 92 return 0; 93 return 1; 94 } 95 96 u16 cpci_get_hs_csr(struct slot* slot) 97 { 98 int hs_cap; 99 u16 hs_csr; 100 101 hs_cap = pci_bus_find_capability(slot->bus, 102 slot->devfn, 103 PCI_CAP_ID_CHSWP); 104 if (!hs_cap) 105 return 0xFFFF; 106 if (pci_bus_read_config_word(slot->bus, 107 slot->devfn, 108 hs_cap + 2, 109 &hs_csr)) 110 return 0xFFFF; 111 return hs_csr; 112 } 113 114 int cpci_check_and_clear_ins(struct slot* slot) 115 { 116 int hs_cap; 117 u16 hs_csr; 118 int ins = 0; 119 120 hs_cap = pci_bus_find_capability(slot->bus, 121 slot->devfn, 122 PCI_CAP_ID_CHSWP); 123 if (!hs_cap) 124 return 0; 125 if (pci_bus_read_config_word(slot->bus, 126 slot->devfn, 127 hs_cap + 2, 128 &hs_csr)) 129 return 0; 130 if (hs_csr & HS_CSR_INS) { 131 /* Clear INS (by setting it) */ 132 if (pci_bus_write_config_word(slot->bus, 133 slot->devfn, 134 hs_cap + 2, 135 hs_csr)) 136 ins = 0; 137 else 138 ins = 1; 139 } 140 return ins; 141 } 142 143 int cpci_check_ext(struct slot* slot) 144 { 145 int hs_cap; 146 u16 hs_csr; 147 int ext = 0; 148 149 hs_cap = pci_bus_find_capability(slot->bus, 150 slot->devfn, 151 PCI_CAP_ID_CHSWP); 152 if (!hs_cap) 153 return 0; 154 if (pci_bus_read_config_word(slot->bus, 155 slot->devfn, 156 hs_cap + 2, 157 &hs_csr)) 158 return 0; 159 if (hs_csr & HS_CSR_EXT) 160 ext = 1; 161 return ext; 162 } 163 164 int cpci_clear_ext(struct slot* slot) 165 { 166 int hs_cap; 167 u16 hs_csr; 168 169 hs_cap = pci_bus_find_capability(slot->bus, 170 slot->devfn, 171 PCI_CAP_ID_CHSWP); 172 if (!hs_cap) 173 return -ENODEV; 174 if (pci_bus_read_config_word(slot->bus, 175 slot->devfn, 176 hs_cap + 2, 177 &hs_csr)) 178 return -ENODEV; 179 if (hs_csr & HS_CSR_EXT) { 180 /* Clear EXT (by setting it) */ 181 if (pci_bus_write_config_word(slot->bus, 182 slot->devfn, 183 hs_cap + 2, 184 hs_csr)) 185 return -ENODEV; 186 } 187 return 0; 188 } 189 190 int cpci_led_on(struct slot* slot) 191 { 192 int hs_cap; 193 u16 hs_csr; 194 195 hs_cap = pci_bus_find_capability(slot->bus, 196 slot->devfn, 197 PCI_CAP_ID_CHSWP); 198 if (!hs_cap) 199 return -ENODEV; 200 if (pci_bus_read_config_word(slot->bus, 201 slot->devfn, 202 hs_cap + 2, 203 &hs_csr)) 204 return -ENODEV; 205 if ((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) { 206 hs_csr |= HS_CSR_LOO; 207 if (pci_bus_write_config_word(slot->bus, 208 slot->devfn, 209 hs_cap + 2, 210 hs_csr)) { 211 err("Could not set LOO for slot %s", 212 hotplug_slot_name(slot->hotplug_slot)); 213 return -ENODEV; 214 } 215 } 216 return 0; 217 } 218 219 int cpci_led_off(struct slot* slot) 220 { 221 int hs_cap; 222 u16 hs_csr; 223 224 hs_cap = pci_bus_find_capability(slot->bus, 225 slot->devfn, 226 PCI_CAP_ID_CHSWP); 227 if (!hs_cap) 228 return -ENODEV; 229 if (pci_bus_read_config_word(slot->bus, 230 slot->devfn, 231 hs_cap + 2, 232 &hs_csr)) 233 return -ENODEV; 234 if (hs_csr & HS_CSR_LOO) { 235 hs_csr &= ~HS_CSR_LOO; 236 if (pci_bus_write_config_word(slot->bus, 237 slot->devfn, 238 hs_cap + 2, 239 hs_csr)) { 240 err("Could not clear LOO for slot %s", 241 hotplug_slot_name(slot->hotplug_slot)); 242 return -ENODEV; 243 } 244 } 245 return 0; 246 } 247 248 249 /* 250 * Device configuration functions 251 */ 252 253 int __ref cpci_configure_slot(struct slot *slot) 254 { 255 struct pci_bus *parent; 256 int fn; 257 258 dbg("%s - enter", __func__); 259 260 if (slot->dev == NULL) { 261 dbg("pci_dev null, finding %02x:%02x:%x", 262 slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn)); 263 slot->dev = pci_get_slot(slot->bus, slot->devfn); 264 } 265 266 /* Still NULL? Well then scan for it! */ 267 if (slot->dev == NULL) { 268 int n; 269 dbg("pci_dev still null"); 270 271 /* 272 * This will generate pci_dev structures for all functions, but 273 * we will only call this case when lookup fails. 274 */ 275 n = pci_scan_slot(slot->bus, slot->devfn); 276 dbg("%s: pci_scan_slot returned %d", __func__, n); 277 slot->dev = pci_get_slot(slot->bus, slot->devfn); 278 if (slot->dev == NULL) { 279 err("Could not find PCI device for slot %02x", slot->number); 280 return -ENODEV; 281 } 282 } 283 parent = slot->dev->bus; 284 285 for (fn = 0; fn < 8; fn++) { 286 struct pci_dev *dev; 287 288 dev = pci_get_slot(parent, PCI_DEVFN(PCI_SLOT(slot->devfn), fn)); 289 if (!dev) 290 continue; 291 if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || 292 (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) { 293 /* Find an unused bus number for the new bridge */ 294 struct pci_bus *child; 295 unsigned char busnr, start = parent->secondary; 296 unsigned char end = parent->subordinate; 297 298 for (busnr = start; busnr <= end; busnr++) { 299 if (!pci_find_bus(pci_domain_nr(parent), 300 busnr)) 301 break; 302 } 303 if (busnr >= end) { 304 err("No free bus for hot-added bridge\n"); 305 pci_dev_put(dev); 306 continue; 307 } 308 child = pci_add_new_bus(parent, dev, busnr); 309 if (!child) { 310 err("Cannot add new bus for %s\n", 311 pci_name(dev)); 312 pci_dev_put(dev); 313 continue; 314 } 315 child->subordinate = pci_do_scan_bus(child); 316 pci_bus_size_bridges(child); 317 } 318 pci_dev_put(dev); 319 } 320 321 pci_bus_assign_resources(parent); 322 pci_bus_add_devices(parent); 323 pci_enable_bridges(parent); 324 325 dbg("%s - exit", __func__); 326 return 0; 327 } 328 329 int cpci_unconfigure_slot(struct slot* slot) 330 { 331 int i; 332 struct pci_dev *dev; 333 334 dbg("%s - enter", __func__); 335 if (!slot->dev) { 336 err("No device for slot %02x\n", slot->number); 337 return -ENODEV; 338 } 339 340 for (i = 0; i < 8; i++) { 341 dev = pci_get_slot(slot->bus, 342 PCI_DEVFN(PCI_SLOT(slot->devfn), i)); 343 if (dev) { 344 pci_remove_bus_device(dev); 345 pci_dev_put(dev); 346 } 347 } 348 pci_dev_put(slot->dev); 349 slot->dev = NULL; 350 351 dbg("%s - exit", __func__); 352 return 0; 353 } 354