11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All rights reserved.
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or (at
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * your option) any later version.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, but
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WITHOUT ANY WARRANTY; without even the implied warranty of
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NON INFRINGEMENT.  See the GNU General Public License for more
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * details.
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send feedback to <lxie@us.ibm.com>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
264e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/string.h>
274e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pci-bridge.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/rtas.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/machdep.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
324e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include "../pci.h"		/* for pci_add_new_bus */
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "rpaphp.h"
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35e06b80b78db96ca272db4ec0b26ce1092a1a9704Linas Vepstasint rpaphp_get_sensor_state(struct slot *slot, int *state)
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int setlevel;
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = rtas_get_sensor(DR_ENTITY_SENSE, slot->index, state);
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc < 0) {
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rc == -EFAULT || rc == -EEXIST) {
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("%s: slot must be power up to get sensor-state\n",
4566bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison			    __func__);
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47f7625980f5820edd1a73536e1a03bcbc1f889fecBjorn Helgaas			/* some slots have to be powered up
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * before get-sensor will succeed.
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rc = rtas_set_power_level(slot->power_domain, POWER_ON,
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  &setlevel);
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (rc < 0) {
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dbg("%s: power on slot[%s] failed rc=%d.\n",
5466bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison				    __func__, slot->name, rc);
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rc = rtas_get_sensor(DR_ENTITY_SENSE,
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						     slot->index, state);
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (rc == -ENODEV)
6066bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison			info("%s: slot is unusable\n", __func__);
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
6266bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison			err("%s failed to get sensor state\n", __func__);
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
67fea54b8cc9c8290b4c99d481c3e600c46eb18fd5Linas Vepstas/**
68fea54b8cc9c8290b4c99d481c3e600c46eb18fd5Linas Vepstas * rpaphp_enable_slot - record slot state, config pci device
6926e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @slot: target &slot
70fea54b8cc9c8290b4c99d481c3e600c46eb18fd5Linas Vepstas *
71fea54b8cc9c8290b4c99d481c3e600c46eb18fd5Linas Vepstas * Initialize values in the slot, and the hotplug_slot info
72fea54b8cc9c8290b4c99d481c3e600c46eb18fd5Linas Vepstas * structures to indicate if there is a pci card plugged into
73fea54b8cc9c8290b4c99d481c3e600c46eb18fd5Linas Vepstas * the slot. If the slot is not empty, run the pcibios routine
74fea54b8cc9c8290b4c99d481c3e600c46eb18fd5Linas Vepstas * to get pcibios stuff correctly set up.
75fea54b8cc9c8290b4c99d481c3e600c46eb18fd5Linas Vepstas */
76fea54b8cc9c8290b4c99d481c3e600c46eb18fd5Linas Vepstasint rpaphp_enable_slot(struct slot *slot)
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
78bf0af511fcc856649a2a39c627828695b580d124Linas Vepstas	int rc, level, state;
79bf0af511fcc856649a2a39c627828695b580d124Linas Vepstas	struct pci_bus *bus;
80517d5a0417e19101eaa769039d1921d626ee546cLinas Vepstas	struct hotplug_slot_info *info = slot->hotplug_slot->info;
81517d5a0417e19101eaa769039d1921d626ee546cLinas Vepstas
8203a667559138d47cea487823332c4712fc6fbec7Linas Vepstas	info->adapter_status = NOT_VALID;
8303a667559138d47cea487823332c4712fc6fbec7Linas Vepstas	slot->state = EMPTY;
8403a667559138d47cea487823332c4712fc6fbec7Linas Vepstas
85bf0af511fcc856649a2a39c627828695b580d124Linas Vepstas	/* Find out if the power is turned on for the slot */
86427310ff02e80cc80826407c0121cec3694c9e7dLinas Vepstas	rc = rtas_get_power_level(slot->power_domain, &level);
87427310ff02e80cc80826407c0121cec3694c9e7dLinas Vepstas	if (rc)
88427310ff02e80cc80826407c0121cec3694c9e7dLinas Vepstas		return rc;
89427310ff02e80cc80826407c0121cec3694c9e7dLinas Vepstas	info->power_status = level;
90427310ff02e80cc80826407c0121cec3694c9e7dLinas Vepstas
91bf0af511fcc856649a2a39c627828695b580d124Linas Vepstas	/* Figure out if there is an adapter in the slot */
92bf0af511fcc856649a2a39c627828695b580d124Linas Vepstas	rc = rpaphp_get_sensor_state(slot, &state);
93bf0af511fcc856649a2a39c627828695b580d124Linas Vepstas	if (rc)
94bf0af511fcc856649a2a39c627828695b580d124Linas Vepstas		return rc;
95517d5a0417e19101eaa769039d1921d626ee546cLinas Vepstas
9603a667559138d47cea487823332c4712fc6fbec7Linas Vepstas	bus = pcibios_find_pci_bus(slot->dn);
9703a667559138d47cea487823332c4712fc6fbec7Linas Vepstas	if (!bus) {
9866bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison		err("%s: no pci_bus for dn %s\n", __func__, slot->dn->full_name);
9903a667559138d47cea487823332c4712fc6fbec7Linas Vepstas		return -EINVAL;
100517d5a0417e19101eaa769039d1921d626ee546cLinas Vepstas	}
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10203a667559138d47cea487823332c4712fc6fbec7Linas Vepstas	info->adapter_status = EMPTY;
10303a667559138d47cea487823332c4712fc6fbec7Linas Vepstas	slot->bus = bus;
10403a667559138d47cea487823332c4712fc6fbec7Linas Vepstas	slot->pci_devs = &bus->devices;
10503a667559138d47cea487823332c4712fc6fbec7Linas Vepstas
10603a667559138d47cea487823332c4712fc6fbec7Linas Vepstas	/* if there's an adapter in the slot, go add the pci devices */
10703a667559138d47cea487823332c4712fc6fbec7Linas Vepstas	if (state == PRESENT) {
10803a667559138d47cea487823332c4712fc6fbec7Linas Vepstas		info->adapter_status = NOT_CONFIGURED;
10903a667559138d47cea487823332c4712fc6fbec7Linas Vepstas		slot->state = NOT_CONFIGURED;
11003a667559138d47cea487823332c4712fc6fbec7Linas Vepstas
11103a667559138d47cea487823332c4712fc6fbec7Linas Vepstas		/* non-empty slot has to have child */
11203a667559138d47cea487823332c4712fc6fbec7Linas Vepstas		if (!slot->dn->child) {
11303a667559138d47cea487823332c4712fc6fbec7Linas Vepstas			err("%s: slot[%s]'s device_node doesn't have child for adapter\n",
11466bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison			    __func__, slot->name);
11503a667559138d47cea487823332c4712fc6fbec7Linas Vepstas			return -EINVAL;
11603a667559138d47cea487823332c4712fc6fbec7Linas Vepstas		}
11703a667559138d47cea487823332c4712fc6fbec7Linas Vepstas
11803a667559138d47cea487823332c4712fc6fbec7Linas Vepstas		if (list_empty(&bus->devices))
11903a667559138d47cea487823332c4712fc6fbec7Linas Vepstas			pcibios_add_pci_devices(bus);
12003a667559138d47cea487823332c4712fc6fbec7Linas Vepstas
12103a667559138d47cea487823332c4712fc6fbec7Linas Vepstas		if (!list_empty(&bus->devices)) {
12203a667559138d47cea487823332c4712fc6fbec7Linas Vepstas			info->adapter_status = CONFIGURED;
12303a667559138d47cea487823332c4712fc6fbec7Linas Vepstas			slot->state = CONFIGURED;
12403a667559138d47cea487823332c4712fc6fbec7Linas Vepstas		}
125307ff12e35526cfab9f09cafcb17239286e6eb85Linas Vepstas
1265d9bc1fa47f0c1561f1d7c0bdff5e24860852b42Kristen Carlson Accardi		if (rpaphp_debug) {
127307ff12e35526cfab9f09cafcb17239286e6eb85Linas Vepstas			struct pci_dev *dev;
12866bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison			dbg("%s: pci_devs of slot[%s]\n", __func__, slot->dn->full_name);
129307ff12e35526cfab9f09cafcb17239286e6eb85Linas Vepstas			list_for_each_entry (dev, &bus->devices, bus_list)
130307ff12e35526cfab9f09cafcb17239286e6eb85Linas Vepstas				dbg("\t%s\n", pci_name(dev));
131307ff12e35526cfab9f09cafcb17239286e6eb85Linas Vepstas		}
13203a667559138d47cea487823332c4712fc6fbec7Linas Vepstas	}
133517d5a0417e19101eaa769039d1921d626ee546cLinas Vepstas
1346f79eb749df7f1eea76c947f31603ade7d2b5f6dLinas Vepstas	return 0;
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
136