Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform.
0004  * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
0005  *
0006  * All rights reserved.
0007  *
0008  * Send feedback to <lxie@us.ibm.com>
0009  *
0010  */
0011 #include <linux/kernel.h>
0012 #include <linux/module.h>
0013 #include <linux/moduleparam.h>
0014 #include <linux/of.h>
0015 #include <linux/pci.h>
0016 #include <linux/pci_hotplug.h>
0017 #include <linux/smp.h>
0018 #include <linux/init.h>
0019 #include <linux/vmalloc.h>
0020 #include <asm/firmware.h>
0021 #include <asm/eeh.h>       /* for eeh_add_device() */
0022 #include <asm/rtas.h>       /* rtas_call */
0023 #include <asm/pci-bridge.h> /* for pci_controller */
0024 #include <asm/prom.h>
0025 #include "../pci.h"     /* for pci_add_new_bus */
0026                 /* and pci_do_scan_bus */
0027 #include "rpaphp.h"
0028 
0029 bool rpaphp_debug;
0030 LIST_HEAD(rpaphp_slot_head);
0031 EXPORT_SYMBOL_GPL(rpaphp_slot_head);
0032 
0033 #define DRIVER_VERSION  "0.1"
0034 #define DRIVER_AUTHOR   "Linda Xie <lxie@us.ibm.com>"
0035 #define DRIVER_DESC "RPA HOT Plug PCI Controller Driver"
0036 
0037 #define MAX_LOC_CODE 128
0038 
0039 MODULE_AUTHOR(DRIVER_AUTHOR);
0040 MODULE_DESCRIPTION(DRIVER_DESC);
0041 MODULE_LICENSE("GPL");
0042 
0043 module_param_named(debug, rpaphp_debug, bool, 0644);
0044 
0045 /**
0046  * set_attention_status - set attention LED
0047  * @hotplug_slot: target &hotplug_slot
0048  * @value: LED control value
0049  *
0050  * echo 0 > attention -- set LED OFF
0051  * echo 1 > attention -- set LED ON
0052  * echo 2 > attention -- set LED ID(identify, light is blinking)
0053  */
0054 static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value)
0055 {
0056     int rc;
0057     struct slot *slot = to_slot(hotplug_slot);
0058 
0059     switch (value) {
0060     case 0:
0061     case 1:
0062     case 2:
0063         break;
0064     default:
0065         value = 1;
0066         break;
0067     }
0068 
0069     rc = rtas_set_indicator(DR_INDICATOR, slot->index, value);
0070     if (!rc)
0071         slot->attention_status = value;
0072 
0073     return rc;
0074 }
0075 
0076 /**
0077  * get_power_status - get power status of a slot
0078  * @hotplug_slot: slot to get status
0079  * @value: pointer to store status
0080  */
0081 static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
0082 {
0083     int retval, level;
0084     struct slot *slot = to_slot(hotplug_slot);
0085 
0086     retval = rtas_get_power_level(slot->power_domain, &level);
0087     if (!retval)
0088         *value = level;
0089     return retval;
0090 }
0091 
0092 /**
0093  * get_attention_status - get attention LED status
0094  * @hotplug_slot: slot to get status
0095  * @value: pointer to store status
0096  */
0097 static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
0098 {
0099     struct slot *slot = to_slot(hotplug_slot);
0100     *value = slot->attention_status;
0101     return 0;
0102 }
0103 
0104 static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
0105 {
0106     struct slot *slot = to_slot(hotplug_slot);
0107     int rc, state;
0108 
0109     rc = rpaphp_get_sensor_state(slot, &state);
0110 
0111     *value = NOT_VALID;
0112     if (rc)
0113         return rc;
0114 
0115     if (state == EMPTY)
0116         *value = EMPTY;
0117     else if (state == PRESENT)
0118         *value = slot->state;
0119 
0120     return 0;
0121 }
0122 
0123 static enum pci_bus_speed get_max_bus_speed(struct slot *slot)
0124 {
0125     enum pci_bus_speed speed;
0126     switch (slot->type) {
0127     case 1:
0128     case 2:
0129     case 3:
0130     case 4:
0131     case 5:
0132     case 6:
0133         speed = PCI_SPEED_33MHz;    /* speed for case 1-6 */
0134         break;
0135     case 7:
0136     case 8:
0137         speed = PCI_SPEED_66MHz;
0138         break;
0139     case 11:
0140     case 14:
0141         speed = PCI_SPEED_66MHz_PCIX;
0142         break;
0143     case 12:
0144     case 15:
0145         speed = PCI_SPEED_100MHz_PCIX;
0146         break;
0147     case 13:
0148     case 16:
0149         speed = PCI_SPEED_133MHz_PCIX;
0150         break;
0151     default:
0152         speed = PCI_SPEED_UNKNOWN;
0153         break;
0154     }
0155 
0156     return speed;
0157 }
0158 
0159 static int get_children_props(struct device_node *dn, const __be32 **drc_indexes,
0160                   const __be32 **drc_names, const __be32 **drc_types,
0161                   const __be32 **drc_power_domains)
0162 {
0163     const __be32 *indexes, *names, *types, *domains;
0164 
0165     indexes = of_get_property(dn, "ibm,drc-indexes", NULL);
0166     names = of_get_property(dn, "ibm,drc-names", NULL);
0167     types = of_get_property(dn, "ibm,drc-types", NULL);
0168     domains = of_get_property(dn, "ibm,drc-power-domains", NULL);
0169 
0170     if (!indexes || !names || !types || !domains) {
0171         /* Slot does not have dynamically-removable children */
0172         return -EINVAL;
0173     }
0174     if (drc_indexes)
0175         *drc_indexes = indexes;
0176     if (drc_names)
0177         /* &drc_names[1] contains NULL terminated slot names */
0178         *drc_names = names;
0179     if (drc_types)
0180         /* &drc_types[1] contains NULL terminated slot types */
0181         *drc_types = types;
0182     if (drc_power_domains)
0183         *drc_power_domains = domains;
0184 
0185     return 0;
0186 }
0187 
0188 
0189 /* Verify the existence of 'drc_name' and/or 'drc_type' within the
0190  * current node.  First obtain its my-drc-index property.  Next,
0191  * obtain the DRC info from its parent.  Use the my-drc-index for
0192  * correlation, and obtain/validate the requested properties.
0193  */
0194 
0195 static int rpaphp_check_drc_props_v1(struct device_node *dn, char *drc_name,
0196                 char *drc_type, unsigned int my_index)
0197 {
0198     char *name_tmp, *type_tmp;
0199     const __be32 *indexes, *names;
0200     const __be32 *types, *domains;
0201     int i, rc;
0202 
0203     rc = get_children_props(dn->parent, &indexes, &names, &types, &domains);
0204     if (rc < 0) {
0205         return -EINVAL;
0206     }
0207 
0208     name_tmp = (char *) &names[1];
0209     type_tmp = (char *) &types[1];
0210 
0211     /* Iterate through parent properties, looking for my-drc-index */
0212     for (i = 0; i < be32_to_cpu(indexes[0]); i++) {
0213         if (be32_to_cpu(indexes[i + 1]) == my_index)
0214             break;
0215 
0216         name_tmp += (strlen(name_tmp) + 1);
0217         type_tmp += (strlen(type_tmp) + 1);
0218     }
0219 
0220     if (((drc_name == NULL) || (drc_name && !strcmp(drc_name, name_tmp))) &&
0221         ((drc_type == NULL) || (drc_type && !strcmp(drc_type, type_tmp))))
0222         return 0;
0223 
0224     return -EINVAL;
0225 }
0226 
0227 static int rpaphp_check_drc_props_v2(struct device_node *dn, char *drc_name,
0228                 char *drc_type, unsigned int my_index)
0229 {
0230     struct property *info;
0231     unsigned int entries;
0232     struct of_drc_info drc;
0233     const __be32 *value;
0234     char cell_drc_name[MAX_DRC_NAME_LEN];
0235     int j;
0236 
0237     info = of_find_property(dn->parent, "ibm,drc-info", NULL);
0238     if (info == NULL)
0239         return -EINVAL;
0240 
0241     value = of_prop_next_u32(info, NULL, &entries);
0242     if (!value)
0243         return -EINVAL;
0244     else
0245         value++;
0246 
0247     for (j = 0; j < entries; j++) {
0248         of_read_drc_info_cell(&info, &value, &drc);
0249 
0250         /* Should now know end of current entry */
0251 
0252         /* Found it */
0253         if (my_index >= drc.drc_index_start && my_index <= drc.last_drc_index) {
0254             int index = my_index - drc.drc_index_start;
0255             sprintf(cell_drc_name, "%s%d", drc.drc_name_prefix,
0256                 drc.drc_name_suffix_start + index);
0257             break;
0258         }
0259     }
0260 
0261     if (((drc_name == NULL) ||
0262          (drc_name && !strcmp(drc_name, cell_drc_name))) &&
0263         ((drc_type == NULL) ||
0264          (drc_type && !strcmp(drc_type, drc.drc_type))))
0265         return 0;
0266 
0267     return -EINVAL;
0268 }
0269 
0270 int rpaphp_check_drc_props(struct device_node *dn, char *drc_name,
0271             char *drc_type)
0272 {
0273     const __be32 *my_index;
0274 
0275     my_index = of_get_property(dn, "ibm,my-drc-index", NULL);
0276     if (!my_index) {
0277         /* Node isn't DLPAR/hotplug capable */
0278         return -EINVAL;
0279     }
0280 
0281     if (of_find_property(dn->parent, "ibm,drc-info", NULL))
0282         return rpaphp_check_drc_props_v2(dn, drc_name, drc_type,
0283                         be32_to_cpu(*my_index));
0284     else
0285         return rpaphp_check_drc_props_v1(dn, drc_name, drc_type,
0286                         be32_to_cpu(*my_index));
0287 }
0288 EXPORT_SYMBOL_GPL(rpaphp_check_drc_props);
0289 
0290 
0291 static int is_php_type(char *drc_type)
0292 {
0293     char *endptr;
0294 
0295     /* PCI Hotplug nodes have an integer for drc_type */
0296     simple_strtoul(drc_type, &endptr, 10);
0297     if (endptr == drc_type)
0298         return 0;
0299 
0300     return 1;
0301 }
0302 
0303 /**
0304  * is_php_dn() - return 1 if this is a hotpluggable pci slot, else 0
0305  * @dn: target &device_node
0306  * @indexes: passed to get_children_props()
0307  * @names: passed to get_children_props()
0308  * @types: returned from get_children_props()
0309  * @power_domains:
0310  *
0311  * This routine will return true only if the device node is
0312  * a hotpluggable slot. This routine will return false
0313  * for built-in pci slots (even when the built-in slots are
0314  * dlparable.)
0315  */
0316 static int is_php_dn(struct device_node *dn, const __be32 **indexes,
0317              const __be32 **names, const __be32 **types,
0318              const __be32 **power_domains)
0319 {
0320     const __be32 *drc_types;
0321     int rc;
0322 
0323     rc = get_children_props(dn, indexes, names, &drc_types, power_domains);
0324     if (rc < 0)
0325         return 0;
0326 
0327     if (!is_php_type((char *) &drc_types[1]))
0328         return 0;
0329 
0330     *types = drc_types;
0331     return 1;
0332 }
0333 
0334 static int rpaphp_drc_info_add_slot(struct device_node *dn)
0335 {
0336     struct slot *slot;
0337     struct property *info;
0338     struct of_drc_info drc;
0339     char drc_name[MAX_DRC_NAME_LEN];
0340     const __be32 *cur;
0341     u32 count;
0342     int retval = 0;
0343 
0344     info = of_find_property(dn, "ibm,drc-info", NULL);
0345     if (!info)
0346         return 0;
0347 
0348     cur = of_prop_next_u32(info, NULL, &count);
0349     if (cur)
0350         cur++;
0351     else
0352         return 0;
0353 
0354     of_read_drc_info_cell(&info, &cur, &drc);
0355     if (!is_php_type(drc.drc_type))
0356         return 0;
0357 
0358     sprintf(drc_name, "%s%d", drc.drc_name_prefix, drc.drc_name_suffix_start);
0359 
0360     slot = alloc_slot_struct(dn, drc.drc_index_start, drc_name, drc.drc_power_domain);
0361     if (!slot)
0362         return -ENOMEM;
0363 
0364     slot->type = simple_strtoul(drc.drc_type, NULL, 10);
0365     retval = rpaphp_enable_slot(slot);
0366     if (!retval)
0367         retval = rpaphp_register_slot(slot);
0368 
0369     if (retval)
0370         dealloc_slot_struct(slot);
0371 
0372     return retval;
0373 }
0374 
0375 static int rpaphp_drc_add_slot(struct device_node *dn)
0376 {
0377     struct slot *slot;
0378     int retval = 0;
0379     int i;
0380     const __be32 *indexes, *names, *types, *power_domains;
0381     char *name, *type;
0382 
0383     /* If this is not a hotplug slot, return without doing anything. */
0384     if (!is_php_dn(dn, &indexes, &names, &types, &power_domains))
0385         return 0;
0386 
0387     dbg("Entry %s: dn=%pOF\n", __func__, dn);
0388 
0389     /* register PCI devices */
0390     name = (char *) &names[1];
0391     type = (char *) &types[1];
0392     for (i = 0; i < be32_to_cpu(indexes[0]); i++) {
0393         int index;
0394 
0395         index = be32_to_cpu(indexes[i + 1]);
0396         slot = alloc_slot_struct(dn, index, name,
0397                      be32_to_cpu(power_domains[i + 1]));
0398         if (!slot)
0399             return -ENOMEM;
0400 
0401         slot->type = simple_strtoul(type, NULL, 10);
0402 
0403         dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n",
0404                 index, name, type);
0405 
0406         retval = rpaphp_enable_slot(slot);
0407         if (!retval)
0408             retval = rpaphp_register_slot(slot);
0409 
0410         if (retval)
0411             dealloc_slot_struct(slot);
0412 
0413         name += strlen(name) + 1;
0414         type += strlen(type) + 1;
0415     }
0416     dbg("%s - Exit: rc[%d]\n", __func__, retval);
0417 
0418     /* XXX FIXME: reports a failure only if last entry in loop failed */
0419     return retval;
0420 }
0421 
0422 /**
0423  * rpaphp_add_slot -- declare a hotplug slot to the hotplug subsystem.
0424  * @dn: device node of slot
0425  *
0426  * This subroutine will register a hotpluggable slot with the
0427  * PCI hotplug infrastructure. This routine is typically called
0428  * during boot time, if the hotplug slots are present at boot time,
0429  * or is called later, by the dlpar add code, if the slot is
0430  * being dynamically added during runtime.
0431  *
0432  * If the device node points at an embedded (built-in) slot, this
0433  * routine will just return without doing anything, since embedded
0434  * slots cannot be hotplugged.
0435  *
0436  * To remove a slot, it suffices to call rpaphp_deregister_slot().
0437  */
0438 int rpaphp_add_slot(struct device_node *dn)
0439 {
0440     if (!of_node_name_eq(dn, "pci"))
0441         return 0;
0442 
0443     if (of_find_property(dn, "ibm,drc-info", NULL))
0444         return rpaphp_drc_info_add_slot(dn);
0445     else
0446         return rpaphp_drc_add_slot(dn);
0447 }
0448 EXPORT_SYMBOL_GPL(rpaphp_add_slot);
0449 
0450 static void __exit cleanup_slots(void)
0451 {
0452     struct slot *slot, *next;
0453 
0454     /*
0455      * Unregister all of our slots with the pci_hotplug subsystem,
0456      * and free up all memory that we had allocated.
0457      */
0458 
0459     list_for_each_entry_safe(slot, next, &rpaphp_slot_head,
0460                  rpaphp_slot_list) {
0461         list_del(&slot->rpaphp_slot_list);
0462         pci_hp_deregister(&slot->hotplug_slot);
0463         dealloc_slot_struct(slot);
0464     }
0465 }
0466 
0467 static int __init rpaphp_init(void)
0468 {
0469     struct device_node *dn;
0470 
0471     info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
0472 
0473     for_each_node_by_name(dn, "pci")
0474         rpaphp_add_slot(dn);
0475 
0476     return 0;
0477 }
0478 
0479 static void __exit rpaphp_exit(void)
0480 {
0481     cleanup_slots();
0482 }
0483 
0484 static int enable_slot(struct hotplug_slot *hotplug_slot)
0485 {
0486     struct slot *slot = to_slot(hotplug_slot);
0487     int state;
0488     int retval;
0489 
0490     if (slot->state == CONFIGURED)
0491         return 0;
0492 
0493     retval = rpaphp_get_sensor_state(slot, &state);
0494     if (retval)
0495         return retval;
0496 
0497     if (state == PRESENT) {
0498         pseries_eeh_init_edev_recursive(PCI_DN(slot->dn));
0499 
0500         pci_lock_rescan_remove();
0501         pci_hp_add_devices(slot->bus);
0502         pci_unlock_rescan_remove();
0503         slot->state = CONFIGURED;
0504     } else if (state == EMPTY) {
0505         slot->state = EMPTY;
0506     } else {
0507         err("%s: slot[%s] is in invalid state\n", __func__, slot->name);
0508         slot->state = NOT_VALID;
0509         return -EINVAL;
0510     }
0511 
0512     slot->bus->max_bus_speed = get_max_bus_speed(slot);
0513     return 0;
0514 }
0515 
0516 static int disable_slot(struct hotplug_slot *hotplug_slot)
0517 {
0518     struct slot *slot = to_slot(hotplug_slot);
0519     if (slot->state == NOT_CONFIGURED)
0520         return -EINVAL;
0521 
0522     pci_lock_rescan_remove();
0523     pci_hp_remove_devices(slot->bus);
0524     pci_unlock_rescan_remove();
0525     vm_unmap_aliases();
0526 
0527     slot->state = NOT_CONFIGURED;
0528     return 0;
0529 }
0530 
0531 const struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
0532     .enable_slot = enable_slot,
0533     .disable_slot = disable_slot,
0534     .set_attention_status = set_attention_status,
0535     .get_power_status = get_power_status,
0536     .get_attention_status = get_attention_status,
0537     .get_adapter_status = get_adapter_status,
0538 };
0539 
0540 module_init(rpaphp_init);
0541 module_exit(rpaphp_exit);