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/config.h> 27 #include <linux/module.h> 28 #include <linux/kernel.h> 29 #include <linux/pci.h> 30 #include <linux/proc_fs.h> 31 #include "../pci.h" 32 #include "pci_hotplug.h" 33 #include "cpci_hotplug.h" 34 35 #define MY_NAME "cpci_hotplug" 36 37 extern int cpci_debug; 38 39 #define dbg(format, arg...) \ 40 do { \ 41 if (cpci_debug) \ 42 printk (KERN_DEBUG "%s: " format "\n", \ 43 MY_NAME , ## arg); \ 44 } while (0) 45 #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) 46 #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) 47 #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) 48 49 #define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) 50 51 52 u8 cpci_get_attention_status(struct slot* slot) 53 { 54 int hs_cap; 55 u16 hs_csr; 56 57 hs_cap = pci_bus_find_capability(slot->bus, 58 slot->devfn, 59 PCI_CAP_ID_CHSWP); 60 if (!hs_cap) 61 return 0; 62 63 if (pci_bus_read_config_word(slot->bus, 64 slot->devfn, 65 hs_cap + 2, 66 &hs_csr)) 67 return 0; 68 69 return hs_csr & 0x0008 ? 1 : 0; 70 } 71 72 int cpci_set_attention_status(struct slot* slot, int status) 73 { 74 int hs_cap; 75 u16 hs_csr; 76 77 hs_cap = pci_bus_find_capability(slot->bus, 78 slot->devfn, 79 PCI_CAP_ID_CHSWP); 80 if (!hs_cap) 81 return 0; 82 if (pci_bus_read_config_word(slot->bus, 83 slot->devfn, 84 hs_cap + 2, 85 &hs_csr)) 86 return 0; 87 if (status) 88 hs_csr |= HS_CSR_LOO; 89 else 90 hs_csr &= ~HS_CSR_LOO; 91 if (pci_bus_write_config_word(slot->bus, 92 slot->devfn, 93 hs_cap + 2, 94 hs_csr)) 95 return 0; 96 return 1; 97 } 98 99 u16 cpci_get_hs_csr(struct slot* slot) 100 { 101 int hs_cap; 102 u16 hs_csr; 103 104 hs_cap = pci_bus_find_capability(slot->bus, 105 slot->devfn, 106 PCI_CAP_ID_CHSWP); 107 if (!hs_cap) 108 return 0xFFFF; 109 if (pci_bus_read_config_word(slot->bus, 110 slot->devfn, 111 hs_cap + 2, 112 &hs_csr)) 113 return 0xFFFF; 114 return hs_csr; 115 } 116 117 int cpci_check_and_clear_ins(struct slot* slot) 118 { 119 int hs_cap; 120 u16 hs_csr; 121 int ins = 0; 122 123 hs_cap = pci_bus_find_capability(slot->bus, 124 slot->devfn, 125 PCI_CAP_ID_CHSWP); 126 if (!hs_cap) 127 return 0; 128 if (pci_bus_read_config_word(slot->bus, 129 slot->devfn, 130 hs_cap + 2, 131 &hs_csr)) 132 return 0; 133 if (hs_csr & HS_CSR_INS) { 134 /* Clear INS (by setting it) */ 135 if (pci_bus_write_config_word(slot->bus, 136 slot->devfn, 137 hs_cap + 2, 138 hs_csr)) 139 ins = 0; 140 else 141 ins = 1; 142 } 143 return ins; 144 } 145 146 int cpci_check_ext(struct slot* slot) 147 { 148 int hs_cap; 149 u16 hs_csr; 150 int ext = 0; 151 152 hs_cap = pci_bus_find_capability(slot->bus, 153 slot->devfn, 154 PCI_CAP_ID_CHSWP); 155 if (!hs_cap) 156 return 0; 157 if (pci_bus_read_config_word(slot->bus, 158 slot->devfn, 159 hs_cap + 2, 160 &hs_csr)) 161 return 0; 162 if (hs_csr & HS_CSR_EXT) 163 ext = 1; 164 return ext; 165 } 166 167 int cpci_clear_ext(struct slot* slot) 168 { 169 int hs_cap; 170 u16 hs_csr; 171 172 hs_cap = pci_bus_find_capability(slot->bus, 173 slot->devfn, 174 PCI_CAP_ID_CHSWP); 175 if (!hs_cap) 176 return -ENODEV; 177 if (pci_bus_read_config_word(slot->bus, 178 slot->devfn, 179 hs_cap + 2, 180 &hs_csr)) 181 return -ENODEV; 182 if (hs_csr & HS_CSR_EXT) { 183 /* Clear EXT (by setting it) */ 184 if (pci_bus_write_config_word(slot->bus, 185 slot->devfn, 186 hs_cap + 2, 187 hs_csr)) 188 return -ENODEV; 189 } 190 return 0; 191 } 192 193 int cpci_led_on(struct slot* slot) 194 { 195 int hs_cap; 196 u16 hs_csr; 197 198 hs_cap = pci_bus_find_capability(slot->bus, 199 slot->devfn, 200 PCI_CAP_ID_CHSWP); 201 if (!hs_cap) 202 return -ENODEV; 203 if (pci_bus_read_config_word(slot->bus, 204 slot->devfn, 205 hs_cap + 2, 206 &hs_csr)) 207 return -ENODEV; 208 if ((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) { 209 hs_csr |= HS_CSR_LOO; 210 if (pci_bus_write_config_word(slot->bus, 211 slot->devfn, 212 hs_cap + 2, 213 hs_csr)) { 214 err("Could not set LOO for slot %s", 215 slot->hotplug_slot->name); 216 return -ENODEV; 217 } 218 } 219 return 0; 220 } 221 222 int cpci_led_off(struct slot* slot) 223 { 224 int hs_cap; 225 u16 hs_csr; 226 227 hs_cap = pci_bus_find_capability(slot->bus, 228 slot->devfn, 229 PCI_CAP_ID_CHSWP); 230 if (!hs_cap) 231 return -ENODEV; 232 if (pci_bus_read_config_word(slot->bus, 233 slot->devfn, 234 hs_cap + 2, 235 &hs_csr)) 236 return -ENODEV; 237 if (hs_csr & HS_CSR_LOO) { 238 hs_csr &= ~HS_CSR_LOO; 239 if (pci_bus_write_config_word(slot->bus, 240 slot->devfn, 241 hs_cap + 2, 242 hs_csr)) { 243 err("Could not clear LOO for slot %s", 244 slot->hotplug_slot->name); 245 return -ENODEV; 246 } 247 } 248 return 0; 249 } 250 251 252 /* 253 * Device configuration functions 254 */ 255 256 int cpci_configure_slot(struct slot* slot) 257 { 258 unsigned char busnr; 259 struct pci_bus *child; 260 261 dbg("%s - enter", __FUNCTION__); 262 263 if (slot->dev == NULL) { 264 dbg("pci_dev null, finding %02x:%02x:%x", 265 slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn)); 266 slot->dev = pci_get_slot(slot->bus, slot->devfn); 267 } 268 269 /* Still NULL? Well then scan for it! */ 270 if (slot->dev == NULL) { 271 int n; 272 dbg("pci_dev still null"); 273 274 /* 275 * This will generate pci_dev structures for all functions, but 276 * we will only call this case when lookup fails. 277 */ 278 n = pci_scan_slot(slot->bus, slot->devfn); 279 dbg("%s: pci_scan_slot returned %d", __FUNCTION__, n); 280 if (n > 0) 281 pci_bus_add_devices(slot->bus); 282 slot->dev = pci_get_slot(slot->bus, slot->devfn); 283 if (slot->dev == NULL) { 284 err("Could not find PCI device for slot %02x", slot->number); 285 return 1; 286 } 287 } 288 289 if (slot->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { 290 pci_read_config_byte(slot->dev, PCI_SECONDARY_BUS, &busnr); 291 child = pci_add_new_bus(slot->dev->bus, slot->dev, busnr); 292 pci_do_scan_bus(child); 293 pci_bus_size_bridges(child); 294 } 295 296 pci_bus_assign_resources(slot->dev->bus); 297 298 dbg("%s - exit", __FUNCTION__); 299 return 0; 300 } 301 302 int cpci_unconfigure_slot(struct slot* slot) 303 { 304 int i; 305 struct pci_dev *dev; 306 307 dbg("%s - enter", __FUNCTION__); 308 if (!slot->dev) { 309 err("No device for slot %02x\n", slot->number); 310 return -ENODEV; 311 } 312 313 for (i = 0; i < 8; i++) { 314 dev = pci_get_slot(slot->bus, 315 PCI_DEVFN(PCI_SLOT(slot->devfn), i)); 316 if (dev) { 317 pci_remove_bus_device(dev); 318 pci_dev_put(dev); 319 } 320 } 321 pci_dev_put(slot->dev); 322 slot->dev = NULL; 323 324 dbg("%s - exit", __FUNCTION__); 325 return 0; 326 } 327