0001
0002
0003
0004
0005
0006
0007
0008
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
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
0047
0048
0049
0050
0051
0052
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
0078
0079
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
0094
0095
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;
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
0172 return -EINVAL;
0173 }
0174 if (drc_indexes)
0175 *drc_indexes = indexes;
0176 if (drc_names)
0177
0178 *drc_names = names;
0179 if (drc_types)
0180
0181 *drc_types = types;
0182 if (drc_power_domains)
0183 *drc_power_domains = domains;
0184
0185 return 0;
0186 }
0187
0188
0189
0190
0191
0192
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
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
0251
0252
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
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
0296 simple_strtoul(drc_type, &endptr, 10);
0297 if (endptr == drc_type)
0298 return 0;
0299
0300 return 1;
0301 }
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
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
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
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
0419 return retval;
0420 }
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
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
0456
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);