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

rpaphp_core.c (12843B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform.
      4 * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
      5 *
      6 * All rights reserved.
      7 *
      8 * Send feedback to <lxie@us.ibm.com>
      9 *
     10 */
     11#include <linux/kernel.h>
     12#include <linux/module.h>
     13#include <linux/moduleparam.h>
     14#include <linux/of.h>
     15#include <linux/pci.h>
     16#include <linux/pci_hotplug.h>
     17#include <linux/smp.h>
     18#include <linux/init.h>
     19#include <linux/vmalloc.h>
     20#include <asm/firmware.h>
     21#include <asm/eeh.h>       /* for eeh_add_device() */
     22#include <asm/rtas.h>		/* rtas_call */
     23#include <asm/pci-bridge.h>	/* for pci_controller */
     24#include <asm/prom.h>
     25#include "../pci.h"		/* for pci_add_new_bus */
     26				/* and pci_do_scan_bus */
     27#include "rpaphp.h"
     28
     29bool rpaphp_debug;
     30LIST_HEAD(rpaphp_slot_head);
     31EXPORT_SYMBOL_GPL(rpaphp_slot_head);
     32
     33#define DRIVER_VERSION	"0.1"
     34#define DRIVER_AUTHOR	"Linda Xie <lxie@us.ibm.com>"
     35#define DRIVER_DESC	"RPA HOT Plug PCI Controller Driver"
     36
     37#define MAX_LOC_CODE 128
     38
     39MODULE_AUTHOR(DRIVER_AUTHOR);
     40MODULE_DESCRIPTION(DRIVER_DESC);
     41MODULE_LICENSE("GPL");
     42
     43module_param_named(debug, rpaphp_debug, bool, 0644);
     44
     45/**
     46 * set_attention_status - set attention LED
     47 * @hotplug_slot: target &hotplug_slot
     48 * @value: LED control value
     49 *
     50 * echo 0 > attention -- set LED OFF
     51 * echo 1 > attention -- set LED ON
     52 * echo 2 > attention -- set LED ID(identify, light is blinking)
     53 */
     54static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value)
     55{
     56	int rc;
     57	struct slot *slot = to_slot(hotplug_slot);
     58
     59	switch (value) {
     60	case 0:
     61	case 1:
     62	case 2:
     63		break;
     64	default:
     65		value = 1;
     66		break;
     67	}
     68
     69	rc = rtas_set_indicator(DR_INDICATOR, slot->index, value);
     70	if (!rc)
     71		slot->attention_status = value;
     72
     73	return rc;
     74}
     75
     76/**
     77 * get_power_status - get power status of a slot
     78 * @hotplug_slot: slot to get status
     79 * @value: pointer to store status
     80 */
     81static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
     82{
     83	int retval, level;
     84	struct slot *slot = to_slot(hotplug_slot);
     85
     86	retval = rtas_get_power_level(slot->power_domain, &level);
     87	if (!retval)
     88		*value = level;
     89	return retval;
     90}
     91
     92/**
     93 * get_attention_status - get attention LED status
     94 * @hotplug_slot: slot to get status
     95 * @value: pointer to store status
     96 */
     97static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
     98{
     99	struct slot *slot = to_slot(hotplug_slot);
    100	*value = slot->attention_status;
    101	return 0;
    102}
    103
    104static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
    105{
    106	struct slot *slot = to_slot(hotplug_slot);
    107	int rc, state;
    108
    109	rc = rpaphp_get_sensor_state(slot, &state);
    110
    111	*value = NOT_VALID;
    112	if (rc)
    113		return rc;
    114
    115	if (state == EMPTY)
    116		*value = EMPTY;
    117	else if (state == PRESENT)
    118		*value = slot->state;
    119
    120	return 0;
    121}
    122
    123static enum pci_bus_speed get_max_bus_speed(struct slot *slot)
    124{
    125	enum pci_bus_speed speed;
    126	switch (slot->type) {
    127	case 1:
    128	case 2:
    129	case 3:
    130	case 4:
    131	case 5:
    132	case 6:
    133		speed = PCI_SPEED_33MHz;	/* speed for case 1-6 */
    134		break;
    135	case 7:
    136	case 8:
    137		speed = PCI_SPEED_66MHz;
    138		break;
    139	case 11:
    140	case 14:
    141		speed = PCI_SPEED_66MHz_PCIX;
    142		break;
    143	case 12:
    144	case 15:
    145		speed = PCI_SPEED_100MHz_PCIX;
    146		break;
    147	case 13:
    148	case 16:
    149		speed = PCI_SPEED_133MHz_PCIX;
    150		break;
    151	default:
    152		speed = PCI_SPEED_UNKNOWN;
    153		break;
    154	}
    155
    156	return speed;
    157}
    158
    159static int get_children_props(struct device_node *dn, const __be32 **drc_indexes,
    160			      const __be32 **drc_names, const __be32 **drc_types,
    161			      const __be32 **drc_power_domains)
    162{
    163	const __be32 *indexes, *names, *types, *domains;
    164
    165	indexes = of_get_property(dn, "ibm,drc-indexes", NULL);
    166	names = of_get_property(dn, "ibm,drc-names", NULL);
    167	types = of_get_property(dn, "ibm,drc-types", NULL);
    168	domains = of_get_property(dn, "ibm,drc-power-domains", NULL);
    169
    170	if (!indexes || !names || !types || !domains) {
    171		/* Slot does not have dynamically-removable children */
    172		return -EINVAL;
    173	}
    174	if (drc_indexes)
    175		*drc_indexes = indexes;
    176	if (drc_names)
    177		/* &drc_names[1] contains NULL terminated slot names */
    178		*drc_names = names;
    179	if (drc_types)
    180		/* &drc_types[1] contains NULL terminated slot types */
    181		*drc_types = types;
    182	if (drc_power_domains)
    183		*drc_power_domains = domains;
    184
    185	return 0;
    186}
    187
    188
    189/* Verify the existence of 'drc_name' and/or 'drc_type' within the
    190 * current node.  First obtain its my-drc-index property.  Next,
    191 * obtain the DRC info from its parent.  Use the my-drc-index for
    192 * correlation, and obtain/validate the requested properties.
    193 */
    194
    195static int rpaphp_check_drc_props_v1(struct device_node *dn, char *drc_name,
    196				char *drc_type, unsigned int my_index)
    197{
    198	char *name_tmp, *type_tmp;
    199	const __be32 *indexes, *names;
    200	const __be32 *types, *domains;
    201	int i, rc;
    202
    203	rc = get_children_props(dn->parent, &indexes, &names, &types, &domains);
    204	if (rc < 0) {
    205		return -EINVAL;
    206	}
    207
    208	name_tmp = (char *) &names[1];
    209	type_tmp = (char *) &types[1];
    210
    211	/* Iterate through parent properties, looking for my-drc-index */
    212	for (i = 0; i < be32_to_cpu(indexes[0]); i++) {
    213		if (be32_to_cpu(indexes[i + 1]) == my_index)
    214			break;
    215
    216		name_tmp += (strlen(name_tmp) + 1);
    217		type_tmp += (strlen(type_tmp) + 1);
    218	}
    219
    220	if (((drc_name == NULL) || (drc_name && !strcmp(drc_name, name_tmp))) &&
    221	    ((drc_type == NULL) || (drc_type && !strcmp(drc_type, type_tmp))))
    222		return 0;
    223
    224	return -EINVAL;
    225}
    226
    227static int rpaphp_check_drc_props_v2(struct device_node *dn, char *drc_name,
    228				char *drc_type, unsigned int my_index)
    229{
    230	struct property *info;
    231	unsigned int entries;
    232	struct of_drc_info drc;
    233	const __be32 *value;
    234	char cell_drc_name[MAX_DRC_NAME_LEN];
    235	int j;
    236
    237	info = of_find_property(dn->parent, "ibm,drc-info", NULL);
    238	if (info == NULL)
    239		return -EINVAL;
    240
    241	value = of_prop_next_u32(info, NULL, &entries);
    242	if (!value)
    243		return -EINVAL;
    244	else
    245		value++;
    246
    247	for (j = 0; j < entries; j++) {
    248		of_read_drc_info_cell(&info, &value, &drc);
    249
    250		/* Should now know end of current entry */
    251
    252		/* Found it */
    253		if (my_index >= drc.drc_index_start && my_index <= drc.last_drc_index) {
    254			int index = my_index - drc.drc_index_start;
    255			sprintf(cell_drc_name, "%s%d", drc.drc_name_prefix,
    256				drc.drc_name_suffix_start + index);
    257			break;
    258		}
    259	}
    260
    261	if (((drc_name == NULL) ||
    262	     (drc_name && !strcmp(drc_name, cell_drc_name))) &&
    263	    ((drc_type == NULL) ||
    264	     (drc_type && !strcmp(drc_type, drc.drc_type))))
    265		return 0;
    266
    267	return -EINVAL;
    268}
    269
    270int rpaphp_check_drc_props(struct device_node *dn, char *drc_name,
    271			char *drc_type)
    272{
    273	const __be32 *my_index;
    274
    275	my_index = of_get_property(dn, "ibm,my-drc-index", NULL);
    276	if (!my_index) {
    277		/* Node isn't DLPAR/hotplug capable */
    278		return -EINVAL;
    279	}
    280
    281	if (of_find_property(dn->parent, "ibm,drc-info", NULL))
    282		return rpaphp_check_drc_props_v2(dn, drc_name, drc_type,
    283						be32_to_cpu(*my_index));
    284	else
    285		return rpaphp_check_drc_props_v1(dn, drc_name, drc_type,
    286						be32_to_cpu(*my_index));
    287}
    288EXPORT_SYMBOL_GPL(rpaphp_check_drc_props);
    289
    290
    291static int is_php_type(char *drc_type)
    292{
    293	char *endptr;
    294
    295	/* PCI Hotplug nodes have an integer for drc_type */
    296	simple_strtoul(drc_type, &endptr, 10);
    297	if (endptr == drc_type)
    298		return 0;
    299
    300	return 1;
    301}
    302
    303/**
    304 * is_php_dn() - return 1 if this is a hotpluggable pci slot, else 0
    305 * @dn: target &device_node
    306 * @indexes: passed to get_children_props()
    307 * @names: passed to get_children_props()
    308 * @types: returned from get_children_props()
    309 * @power_domains:
    310 *
    311 * This routine will return true only if the device node is
    312 * a hotpluggable slot. This routine will return false
    313 * for built-in pci slots (even when the built-in slots are
    314 * dlparable.)
    315 */
    316static int is_php_dn(struct device_node *dn, const __be32 **indexes,
    317		     const __be32 **names, const __be32 **types,
    318		     const __be32 **power_domains)
    319{
    320	const __be32 *drc_types;
    321	int rc;
    322
    323	rc = get_children_props(dn, indexes, names, &drc_types, power_domains);
    324	if (rc < 0)
    325		return 0;
    326
    327	if (!is_php_type((char *) &drc_types[1]))
    328		return 0;
    329
    330	*types = drc_types;
    331	return 1;
    332}
    333
    334static int rpaphp_drc_info_add_slot(struct device_node *dn)
    335{
    336	struct slot *slot;
    337	struct property *info;
    338	struct of_drc_info drc;
    339	char drc_name[MAX_DRC_NAME_LEN];
    340	const __be32 *cur;
    341	u32 count;
    342	int retval = 0;
    343
    344	info = of_find_property(dn, "ibm,drc-info", NULL);
    345	if (!info)
    346		return 0;
    347
    348	cur = of_prop_next_u32(info, NULL, &count);
    349	if (cur)
    350		cur++;
    351	else
    352		return 0;
    353
    354	of_read_drc_info_cell(&info, &cur, &drc);
    355	if (!is_php_type(drc.drc_type))
    356		return 0;
    357
    358	sprintf(drc_name, "%s%d", drc.drc_name_prefix, drc.drc_name_suffix_start);
    359
    360	slot = alloc_slot_struct(dn, drc.drc_index_start, drc_name, drc.drc_power_domain);
    361	if (!slot)
    362		return -ENOMEM;
    363
    364	slot->type = simple_strtoul(drc.drc_type, NULL, 10);
    365	retval = rpaphp_enable_slot(slot);
    366	if (!retval)
    367		retval = rpaphp_register_slot(slot);
    368
    369	if (retval)
    370		dealloc_slot_struct(slot);
    371
    372	return retval;
    373}
    374
    375static int rpaphp_drc_add_slot(struct device_node *dn)
    376{
    377	struct slot *slot;
    378	int retval = 0;
    379	int i;
    380	const __be32 *indexes, *names, *types, *power_domains;
    381	char *name, *type;
    382
    383	/* If this is not a hotplug slot, return without doing anything. */
    384	if (!is_php_dn(dn, &indexes, &names, &types, &power_domains))
    385		return 0;
    386
    387	dbg("Entry %s: dn=%pOF\n", __func__, dn);
    388
    389	/* register PCI devices */
    390	name = (char *) &names[1];
    391	type = (char *) &types[1];
    392	for (i = 0; i < be32_to_cpu(indexes[0]); i++) {
    393		int index;
    394
    395		index = be32_to_cpu(indexes[i + 1]);
    396		slot = alloc_slot_struct(dn, index, name,
    397					 be32_to_cpu(power_domains[i + 1]));
    398		if (!slot)
    399			return -ENOMEM;
    400
    401		slot->type = simple_strtoul(type, NULL, 10);
    402
    403		dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n",
    404				index, name, type);
    405
    406		retval = rpaphp_enable_slot(slot);
    407		if (!retval)
    408			retval = rpaphp_register_slot(slot);
    409
    410		if (retval)
    411			dealloc_slot_struct(slot);
    412
    413		name += strlen(name) + 1;
    414		type += strlen(type) + 1;
    415	}
    416	dbg("%s - Exit: rc[%d]\n", __func__, retval);
    417
    418	/* XXX FIXME: reports a failure only if last entry in loop failed */
    419	return retval;
    420}
    421
    422/**
    423 * rpaphp_add_slot -- declare a hotplug slot to the hotplug subsystem.
    424 * @dn: device node of slot
    425 *
    426 * This subroutine will register a hotpluggable slot with the
    427 * PCI hotplug infrastructure. This routine is typically called
    428 * during boot time, if the hotplug slots are present at boot time,
    429 * or is called later, by the dlpar add code, if the slot is
    430 * being dynamically added during runtime.
    431 *
    432 * If the device node points at an embedded (built-in) slot, this
    433 * routine will just return without doing anything, since embedded
    434 * slots cannot be hotplugged.
    435 *
    436 * To remove a slot, it suffices to call rpaphp_deregister_slot().
    437 */
    438int rpaphp_add_slot(struct device_node *dn)
    439{
    440	if (!of_node_name_eq(dn, "pci"))
    441		return 0;
    442
    443	if (of_find_property(dn, "ibm,drc-info", NULL))
    444		return rpaphp_drc_info_add_slot(dn);
    445	else
    446		return rpaphp_drc_add_slot(dn);
    447}
    448EXPORT_SYMBOL_GPL(rpaphp_add_slot);
    449
    450static void __exit cleanup_slots(void)
    451{
    452	struct slot *slot, *next;
    453
    454	/*
    455	 * Unregister all of our slots with the pci_hotplug subsystem,
    456	 * and free up all memory that we had allocated.
    457	 */
    458
    459	list_for_each_entry_safe(slot, next, &rpaphp_slot_head,
    460				 rpaphp_slot_list) {
    461		list_del(&slot->rpaphp_slot_list);
    462		pci_hp_deregister(&slot->hotplug_slot);
    463		dealloc_slot_struct(slot);
    464	}
    465}
    466
    467static int __init rpaphp_init(void)
    468{
    469	struct device_node *dn;
    470
    471	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
    472
    473	for_each_node_by_name(dn, "pci")
    474		rpaphp_add_slot(dn);
    475
    476	return 0;
    477}
    478
    479static void __exit rpaphp_exit(void)
    480{
    481	cleanup_slots();
    482}
    483
    484static int enable_slot(struct hotplug_slot *hotplug_slot)
    485{
    486	struct slot *slot = to_slot(hotplug_slot);
    487	int state;
    488	int retval;
    489
    490	if (slot->state == CONFIGURED)
    491		return 0;
    492
    493	retval = rpaphp_get_sensor_state(slot, &state);
    494	if (retval)
    495		return retval;
    496
    497	if (state == PRESENT) {
    498		pseries_eeh_init_edev_recursive(PCI_DN(slot->dn));
    499
    500		pci_lock_rescan_remove();
    501		pci_hp_add_devices(slot->bus);
    502		pci_unlock_rescan_remove();
    503		slot->state = CONFIGURED;
    504	} else if (state == EMPTY) {
    505		slot->state = EMPTY;
    506	} else {
    507		err("%s: slot[%s] is in invalid state\n", __func__, slot->name);
    508		slot->state = NOT_VALID;
    509		return -EINVAL;
    510	}
    511
    512	slot->bus->max_bus_speed = get_max_bus_speed(slot);
    513	return 0;
    514}
    515
    516static int disable_slot(struct hotplug_slot *hotplug_slot)
    517{
    518	struct slot *slot = to_slot(hotplug_slot);
    519	if (slot->state == NOT_CONFIGURED)
    520		return -EINVAL;
    521
    522	pci_lock_rescan_remove();
    523	pci_hp_remove_devices(slot->bus);
    524	pci_unlock_rescan_remove();
    525	vm_unmap_aliases();
    526
    527	slot->state = NOT_CONFIGURED;
    528	return 0;
    529}
    530
    531const struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
    532	.enable_slot = enable_slot,
    533	.disable_slot = disable_slot,
    534	.set_attention_status = set_attention_status,
    535	.get_power_status = get_power_status,
    536	.get_attention_status = get_attention_status,
    537	.get_adapter_status = get_adapter_status,
    538};
    539
    540module_init(rpaphp_init);
    541module_exit(rpaphp_exit);