rpaphp_pci.c revision 7fec77e4793f307b30846a3d4015d329ffc0b685
1/*
2 * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform.
3 * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
4 *
5 * All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or (at
10 * your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
15 * NON INFRINGEMENT.  See the GNU General Public License for more
16 * details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * Send feedback to <lxie@us.ibm.com>
23 *
24 */
25#include <linux/pci.h>
26#include <linux/string.h>
27
28#include <asm/pci-bridge.h>
29#include <asm/rtas.h>
30#include <asm/machdep.h>
31
32#include "../pci.h"		/* for pci_add_new_bus */
33#include "rpaphp.h"
34
35static int rpaphp_get_sensor_state(struct slot *slot, int *state)
36{
37	int rc;
38	int setlevel;
39
40	rc = rtas_get_sensor(DR_ENTITY_SENSE, slot->index, state);
41
42	if (rc < 0) {
43		if (rc == -EFAULT || rc == -EEXIST) {
44			dbg("%s: slot must be power up to get sensor-state\n",
45			    __FUNCTION__);
46
47			/* some slots have to be powered up
48			 * before get-sensor will succeed.
49			 */
50			rc = rtas_set_power_level(slot->power_domain, POWER_ON,
51						  &setlevel);
52			if (rc < 0) {
53				dbg("%s: power on slot[%s] failed rc=%d.\n",
54				    __FUNCTION__, slot->name, rc);
55			} else {
56				rc = rtas_get_sensor(DR_ENTITY_SENSE,
57						     slot->index, state);
58			}
59		} else if (rc == -ENODEV)
60			info("%s: slot is unusable\n", __FUNCTION__);
61		else
62			err("%s failed to get sensor state\n", __FUNCTION__);
63	}
64	return rc;
65}
66
67/**
68 * get_pci_adapter_status - get the status of a slot
69 *
70 * 0-- slot is empty
71 * 1-- adapter is configured
72 * 2-- adapter is not configured
73 * 3-- not valid
74 */
75int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value)
76{
77	struct pci_bus *bus;
78	int state, rc;
79
80	*value = NOT_VALID;
81	rc = rpaphp_get_sensor_state(slot, &state);
82	if (rc)
83		goto exit;
84
85 	if (state == EMPTY)
86 		*value = EMPTY;
87 	else if (state == PRESENT) {
88		if (!is_init) {
89			/* at run-time slot->state can be changed by */
90			/* config/unconfig adapter */
91			*value = slot->state;
92		} else {
93			bus = pcibios_find_pci_bus(slot->dn);
94			if (bus && !list_empty(&bus->devices))
95				*value = CONFIGURED;
96			else
97				*value = NOT_CONFIGURED;
98		}
99	}
100exit:
101	return rc;
102}
103
104static void print_slot_pci_funcs(struct pci_bus *bus)
105{
106	struct device_node *dn;
107	struct pci_dev *dev;
108
109	dn = pci_bus_to_OF_node(bus);
110	if (!dn)
111		return;
112
113	dbg("%s: pci_devs of slot[%s]\n", __FUNCTION__, dn->full_name);
114	list_for_each_entry (dev, &bus->devices, bus_list)
115		dbg("\t%s\n", pci_name(dev));
116	return;
117}
118
119static void rpaphp_eeh_remove_bus_device(struct pci_dev *dev)
120{
121	eeh_remove_device(dev);
122	if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
123		struct pci_bus *bus = dev->subordinate;
124		struct list_head *ln;
125		if (!bus)
126			return;
127		for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
128			struct pci_dev *pdev = pci_dev_b(ln);
129			if (pdev)
130				rpaphp_eeh_remove_bus_device(pdev);
131		}
132
133	}
134	return;
135}
136
137int rpaphp_unconfig_pci_adapter(struct pci_bus *bus)
138{
139	struct pci_dev *dev, *tmp;
140
141	list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
142		rpaphp_eeh_remove_bus_device(dev);
143		pci_remove_bus_device(dev);
144	}
145	return 0;
146}
147EXPORT_SYMBOL_GPL(rpaphp_unconfig_pci_adapter);
148
149static int setup_pci_hotplug_slot_info(struct slot *slot)
150{
151	struct hotplug_slot_info *hotplug_slot_info = slot->hotplug_slot->info;
152
153	dbg("%s Initilize the PCI slot's hotplug->info structure ...\n",
154	    __FUNCTION__);
155	rpaphp_get_power_status(slot, &hotplug_slot_info->power_status);
156	rpaphp_get_pci_adapter_status(slot, 1,
157				      &hotplug_slot_info->adapter_status);
158	if (hotplug_slot_info->adapter_status == NOT_VALID) {
159		err("%s: NOT_VALID: skip dn->full_name=%s\n",
160		    __FUNCTION__, slot->dn->full_name);
161		return -EINVAL;
162	}
163	return 0;
164}
165
166static void set_slot_name(struct slot *slot)
167{
168	struct pci_bus *bus = slot->bus;
169	struct pci_dev *bridge;
170
171	bridge = bus->self;
172	if (bridge)
173		strcpy(slot->name, pci_name(bridge));
174	else
175		sprintf(slot->name, "%04x:%02x:00.0", pci_domain_nr(bus),
176			bus->number);
177}
178
179static int setup_pci_slot(struct slot *slot)
180{
181	struct device_node *dn = slot->dn;
182	struct pci_bus *bus;
183
184	BUG_ON(!dn);
185	bus = pcibios_find_pci_bus(dn);
186	if (!bus) {
187		err("%s: no pci_bus for dn %s\n", __FUNCTION__, dn->full_name);
188		goto exit_rc;
189	}
190
191	slot->bus = bus;
192	slot->pci_devs = &bus->devices;
193	set_slot_name(slot);
194
195	/* find slot's pci_dev if it's not empty */
196	if (slot->hotplug_slot->info->adapter_status == EMPTY) {
197		slot->state = EMPTY;	/* slot is empty */
198	} else {
199		/* slot is occupied */
200		if (!dn->child) {
201			/* non-empty slot has to have child */
202			err("%s: slot[%s]'s device_node doesn't have child for adapter\n",
203				__FUNCTION__, slot->name);
204			goto exit_rc;
205		}
206
207		if (slot->hotplug_slot->info->adapter_status == NOT_CONFIGURED) {
208			dbg("%s CONFIGURING pci adapter in slot[%s]\n",
209				__FUNCTION__, slot->name);
210			pcibios_add_pci_devices(slot->bus);
211
212		} else if (slot->hotplug_slot->info->adapter_status != CONFIGURED) {
213			err("%s: slot[%s]'s adapter_status is NOT_VALID.\n",
214				__FUNCTION__, slot->name);
215			goto exit_rc;
216		}
217		print_slot_pci_funcs(slot->bus);
218		if (!list_empty(slot->pci_devs)) {
219			slot->state = CONFIGURED;
220		} else {
221			/* DLPAR add as opposed to
222		 	 * boot time */
223			slot->state = NOT_CONFIGURED;
224		}
225	}
226	return 0;
227exit_rc:
228	dealloc_slot_struct(slot);
229	return -EINVAL;
230}
231
232int register_pci_slot(struct slot *slot)
233{
234	int rc = -EINVAL;
235
236	if (setup_pci_hotplug_slot_info(slot))
237		goto exit_rc;
238	if (setup_pci_slot(slot))
239		goto exit_rc;
240	rc = register_slot(slot);
241exit_rc:
242	return rc;
243}
244
245int rpaphp_enable_pci_slot(struct slot *slot)
246{
247	int retval = 0, state;
248
249	retval = rpaphp_get_sensor_state(slot, &state);
250	if (retval)
251		goto exit;
252	dbg("%s: sensor state[%d]\n", __FUNCTION__, state);
253	/* if slot is not empty, enable the adapter */
254	if (state == PRESENT) {
255		dbg("%s : slot[%s] is occupied.\n", __FUNCTION__, slot->name);
256		pcibios_add_pci_devices(slot->bus);
257		slot->state = CONFIGURED;
258		info("%s: devices in slot[%s] configured\n",
259					__FUNCTION__, slot->name);
260	} else if (state == EMPTY) {
261		dbg("%s : slot[%s] is empty\n", __FUNCTION__, slot->name);
262		slot->state = EMPTY;
263	} else {
264		err("%s: slot[%s] is in invalid state\n", __FUNCTION__,
265		    slot->name);
266		slot->state = NOT_VALID;
267		retval = -EINVAL;
268	}
269exit:
270	dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
271	return retval;
272}
273