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 structure to indicate if there is a pci card 58 * plugged into the slot. If the slot is not empty, run the pcibios routine 59 * to get pcibios stuff correctly set up. 60 */ 61 int rpaphp_enable_slot(struct slot *slot) 62 { 63 int rc, level, state; 64 struct pci_bus *bus; 65 66 slot->state = EMPTY; 67 68 /* Find out if the power is turned on for the slot */ 69 rc = rtas_get_power_level(slot->power_domain, &level); 70 if (rc) 71 return rc; 72 73 /* Figure out if there is an adapter in the slot */ 74 rc = rpaphp_get_sensor_state(slot, &state); 75 if (rc) 76 return rc; 77 78 bus = pci_find_bus_by_node(slot->dn); 79 if (!bus) { 80 err("%s: no pci_bus for dn %pOF\n", __func__, slot->dn); 81 return -EINVAL; 82 } 83 84 slot->bus = bus; 85 slot->pci_devs = &bus->devices; 86 87 /* if there's an adapter in the slot, go add the pci devices */ 88 if (state == PRESENT) { 89 slot->state = NOT_CONFIGURED; 90 91 /* non-empty slot has to have child */ 92 if (!slot->dn->child) { 93 err("%s: slot[%s]'s device_node doesn't have child for adapter\n", 94 __func__, slot->name); 95 return -EINVAL; 96 } 97 98 if (list_empty(&bus->devices)) { 99 pseries_eeh_init_edev_recursive(PCI_DN(slot->dn)); 100 pci_hp_add_devices(bus); 101 } 102 103 if (!list_empty(&bus->devices)) { 104 slot->state = CONFIGURED; 105 } 106 107 if (rpaphp_debug) { 108 struct pci_dev *dev; 109 dbg("%s: pci_devs of slot[%pOF]\n", __func__, slot->dn); 110 list_for_each_entry(dev, &bus->devices, bus_list) 111 dbg("\t%s\n", pci_name(dev)); 112 } 113 } 114 115 return 0; 116 } 117