root/drivers/pci/hotplug/acpiphp_core.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. acpiphp_register_attention
  2. acpiphp_unregister_attention
  3. enable_slot
  4. disable_slot
  5. set_attention_status
  6. get_power_status
  7. get_attention_status
  8. get_latch_status
  9. get_adapter_status
  10. acpiphp_register_hotplug_slot
  11. acpiphp_unregister_hotplug_slot
  12. acpiphp_init

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * ACPI PCI Hot Plug Controller Driver
   4  *
   5  * Copyright (C) 1995,2001 Compaq Computer Corporation
   6  * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
   7  * Copyright (C) 2001 IBM Corp.
   8  * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
   9  * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
  10  * Copyright (C) 2002,2003 NEC Corporation
  11  * Copyright (C) 2003-2005 Matthew Wilcox (willy@infradead.org)
  12  * Copyright (C) 2003-2005 Hewlett Packard
  13  *
  14  * All rights reserved.
  15  *
  16  * Send feedback to <kristen.c.accardi@intel.com>
  17  *
  18  */
  19 
  20 #define pr_fmt(fmt) "acpiphp: " fmt
  21 
  22 #include <linux/init.h>
  23 #include <linux/module.h>
  24 #include <linux/moduleparam.h>
  25 
  26 #include <linux/kernel.h>
  27 #include <linux/pci.h>
  28 #include <linux/pci-acpi.h>
  29 #include <linux/pci_hotplug.h>
  30 #include <linux/slab.h>
  31 #include <linux/smp.h>
  32 #include "acpiphp.h"
  33 
  34 /* name size which is used for entries in pcihpfs */
  35 #define SLOT_NAME_SIZE  21              /* {_SUN} */
  36 
  37 bool acpiphp_disabled;
  38 
  39 /* local variables */
  40 static struct acpiphp_attention_info *attention_info;
  41 
  42 #define DRIVER_VERSION  "0.5"
  43 #define DRIVER_AUTHOR   "Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kochi@bq.jp.nec.com>, Matthew Wilcox <willy@infradead.org>"
  44 #define DRIVER_DESC     "ACPI Hot Plug PCI Controller Driver"
  45 
  46 MODULE_AUTHOR(DRIVER_AUTHOR);
  47 MODULE_DESCRIPTION(DRIVER_DESC);
  48 MODULE_LICENSE("GPL");
  49 MODULE_PARM_DESC(disable, "disable acpiphp driver");
  50 module_param_named(disable, acpiphp_disabled, bool, 0444);
  51 
  52 static int enable_slot(struct hotplug_slot *slot);
  53 static int disable_slot(struct hotplug_slot *slot);
  54 static int set_attention_status(struct hotplug_slot *slot, u8 value);
  55 static int get_power_status(struct hotplug_slot *slot, u8 *value);
  56 static int get_attention_status(struct hotplug_slot *slot, u8 *value);
  57 static int get_latch_status(struct hotplug_slot *slot, u8 *value);
  58 static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
  59 
  60 static const struct hotplug_slot_ops acpi_hotplug_slot_ops = {
  61         .enable_slot            = enable_slot,
  62         .disable_slot           = disable_slot,
  63         .set_attention_status   = set_attention_status,
  64         .get_power_status       = get_power_status,
  65         .get_attention_status   = get_attention_status,
  66         .get_latch_status       = get_latch_status,
  67         .get_adapter_status     = get_adapter_status,
  68 };
  69 
  70 /**
  71  * acpiphp_register_attention - set attention LED callback
  72  * @info: must be completely filled with LED callbacks
  73  *
  74  * Description: This is used to register a hardware specific ACPI
  75  * driver that manipulates the attention LED.  All the fields in
  76  * info must be set.
  77  */
  78 int acpiphp_register_attention(struct acpiphp_attention_info *info)
  79 {
  80         int retval = -EINVAL;
  81 
  82         if (info && info->owner && info->set_attn &&
  83                         info->get_attn && !attention_info) {
  84                 retval = 0;
  85                 attention_info = info;
  86         }
  87         return retval;
  88 }
  89 EXPORT_SYMBOL_GPL(acpiphp_register_attention);
  90 
  91 
  92 /**
  93  * acpiphp_unregister_attention - unset attention LED callback
  94  * @info: must match the pointer used to register
  95  *
  96  * Description: This is used to un-register a hardware specific acpi
  97  * driver that manipulates the attention LED.  The pointer to the
  98  * info struct must be the same as the one used to set it.
  99  */
 100 int acpiphp_unregister_attention(struct acpiphp_attention_info *info)
 101 {
 102         int retval = -EINVAL;
 103 
 104         if (info && attention_info == info) {
 105                 attention_info = NULL;
 106                 retval = 0;
 107         }
 108         return retval;
 109 }
 110 EXPORT_SYMBOL_GPL(acpiphp_unregister_attention);
 111 
 112 
 113 /**
 114  * enable_slot - power on and enable a slot
 115  * @hotplug_slot: slot to enable
 116  *
 117  * Actual tasks are done in acpiphp_enable_slot()
 118  */
 119 static int enable_slot(struct hotplug_slot *hotplug_slot)
 120 {
 121         struct slot *slot = to_slot(hotplug_slot);
 122 
 123         pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
 124 
 125         /* enable the specified slot */
 126         return acpiphp_enable_slot(slot->acpi_slot);
 127 }
 128 
 129 
 130 /**
 131  * disable_slot - disable and power off a slot
 132  * @hotplug_slot: slot to disable
 133  *
 134  * Actual tasks are done in acpiphp_disable_slot()
 135  */
 136 static int disable_slot(struct hotplug_slot *hotplug_slot)
 137 {
 138         struct slot *slot = to_slot(hotplug_slot);
 139 
 140         pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
 141 
 142         /* disable the specified slot */
 143         return acpiphp_disable_slot(slot->acpi_slot);
 144 }
 145 
 146 
 147 /**
 148  * set_attention_status - set attention LED
 149  * @hotplug_slot: slot to set attention LED on
 150  * @status: value to set attention LED to (0 or 1)
 151  *
 152  * attention status LED, so we use a callback that
 153  * was registered with us.  This allows hardware specific
 154  * ACPI implementations to blink the light for us.
 155  */
 156 static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
 157 {
 158         int retval = -ENODEV;
 159 
 160         pr_debug("%s - physical_slot = %s\n", __func__,
 161                 hotplug_slot_name(hotplug_slot));
 162 
 163         if (attention_info && try_module_get(attention_info->owner)) {
 164                 retval = attention_info->set_attn(hotplug_slot, status);
 165                 module_put(attention_info->owner);
 166         } else
 167                 attention_info = NULL;
 168         return retval;
 169 }
 170 
 171 
 172 /**
 173  * get_power_status - get power status of a slot
 174  * @hotplug_slot: slot to get status
 175  * @value: pointer to store status
 176  *
 177  * Some platforms may not implement _STA method properly.
 178  * In that case, the value returned may not be reliable.
 179  */
 180 static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
 181 {
 182         struct slot *slot = to_slot(hotplug_slot);
 183 
 184         pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
 185 
 186         *value = acpiphp_get_power_status(slot->acpi_slot);
 187 
 188         return 0;
 189 }
 190 
 191 
 192 /**
 193  * get_attention_status - get attention LED status
 194  * @hotplug_slot: slot to get status from
 195  * @value: returns with value of attention LED
 196  *
 197  * ACPI doesn't have known method to determine the state
 198  * of the attention status LED, so we use a callback that
 199  * was registered with us.  This allows hardware specific
 200  * ACPI implementations to determine its state.
 201  */
 202 static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
 203 {
 204         int retval = -EINVAL;
 205 
 206         pr_debug("%s - physical_slot = %s\n", __func__,
 207                 hotplug_slot_name(hotplug_slot));
 208 
 209         if (attention_info && try_module_get(attention_info->owner)) {
 210                 retval = attention_info->get_attn(hotplug_slot, value);
 211                 module_put(attention_info->owner);
 212         } else
 213                 attention_info = NULL;
 214         return retval;
 215 }
 216 
 217 
 218 /**
 219  * get_latch_status - get latch status of a slot
 220  * @hotplug_slot: slot to get status
 221  * @value: pointer to store status
 222  *
 223  * ACPI doesn't provide any formal means to access latch status.
 224  * Instead, we fake latch status from _STA.
 225  */
 226 static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
 227 {
 228         struct slot *slot = to_slot(hotplug_slot);
 229 
 230         pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
 231 
 232         *value = acpiphp_get_latch_status(slot->acpi_slot);
 233 
 234         return 0;
 235 }
 236 
 237 
 238 /**
 239  * get_adapter_status - get adapter status of a slot
 240  * @hotplug_slot: slot to get status
 241  * @value: pointer to store status
 242  *
 243  * ACPI doesn't provide any formal means to access adapter status.
 244  * Instead, we fake adapter status from _STA.
 245  */
 246 static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
 247 {
 248         struct slot *slot = to_slot(hotplug_slot);
 249 
 250         pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
 251 
 252         *value = acpiphp_get_adapter_status(slot->acpi_slot);
 253 
 254         return 0;
 255 }
 256 
 257 /* callback routine to initialize 'struct slot' for each slot */
 258 int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot,
 259                                   unsigned int sun)
 260 {
 261         struct slot *slot;
 262         int retval = -ENOMEM;
 263         char name[SLOT_NAME_SIZE];
 264 
 265         slot = kzalloc(sizeof(*slot), GFP_KERNEL);
 266         if (!slot)
 267                 goto error;
 268 
 269         slot->hotplug_slot.ops = &acpi_hotplug_slot_ops;
 270 
 271         slot->acpi_slot = acpiphp_slot;
 272 
 273         acpiphp_slot->slot = slot;
 274         slot->sun = sun;
 275         snprintf(name, SLOT_NAME_SIZE, "%u", sun);
 276 
 277         retval = pci_hp_register(&slot->hotplug_slot, acpiphp_slot->bus,
 278                                  acpiphp_slot->device, name);
 279         if (retval == -EBUSY)
 280                 goto error_slot;
 281         if (retval) {
 282                 pr_err("pci_hp_register failed with error %d\n", retval);
 283                 goto error_slot;
 284         }
 285 
 286         pr_info("Slot [%s] registered\n", slot_name(slot));
 287 
 288         return 0;
 289 error_slot:
 290         kfree(slot);
 291 error:
 292         return retval;
 293 }
 294 
 295 
 296 void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
 297 {
 298         struct slot *slot = acpiphp_slot->slot;
 299 
 300         pr_info("Slot [%s] unregistered\n", slot_name(slot));
 301 
 302         pci_hp_deregister(&slot->hotplug_slot);
 303         kfree(slot);
 304 }
 305 
 306 
 307 void __init acpiphp_init(void)
 308 {
 309         pr_info(DRIVER_DESC " version: " DRIVER_VERSION "%s\n",
 310                 acpiphp_disabled ? ", disabled by user; please report a bug"
 311                                  : "");
 312 }

/* [<][>][^][v][top][bottom][index][help] */