313 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * CompactPCI Hot Plug Driver PCI functions4 *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 33u8 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 53int 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 else71 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 80u16 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 98int 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 else122 ins = 1;123 }124 return ins;125}126 127int 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 148int 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 174int 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 202int 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 functions233 */234 235int 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, but258 * 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 286int 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