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 __ref cpci_configure_slot(struct slot *slot)
 254{
 255        struct pci_bus *parent;
 256        int fn;
 257
 258        dbg("%s - enter", __func__);
 259
 260        if (slot->dev == NULL) {
 261                dbg("pci_dev null, finding %02x:%02x:%x",
 262                    slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn));
 263                slot->dev = pci_get_slot(slot->bus, slot->devfn);
 264        }
 265
 266        /* Still NULL? Well then scan for it! */
 267        if (slot->dev == NULL) {
 268                int n;
 269                dbg("pci_dev still null");
 270
 271                /*
 272                 * This will generate pci_dev structures for all functions, but
 273                 * we will only call this case when lookup fails.
 274                 */
 275                n = pci_scan_slot(slot->bus, slot->devfn);
 276                dbg("%s: pci_scan_slot returned %d", __func__, n);
 277                slot->dev = pci_get_slot(slot->bus, slot->devfn);
 278                if (slot->dev == NULL) {
 279                        err("Could not find PCI device for slot %02x", slot->number);
 280                        return -ENODEV;
 281                }
 282        }
 283        parent = slot->dev->bus;
 284
 285        for (fn = 0; fn < 8; fn++) {
 286                struct pci_dev *dev;
 287
 288                dev = pci_get_slot(parent, PCI_DEVFN(PCI_SLOT(slot->devfn), fn));
 289                if (!dev)
 290                        continue;
 291                if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
 292                    (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
 293                        /* Find an unused bus number for the new bridge */
 294                        struct pci_bus *child;
 295                        unsigned char busnr, start = parent->secondary;
 296                        unsigned char end = parent->subordinate;
 297
 298                        for (busnr = start; busnr <= end; busnr++) {
 299                                if (!pci_find_bus(pci_domain_nr(parent),
 300                                                  busnr))
 301                                        break;
 302                        }
 303                        if (busnr >= end) {
 304                                err("No free bus for hot-added bridge\n");
 305                                pci_dev_put(dev);
 306                                continue;
 307                        }
 308                        child = pci_add_new_bus(parent, dev, busnr);
 309                        if (!child) {
 310                                err("Cannot add new bus for %s\n",
 311                                    pci_name(dev));
 312                                pci_dev_put(dev);
 313                                continue;
 314                        }
 315                        child->subordinate = pci_do_scan_bus(child);
 316                        pci_bus_size_bridges(child);
 317                }
 318                pci_dev_put(dev);
 319        }
 320
 321        pci_bus_assign_resources(parent);
 322        pci_bus_add_devices(parent);
 323        pci_enable_bridges(parent);
 324
 325        dbg("%s - exit", __func__);
 326        return 0;
 327}
 328
 329int cpci_unconfigure_slot(struct slot* slot)
 330{
 331        int i;
 332        struct pci_dev *dev;
 333
 334        dbg("%s - enter", __func__);
 335        if (!slot->dev) {
 336                err("No device for slot %02x\n", slot->number);
 337                return -ENODEV;
 338        }
 339
 340        for (i = 0; i < 8; i++) {
 341                dev = pci_get_slot(slot->bus,
 342                                    PCI_DEVFN(PCI_SLOT(slot->devfn), i));
 343                if (dev) {
 344                        pci_remove_bus_device(dev);
 345                        pci_dev_put(dev);
 346                }
 347        }
 348        pci_dev_put(slot->dev);
 349        slot->dev = NULL;
 350
 351        dbg("%s - exit", __func__);
 352        return 0;
 353}
 354