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/pci.h> 12 #include <linux/string.h> 13 14 #include <asm/pci-bridge.h> 15 #include <asm/rtas.h> 16 #include <asm/machdep.h> 17 18 #include "../pci.h" /* for pci_add_new_bus */ 19 #include "rpaphp.h" 20 21 int rpaphp_get_sensor_state(struct slot *slot, int *state) 22 { 23 int rc; 24 int setlevel; 25 26 rc = rtas_get_sensor(DR_ENTITY_SENSE, slot->index, state); 27 28 if (rc < 0) { 29 if (rc == -EFAULT || rc == -EEXIST) { 30 dbg("%s: slot must be power up to get sensor-state\n", 31 __func__); 32 33 /* some slots have to be powered up 34 * before get-sensor will succeed. 35 */ 36 rc = rtas_set_power_level(slot->power_domain, POWER_ON, 37 &setlevel); 38 if (rc < 0) { 39 dbg("%s: power on slot[%s] failed rc=%d.\n", 40 __func__, slot->name, rc); 41 } else { 42 rc = rtas_get_sensor(DR_ENTITY_SENSE, 43 slot->index, state); 44 } 45 } else if (rc == -ENODEV) 46 info("%s: slot is unusable\n", __func__); 47 else 48 err("%s failed to get sensor state\n", __func__); 49 } 50 return rc; 51 } 52 53 /** 54 * rpaphp_enable_slot - record slot state, config pci device 55 * @slot: target &slot 56 * 57 * Initialize values in the slot, and the hotplug_slot info 58 * structures to indicate if there is a pci card plugged into 59 * the slot. If the slot is not empty, run the pcibios routine 60 * to get pcibios stuff correctly set up. 61 */ 62 int rpaphp_enable_slot(struct slot *slot) 63 { 64 int rc, level, state; 65 struct pci_bus *bus; 66 struct hotplug_slot_info *info = slot->hotplug_slot->info; 67 68 info->adapter_status = NOT_VALID; 69 slot->state = EMPTY; 70 71 /* Find out if the power is turned on for the slot */ 72 rc = rtas_get_power_level(slot->power_domain, &level); 73 if (rc) 74 return rc; 75 info->power_status = level; 76 77 /* Figure out if there is an adapter in the slot */ 78 rc = rpaphp_get_sensor_state(slot, &state); 79 if (rc) 80 return rc; 81 82 bus = pci_find_bus_by_node(slot->dn); 83 if (!bus) { 84 err("%s: no pci_bus for dn %pOF\n", __func__, slot->dn); 85 return -EINVAL; 86 } 87 88 info->adapter_status = EMPTY; 89 slot->bus = bus; 90 slot->pci_devs = &bus->devices; 91 92 /* if there's an adapter in the slot, go add the pci devices */ 93 if (state == PRESENT) { 94 info->adapter_status = NOT_CONFIGURED; 95 slot->state = NOT_CONFIGURED; 96 97 /* non-empty slot has to have child */ 98 if (!slot->dn->child) { 99 err("%s: slot[%s]'s device_node doesn't have child for adapter\n", 100 __func__, slot->name); 101 return -EINVAL; 102 } 103 104 if (list_empty(&bus->devices)) 105 pci_hp_add_devices(bus); 106 107 if (!list_empty(&bus->devices)) { 108 info->adapter_status = CONFIGURED; 109 slot->state = CONFIGURED; 110 } 111 112 if (rpaphp_debug) { 113 struct pci_dev *dev; 114 dbg("%s: pci_devs of slot[%pOF]\n", __func__, slot->dn); 115 list_for_each_entry(dev, &bus->devices, bus_list) 116 dbg("\t%s\n", pci_name(dev)); 117 } 118 } 119 120 return 0; 121 } 122