LCOV - code coverage report
Current view: top level - drivers/pci/hotplug - acpiphp_core.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 19 83 22.9 %
Date: 2022-03-28 13:20:08 Functions: 2 12 16.7 %
Branches: 4 30 13.3 %

           Branch data     Line data    Source code
       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                 :          0 : int acpiphp_register_attention(struct acpiphp_attention_info *info)
      79                 :            : {
      80                 :          0 :         int retval = -EINVAL;
      81                 :            : 
      82   [ #  #  #  #  :          0 :         if (info && info->owner && info->set_attn &&
                   #  # ]
      83   [ #  #  #  # ]:          0 :                         info->get_attn && !attention_info) {
      84                 :          0 :                 retval = 0;
      85                 :          0 :                 attention_info = info;
      86                 :            :         }
      87                 :          0 :         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                 :          0 : int acpiphp_unregister_attention(struct acpiphp_attention_info *info)
     101                 :            : {
     102                 :          0 :         int retval = -EINVAL;
     103                 :            : 
     104   [ #  #  #  # ]:          0 :         if (info && attention_info == info) {
     105                 :          0 :                 attention_info = NULL;
     106                 :          0 :                 retval = 0;
     107                 :            :         }
     108                 :          0 :         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                 :          0 : static int enable_slot(struct hotplug_slot *hotplug_slot)
     120                 :            : {
     121                 :          0 :         struct slot *slot = to_slot(hotplug_slot);
     122                 :            : 
     123                 :          0 :         pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
     124                 :            : 
     125                 :            :         /* enable the specified slot */
     126                 :          0 :         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                 :          0 : static int disable_slot(struct hotplug_slot *hotplug_slot)
     137                 :            : {
     138                 :          0 :         struct slot *slot = to_slot(hotplug_slot);
     139                 :            : 
     140                 :          0 :         pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
     141                 :            : 
     142                 :            :         /* disable the specified slot */
     143                 :          0 :         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                 :          0 : static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
     157                 :            : {
     158                 :          0 :         int retval = -ENODEV;
     159                 :            : 
     160                 :          0 :         pr_debug("%s - physical_slot = %s\n", __func__,
     161                 :            :                 hotplug_slot_name(hotplug_slot));
     162                 :            : 
     163   [ #  #  #  # ]:          0 :         if (attention_info && try_module_get(attention_info->owner)) {
     164                 :          0 :                 retval = attention_info->set_attn(hotplug_slot, status);
     165                 :          0 :                 module_put(attention_info->owner);
     166                 :            :         } else
     167                 :          0 :                 attention_info = NULL;
     168                 :          0 :         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                 :          0 : static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
     181                 :            : {
     182                 :          0 :         struct slot *slot = to_slot(hotplug_slot);
     183                 :            : 
     184                 :          0 :         pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
     185                 :            : 
     186                 :          0 :         *value = acpiphp_get_power_status(slot->acpi_slot);
     187                 :            : 
     188                 :          0 :         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                 :          0 : static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
     203                 :            : {
     204                 :          0 :         int retval = -EINVAL;
     205                 :            : 
     206                 :          0 :         pr_debug("%s - physical_slot = %s\n", __func__,
     207                 :            :                 hotplug_slot_name(hotplug_slot));
     208                 :            : 
     209   [ #  #  #  # ]:          0 :         if (attention_info && try_module_get(attention_info->owner)) {
     210                 :          0 :                 retval = attention_info->get_attn(hotplug_slot, value);
     211                 :          0 :                 module_put(attention_info->owner);
     212                 :            :         } else
     213                 :          0 :                 attention_info = NULL;
     214                 :          0 :         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                 :          0 : static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
     227                 :            : {
     228                 :          0 :         struct slot *slot = to_slot(hotplug_slot);
     229                 :            : 
     230                 :          0 :         pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
     231                 :            : 
     232                 :          0 :         *value = acpiphp_get_latch_status(slot->acpi_slot);
     233                 :            : 
     234                 :          0 :         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                 :          0 : static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
     247                 :            : {
     248                 :          0 :         struct slot *slot = to_slot(hotplug_slot);
     249                 :            : 
     250                 :          0 :         pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
     251                 :            : 
     252                 :          0 :         *value = acpiphp_get_adapter_status(slot->acpi_slot);
     253                 :            : 
     254                 :          0 :         return 0;
     255                 :            : }
     256                 :            : 
     257                 :            : /* callback routine to initialize 'struct slot' for each slot */
     258                 :        870 : int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot,
     259                 :            :                                   unsigned int sun)
     260                 :            : {
     261                 :        870 :         struct slot *slot;
     262                 :        870 :         int retval = -ENOMEM;
     263                 :        870 :         char name[SLOT_NAME_SIZE];
     264                 :            : 
     265                 :        870 :         slot = kzalloc(sizeof(*slot), GFP_KERNEL);
     266         [ -  + ]:        870 :         if (!slot)
     267                 :          0 :                 goto error;
     268                 :            : 
     269                 :        870 :         slot->hotplug_slot.ops = &acpi_hotplug_slot_ops;
     270                 :            : 
     271                 :        870 :         slot->acpi_slot = acpiphp_slot;
     272                 :            : 
     273                 :        870 :         acpiphp_slot->slot = slot;
     274                 :        870 :         slot->sun = sun;
     275                 :        870 :         snprintf(name, SLOT_NAME_SIZE, "%u", sun);
     276                 :            : 
     277                 :        870 :         retval = pci_hp_register(&slot->hotplug_slot, acpiphp_slot->bus,
     278                 :            :                                  acpiphp_slot->device, name);
     279         [ -  + ]:        870 :         if (retval == -EBUSY)
     280                 :          0 :                 goto error_slot;
     281         [ -  + ]:        870 :         if (retval) {
     282                 :          0 :                 pr_err("pci_hp_register failed with error %d\n", retval);
     283                 :          0 :                 goto error_slot;
     284                 :            :         }
     285                 :            : 
     286                 :        870 :         pr_info("Slot [%s] registered\n", slot_name(slot));
     287                 :            : 
     288                 :        870 :         return 0;
     289                 :          0 : error_slot:
     290                 :          0 :         kfree(slot);
     291                 :            : error:
     292                 :            :         return retval;
     293                 :            : }
     294                 :            : 
     295                 :            : 
     296                 :          0 : void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
     297                 :            : {
     298                 :          0 :         struct slot *slot = acpiphp_slot->slot;
     299                 :            : 
     300                 :          0 :         pr_info("Slot [%s] unregistered\n", slot_name(slot));
     301                 :            : 
     302                 :          0 :         pci_hp_deregister(&slot->hotplug_slot);
     303                 :          0 :         kfree(slot);
     304                 :          0 : }
     305                 :            : 
     306                 :            : 
     307                 :         30 : void __init acpiphp_init(void)
     308                 :            : {
     309         [ +  - ]:         60 :         pr_info(DRIVER_DESC " version: " DRIVER_VERSION "%s\n",
     310                 :            :                 acpiphp_disabled ? ", disabled by user; please report a bug"
     311                 :            :                                  : "");
     312                 :         30 : }

Generated by: LCOV version 1.14