linux/drivers/pci/hotplug/cpci_hotplug_pci.c
<<
>>
Prefs
   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
  36extern 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
  49u8 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
  69int 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
  96u16 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
 114int 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
 143int 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
 164int 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
 190int 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
 219int 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
 253int cpci_configure_slot(struct slot *slot)
 254{
 255        struct pci_dev *dev;
 256        struct pci_bus *parent;
 257        int ret = 0;
 258
 259        dbg("%s - enter", __func__);
 260
 261        pci_lock_rescan_remove();
 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", __func__, n);
 280                slot->dev = pci_get_slot(slot->bus, slot->devfn);
 281                if (slot->dev == NULL) {
 282                        err("Could not find PCI device for slot %02x", slot->number);
 283                        ret = -ENODEV;
 284                        goto out;
 285                }
 286        }
 287        parent = slot->dev->bus;
 288
 289        list_for_each_entry(dev, &parent->devices, bus_list) {
 290                if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn))
 291                        continue;
 292                if (pci_is_bridge(dev))
 293                        pci_hp_add_bridge(dev);
 294        }
 295
 296
 297        pci_assign_unassigned_bridge_resources(parent->self);
 298
 299        pci_bus_add_devices(parent);
 300
 301 out:
 302        pci_unlock_rescan_remove();
 303        dbg("%s - exit", __func__);
 304        return ret;
 305}
 306
 307int cpci_unconfigure_slot(struct slot *slot)
 308{
 309        struct pci_dev *dev, *temp;
 310
 311        dbg("%s - enter", __func__);
 312        if (!slot->dev) {
 313                err("No device for slot %02x\n", slot->number);
 314                return -ENODEV;
 315        }
 316
 317        pci_lock_rescan_remove();
 318
 319        list_for_each_entry_safe(dev, temp, &slot->bus->devices, bus_list) {
 320                if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn))
 321                        continue;
 322                pci_dev_get(dev);
 323                pci_stop_and_remove_bus_device(dev);
 324                pci_dev_put(dev);
 325        }
 326        pci_dev_put(slot->dev);
 327        slot->dev = NULL;
 328
 329        pci_unlock_rescan_remove();
 330
 331        dbg("%s - exit", __func__);
 332        return 0;
 333}
 334