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