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