linux/drivers/pci/hotplug/cpci_hotplug_pci.c
<<
>>
Prefs
   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
  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        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
  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                else
 122                        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 functions
 233 */
 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, 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
 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