cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

acpiphp_core.c (8480B)


      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
     37bool acpiphp_disabled;
     38
     39/* local variables */
     40static 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
     46MODULE_AUTHOR(DRIVER_AUTHOR);
     47MODULE_DESCRIPTION(DRIVER_DESC);
     48MODULE_LICENSE("GPL");
     49MODULE_PARM_DESC(disable, "disable acpiphp driver");
     50module_param_named(disable, acpiphp_disabled, bool, 0444);
     51
     52static int enable_slot(struct hotplug_slot *slot);
     53static int disable_slot(struct hotplug_slot *slot);
     54static int set_attention_status(struct hotplug_slot *slot, u8 value);
     55static int get_power_status(struct hotplug_slot *slot, u8 *value);
     56static int get_attention_status(struct hotplug_slot *slot, u8 *value);
     57static int get_latch_status(struct hotplug_slot *slot, u8 *value);
     58static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
     59
     60static 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 */
     78int 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}
     89EXPORT_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 */
    100int 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}
    110EXPORT_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 */
    119static 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 */
    136static 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 */
    156static 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 */
    180static 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 */
    202static 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 */
    226static 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 */
    246static 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 */
    258int 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;
    289error_slot:
    290	kfree(slot);
    291error:
    292	return retval;
    293}
    294
    295
    296void 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
    307void __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}