All of lore.kernel.org
 help / color / mirror / Atom feed
From: Greg KH <greg@kroah.com>
To: linux-kernel@vger.kernel.org, pcihpd-discuss@lists.sourceforge.net
Subject: Re: [PATCH] PCI update for 2.6.3
Date: Fri, 20 Feb 2004 11:06:20 -0800	[thread overview]
Message-ID: <10773039802021@kroah.com> (raw)
In-Reply-To: <10773039792482@kroah.com>

ChangeSet 1.1557.58.6, 2004/02/18 12:53:42-08:00, lxiep@linux.ibm.com

[PATCH] PCI Hotplug: Add PPC64 PCI Hotplug Driver for RPA


 drivers/pci/hotplug/Kconfig       |   11 
 drivers/pci/hotplug/Makefile      |    4 
 drivers/pci/hotplug/rpaphp.h      |  101 ++++
 drivers/pci/hotplug/rpaphp_core.c |  948 ++++++++++++++++++++++++++++++++++++++
 drivers/pci/hotplug/rpaphp_pci.c  |   75 +++
 5 files changed, 1139 insertions(+)


diff -Nru a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
--- a/drivers/pci/hotplug/Kconfig	Fri Feb 20 10:44:56 2004
+++ b/drivers/pci/hotplug/Kconfig	Fri Feb 20 10:44:56 2004
@@ -189,5 +189,16 @@
 	  Say Y here for AMD SHPC. You have to select this option if you are 
 	  using this driver on AMD platform with SHPC.
 
+config HOTPLUG_PCI_RPA
+	tristate "RPA PCI Hotplug driver"
+	depends on HOTPLUG_PCI && PPC_PSERIES && PPC64
+	help
+	  Say Y here if you have a a RPA system that supports PCI Hotplug.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called rpaphp.
+
+	  When in doubt, say N.
+
 endmenu
 
diff -Nru a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile
--- a/drivers/pci/hotplug/Makefile	Fri Feb 20 10:44:56 2004
+++ b/drivers/pci/hotplug/Makefile	Fri Feb 20 10:44:56 2004
@@ -11,6 +11,7 @@
 obj-$(CONFIG_HOTPLUG_PCI_CPCI_GENERIC)	+= cpcihp_generic.o
 obj-$(CONFIG_HOTPLUG_PCI_PCIE)		+= pciehp.o
 obj-$(CONFIG_HOTPLUG_PCI_SHPC)		+= shpchp.o
+obj-$(CONFIG_HOTPLUG_PCI_RPA)		+= rpaphp.o
 
 pci_hotplug-objs	:=	pci_hotplug_core.o
 
@@ -34,6 +35,9 @@
 				acpiphp_glue.o	\
 				acpiphp_pci.o	\
 				acpiphp_res.o
+
+rpaphp-objs		:=	rpaphp_core.o	\
+				rpaphp_pci.o	
 
 pciehp-objs		:=	pciehp_core.o	\
 				pciehp_ctrl.o	\
diff -Nru a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/pci/hotplug/rpaphp.h	Fri Feb 20 10:44:56 2004
@@ -0,0 +1,101 @@
+/*
+ * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform.
+ *
+ * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <lxie@us.ibm.com>,
+ *
+ */
+
+#ifndef _PPC64PHP_H
+#define _PPC64PHP_H
+#include "pci_hotplug.h"
+
+#define DR_INDICATOR 9002
+#define DR_ENTITY_SENSE 9003
+
+#define POWER_ON	100
+#define POWER_OFF	0
+
+#define LED_OFF		0 
+#define LED_ON		1	/* continuous on */ 
+#define LED_ID		2	/* slow blinking */
+#define LED_ACTION	3	/* fast blinking */
+
+#define SLOT_NAME_SIZE 12
+
+/* Error status from rtas_get-sensor */
+#define NEED_POWER    -9000     /* slot must be power up and unisolated to get state */
+#define PWR_ONLY      -9001     /* slot must be powerd up to get state, leave isolated */
+#define ERR_SENSE_USE -9002     /* No DR operation will succeed, slot is unusable  */
+
+/* Sensor values from rtas_get-sensor */
+#define EMPTY	0       /* No card in slot */
+#define PRESENT	1       /* Card in slot */
+
+#define MY_NAME "rpaphp"
+
+#define dbg(format, arg...)					\
+	do {							\
+		if (rpaphp_debug)				\
+			printk(KERN_DEBUG "%s: " format,	\
+				MY_NAME , ## arg); 		\
+	} while (0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
+
+#define SLOT_MAGIC	0x67267322
+
+/* slot states */
+
+#define	NOT_VALID	3
+#define	NOT_CONFIGURED	2
+#define	CONFIGURED	1
+#define	EMPTY		0
+
+/*
+ * struct slot - slot information for each *physical* slot
+ */
+struct slot {
+	u32	magic;
+	int     state;
+	u32     index;
+	u32     type;
+	u32     power_domain;
+	char    *name;
+	struct	device_node *dn;/* slot's device_node in OFDT		*/
+				/* dn has phb info			*/
+	struct	pci_dev	*bridge;/* slot's pci_dev in pci_devices	*/
+
+	struct	pci_dev	*dev;	/* pci_dev of device in this slot 	*/
+				/* it will be used for unconfig		*/ 
+				/* NULL if slot is empty		*/
+
+	struct  hotplug_slot    *hotplug_slot;
+	struct list_head	rpaphp_slot_list;
+};
+
+extern struct pci_dev *rpaphp_find_pci_dev(struct device_node *dn);
+extern int rpaphp_add_slot(char *slot_name);
+extern int rpaphp_remove_slot(struct slot *slot);
+extern int rpaphp_claim_resource(struct pci_dev *dev, int resource);
+
+#endif /* _PPC64PHP_H */
diff -Nru a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/pci/hotplug/rpaphp_core.c	Fri Feb 20 10:44:56 2004
@@ -0,0 +1,948 @@
+/*
+ * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform.
+ * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <lxie@us.ibm.com>
+ *
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <asm/rtas.h>		/* rtas_call */
+#include <asm/pci-bridge.h>	/* for pci_controller */
+#include "../pci.h"		/* for pci_add_new_bus*/
+				/* and pci_do_scan_bus*/
+#include "rpaphp.h"
+#include "pci_hotplug.h"
+
+
+static int debug = 1;
+static struct semaphore rpaphp_sem;
+static LIST_HEAD (rpaphp_slot_head);
+static int num_slots;
+
+#define DRIVER_VERSION	"0.1"
+#define DRIVER_AUTHOR	"Linda Xie <lxie@us.ibm.com>"
+#define DRIVER_DESC	"RPA HOT Plug PCI Controller Driver"
+
+#define MAX_LOC_CODE 128
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+module_param(debug, int, 0644);
+
+static int enable_slot(struct hotplug_slot *slot);
+static int disable_slot(struct hotplug_slot *slot);
+static int set_attention_status(struct hotplug_slot *slot, u8 value);
+static int get_power_status(struct hotplug_slot *slot, u8 *value);
+static int get_attention_status(struct hotplug_slot *slot, u8 *value);
+static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
+static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value);
+static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value);
+
+static struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
+	.owner			= THIS_MODULE,
+	.enable_slot		= enable_slot,
+	.disable_slot		= disable_slot,
+	.set_attention_status	= set_attention_status,
+	.get_power_status	= get_power_status,
+	.get_attention_status	= get_attention_status,
+	.get_adapter_status	= get_adapter_status,
+	.get_max_bus_speed	= get_max_bus_speed,
+	.get_cur_bus_speed	= get_cur_bus_speed,
+};
+
+static int rpaphp_get_sensor_state(int index, int *state)
+{
+	int rc;
+
+	rc = rtas_get_sensor(DR_ENTITY_SENSE, index, state);
+
+	if (rc) {
+		if (rc ==  NEED_POWER || rc == PWR_ONLY) {
+			dbg("%s: slot must be power up to get sensor-state\n",
+				__FUNCTION__);
+		} else if (rc == ERR_SENSE_USE)
+			info("%s: slot is unusable\n", __FUNCTION__);
+		   else err("%s failed to get sensor state\n", __FUNCTION__);
+	}
+	return rc;
+}
+
+static struct pci_dev *rpaphp_find_bridge_pdev(struct slot *slot)
+{
+	return rpaphp_find_pci_dev(slot->dn);
+}
+
+static struct pci_dev *rpaphp_find_adapter_pdev(struct slot *slot)
+{
+	return rpaphp_find_pci_dev(slot->dn->child);
+}
+
+/* Inline functions to check the sanity of a pointer that is passed to us */
+static inline int slot_paranoia_check(struct slot *slot, const char *function)
+{
+	if (!slot) {
+		dbg("%s - slot == NULL\n", function);
+		return -1;
+	}
+
+	if (!slot->hotplug_slot) {
+		dbg("%s - slot->hotplug_slot == NULL!\n", function);
+		return -1;
+	}
+	return 0;
+}
+
+static inline struct slot *get_slot(struct hotplug_slot *hotplug_slot, const char *function)
+{
+	struct slot *slot;
+
+	if (!hotplug_slot) {
+		dbg("%s - hotplug_slot == NULL\n", function);
+		return NULL;
+	}
+
+	slot = (struct slot *)hotplug_slot->private;
+	if (slot_paranoia_check(slot, function))
+		return NULL;
+	return slot;
+}
+
+static inline int rpaphp_set_attention_status(struct slot *slot, u8 status)
+{
+	int	rc;
+
+	/* status: LED_OFF or LED_ON */
+	rc = rtas_set_indicator(DR_INDICATOR, slot->index, status);
+	if (rc)
+		err("slot(%s) set attention-status(%d) failed! rc=0x%x\n",
+			slot->name, status, rc);
+	
+	return rc;
+}
+
+static int rpaphp_get_power_status(struct slot *slot, u8 *value)
+{
+	int	rc;
+
+	rc = rtas_get_power_level(slot->power_domain, (int *)value);
+	if (rc)
+		err("failed to get power-level for slot(%s), rc=0x%x\n",
+			slot->name, rc);
+
+	return rc;
+}
+
+static int rpaphp_get_attention_status(struct slot *slot)
+{
+
+	return slot->hotplug_slot->info->attention_status;
+}
+
+/**
+ * set_attention_status - set attention LED
+ * echo 0 > attention -- set LED OFF
+ * echo 1 > attention -- set LED ON
+ * echo 2 > attention -- set LED ID(identify, light is blinking)
+ *
+ */
+static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 value)
+{
+	int retval = 0;
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	down(&rpaphp_sem);
+	switch (value) {
+		case 0:
+			retval = rpaphp_set_attention_status(slot, LED_OFF);
+			hotplug_slot->info->attention_status = 0;
+			break;
+
+		case 1:
+		default:
+			retval = rpaphp_set_attention_status(slot, LED_ON);
+			hotplug_slot->info->attention_status = 1;
+			break;
+
+		case 2:
+			retval = rpaphp_set_attention_status(slot, LED_ID);
+			hotplug_slot->info->attention_status = 2;
+			break;
+
+	}
+	up(&rpaphp_sem);
+	
+	return retval;
+}
+
+/**
+ * get_power_status - get power status of a slot
+ * @hotplug_slot: slot to get status
+ * @value: pointer to store status
+ *
+ *
+ */
+static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	int retval;
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	down(&rpaphp_sem);
+	retval = rpaphp_get_power_status(slot, value);
+	up(&rpaphp_sem);
+
+	return retval;
+}
+
+/**
+ * get_attention_status - get attention LED status
+ *
+ *
+ */
+static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	int retval = 0;
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+
+
+	down(&rpaphp_sem);
+	*value = rpaphp_get_attention_status(slot);
+	up(&rpaphp_sem);
+
+	return retval;
+}
+
+/*
+ * get_adapter_status - get  the status of a slot
+ *
+ * 0-- slot is empty
+ * 1-- adapter is configured
+ * 2-- adapter is not configured
+ * 3-- not valid
+ */
+static int rpaphp_get_adapter_status(struct slot *slot, int is_init, u8 *value)
+{
+	int	state, rc;
+
+	*value 		  = NOT_VALID;
+
+	rc = rpaphp_get_sensor_state(slot->index, &state);
+
+	if (rc)
+		return rc;
+
+	if (state == PRESENT) {
+		dbg("slot is occupied\n");
+
+		if (!is_init) /* at run-time slot->state can be changed by */
+			  /* config/unconfig adapter	 		   */
+			*value = slot->state;
+		else {
+		if (!slot->dn->child)
+			dbg("%s: %s is not valid OFDT node\n",
+				__FUNCTION__, slot->dn->full_name);
+		else
+			if (rpaphp_find_pci_dev(slot->dn->child))
+				*value = CONFIGURED;
+			else {
+				dbg("%s: can't find pdev of adapter in slot[%s]\n",
+					__FUNCTION__, slot->name);
+				*value = NOT_CONFIGURED;
+				}
+		}
+	} else
+		if (state == EMPTY) {
+		dbg("slot is empty\n");
+			*value = state;
+		}
+	
+	return 0;
+}
+
+static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+	int retval = 0;
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	down(&rpaphp_sem);
+
+	/*  have to go through this */
+	retval = rpaphp_get_adapter_status(slot, 0, value);
+
+	up(&rpaphp_sem);
+
+	return retval;
+}
+
+
+static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	down(&rpaphp_sem);
+
+	switch (slot->type) {
+		case 1:
+		case 2:
+		case 3:
+		case 4:
+		case 5:
+		case 6:
+			*value = PCI_SPEED_33MHz;	/* speed for case 1-6 */
+			break;
+		case 7:
+		case 8:
+			*value = PCI_SPEED_66MHz;
+			break;
+		case 11:
+		case 14:
+			*value = PCI_SPEED_66MHz_PCIX;
+			break;
+		case 12:
+		case 15:
+			*value = PCI_SPEED_100MHz_PCIX;
+			break;
+		case 13:
+		case 16:
+			*value = PCI_SPEED_133MHz_PCIX;
+			break;
+		default:
+			*value = PCI_SPEED_UNKNOWN;
+			break;
+
+	}
+
+	up(&rpaphp_sem);
+
+	return 0;
+}
+
+
+/* return dummy value because not sure if PRA provides any method... */
+static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	*value = PCI_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+/*
+ * rpaphp_validate_slot - make sure the name of the slot matches
+ * 				the location code , if the slots is not
+ *				empty.
+ */
+static int rpaphp_validate_slot(const char *slot_name, const int slot_index)
+{
+	struct device_node	*dn;
+
+	for(dn = find_all_nodes(); dn; dn = dn->next) {
+
+		int 		*index;
+		unsigned char	*loc_code;
+
+		index  = (int *)get_property(dn, "ibm,my-drc-index", NULL);
+
+		if (index && *index == slot_index) {
+			char *slash, *tmp_str;
+
+			loc_code = get_property(dn, "ibm,loc-code", NULL);
+			if (!loc_code) { 
+				return -1;
+			}
+
+			tmp_str = kmalloc(MAX_LOC_CODE, GFP_KERNEL); 
+			if (!tmp_str) {
+				err("%s: out of memory\n", __FUNCTION__);
+				return -1;
+			}
+				
+			strcpy(tmp_str, loc_code);
+			slash = strrchr(tmp_str, '/');
+			if (slash) 
+				*slash = '\0';
+			
+			if (strcmp(slot_name, tmp_str)) {
+				kfree(tmp_str);
+				return -1;
+			}
+
+			kfree(tmp_str);
+			break;
+		}
+	}
+	
+	return 0;
+}
+
+/* Must be called before pci_bus_add_devices */
+static void rpaphp_fixup_new_devices(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+	/*
+	 * Skip already-present devices (which are on the
+	 * global device list.)
+	 */
+		if (list_empty(&dev->global_list)) {
+			int i;
+			pcibios_fixup_device_resources(dev, bus);
+			pci_read_irq_line(dev);
+			for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+				struct resource *r = &dev->resource[i];
+				if (r->parent || !r->start || !r->flags)
+					continue;
+				rpaphp_claim_resource(dev, i);
+			}
+		}
+	}
+}
+
+static struct pci_dev *rpaphp_config_adapter(struct slot *slot)
+{
+	struct pci_bus 		*pci_bus;
+	struct device_node	*dn;
+	int 			num;
+	struct pci_dev		*dev = NULL;
+
+	if (slot->bridge) {
+
+		pci_bus = slot->bridge->subordinate;
+
+		if (!pci_bus) {
+			err("%s: can't find bus structure\n", __FUNCTION__);
+			goto exit;
+		}
+
+		for (dn = slot->dn->child; dn; dn = dn->sibling) {
+			dbg("child dn's devfn=[%x]\n", dn->devfn);
+				num = pci_scan_slot(pci_bus,
+				PCI_DEVFN(PCI_SLOT(dn->devfn),  0));
+
+				dbg("pci_scan_slot return num=%d\n", num);
+
+			if (num) {
+				rpaphp_fixup_new_devices(pci_bus);
+				pci_bus_add_devices(pci_bus);
+			}
+		}
+
+		dev = rpaphp_find_pci_dev(slot->dn->child);
+	} else {
+		/* slot is not enabled */
+		err("slot doesn't have pci_dev structure\n");
+		dev = NULL;
+		goto exit;
+	}
+
+exit:
+	dbg("Exit %s: pci_dev %s\n", __FUNCTION__, dev? "found":"not found");
+
+	return dev;
+}
+
+static int rpaphp_unconfig_adapter(struct slot *slot)
+{
+	if (!slot->dev) {
+		info("%s: no card in slot[%s]\n",
+			__FUNCTION__, slot->name);
+
+		return -EINVAL;
+	}
+
+	/* remove the device from the pci core */
+	pci_remove_bus_device(slot->dev);
+
+	pci_dev_put(slot->dev);
+	slot->state = NOT_CONFIGURED;
+
+	dbg("%s: adapter in slot[%s] unconfigured.\n", __FUNCTION__, slot->name);
+
+	return 0;
+}
+
+/* free up the memory user be a slot */
+
+static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return;
+
+	kfree(slot->hotplug_slot->info);
+	kfree(slot->hotplug_slot->name);
+	kfree(slot->hotplug_slot);
+	pci_dev_put(slot->bridge);
+	pci_dev_put(slot->dev);
+	kfree(slot);
+}
+
+int rpaphp_remove_slot(struct slot *slot)
+{
+	int retval = 0;
+
+  	sysfs_remove_link(slot->hotplug_slot->kobj.parent,
+			slot->bridge->slot_name);
+
+	list_del(&slot->rpaphp_slot_list);
+	retval = pci_hp_deregister(slot->hotplug_slot);
+	if (retval)
+		err("Problem unregistering a slot %s\n", slot->name);
+	num_slots--;
+
+	return retval;
+}
+
+static int is_php_dn(struct device_node *dn, int **indexes,  int **names, int **types, int **power_domains)
+{
+	*indexes = (int *)get_property(dn, "ibm,drc-indexes", NULL);
+	if (!*indexes)
+		return(0);
+
+	/* &names[1] contains NULL terminated slot names */
+	*names = (int *)get_property(dn, "ibm,drc-names", NULL);
+	if (!*names)
+		return(0);
+
+	/* &types[1] contains NULL terminated slot types */
+	*types = (int *)get_property(dn, "ibm,drc-types", NULL);
+	if (!*types)
+		return(0);
+
+	/* power_domains[1...n] are the slot power domains */
+	*power_domains = (int *)get_property(dn,
+		"ibm,drc-power-domains", NULL);
+	if (!*power_domains)
+		return(0);
+
+	if (!get_property(dn, "ibm,fw-pci-hot-plug-ctrl", NULL))
+		return(0);
+
+	return(1);
+}
+
+static struct slot *alloc_slot_struct(void)
+{
+	struct slot *slot;
+
+	slot = kmalloc(sizeof(struct slot), GFP_KERNEL);
+	if (!slot)
+		return (NULL);
+	memset(slot, 0, sizeof(struct slot));
+	slot->hotplug_slot = kmalloc(sizeof(struct hotplug_slot),
+		GFP_KERNEL);
+	if (!slot->hotplug_slot) {
+		kfree(slot);
+		return (NULL);
+	}
+	memset(slot->hotplug_slot, 0, sizeof(struct hotplug_slot));
+	slot->hotplug_slot->info = kmalloc(sizeof(struct hotplug_slot_info),
+		GFP_KERNEL);
+	if (!slot->hotplug_slot->info) {
+		kfree(slot->hotplug_slot);
+		kfree(slot);
+		return (NULL);
+	}
+	memset(slot->hotplug_slot->info, 0, sizeof(struct hotplug_slot_info));
+	slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
+	if (!slot->hotplug_slot->name) {
+		kfree(slot->hotplug_slot->info);
+		kfree(slot->hotplug_slot);
+		kfree(slot);
+		return (NULL);
+	}
+	return (slot);
+}
+
+static int setup_hotplug_slot_info(struct slot *slot)
+{
+	rpaphp_get_power_status(slot,
+		&slot->hotplug_slot->info->power_status);
+
+	rpaphp_get_adapter_status(slot, 1,
+		&slot->hotplug_slot->info->adapter_status);
+
+	if (slot->hotplug_slot->info->adapter_status == NOT_VALID) {
+		dbg("%s: NOT_VALID: skip dn->full_name=%s\n",
+			__FUNCTION__, slot->dn->full_name);
+		    kfree(slot->hotplug_slot->info);
+		    kfree(slot->hotplug_slot->name);
+		    kfree(slot->hotplug_slot);
+		    kfree(slot);
+		return (-1);
+	}
+	return (0);
+}
+
+static int register_slot(struct slot *slot)
+{
+	int retval;
+
+	retval = pci_hp_register(slot->hotplug_slot);
+	if (retval) {
+		err("pci_hp_register failed with error %d\n", retval);
+		rpaphp_release_slot(slot->hotplug_slot);
+		return (retval);
+	}
+	/* create symlink between slot->name and it's bus_id */
+	dbg("%s: sysfs_create_link: %s --> %s\n", __FUNCTION__,
+		slot->bridge->slot_name, slot->name);
+	retval = sysfs_create_link(slot->hotplug_slot->kobj.parent,
+			&slot->hotplug_slot->kobj,
+			slot->bridge->slot_name);
+	if (retval) {
+		err("sysfs_create_link failed with error %d\n", retval);
+		rpaphp_release_slot(slot->hotplug_slot);
+		return (retval);
+	}
+	/* add slot to our internal list */
+	dbg("%s adding slot[%s] to rpaphp_slot_list\n",
+		__FUNCTION__, slot->name);
+
+	list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head);
+
+	info("Slot [%s] (bus_id=%s) registered\n",
+		slot->name, slot->bridge->slot_name);
+	return (0);
+}
+
+/*************************************
+ * Add  Hot Plug slot(s) to sysfs
+ *
+ ************************************/
+int rpaphp_add_slot(char *slot_name)
+{
+	struct slot		*slot;
+	int 			retval = 0;
+	int 			i;
+	struct device_node 	*dn;
+	int 			*indexes, *names, *types, *power_domains;
+	char 			*name, *type;
+
+	for (dn = find_all_nodes(); dn; dn = dn->next) {
+
+		if (dn->name != 0 && strcmp(dn->name, "pci") == 0)	{
+			if (!is_php_dn(dn, &indexes, &names, &types, &power_domains))
+				continue;
+
+			dbg("%s : found device_node in OFDT full_name=%s, name=%s\n",
+				__FUNCTION__, dn->full_name, dn->name);
+
+			name = (char *)&names[1];
+			type = (char *)&types[1];
+
+			for (i = 0; i < indexes[0];
+				i++,
+				name += (strlen(name) + 1),
+				type += (strlen(type) + 1)) {
+
+				dbg("%s: name[%s] index[%x]\n",
+					__FUNCTION__, name, indexes[i+1]);
+
+				if (slot_name && strcmp(slot_name, name))
+					continue;
+
+				if (rpaphp_validate_slot(name, indexes[i + 1])) {
+					dbg("%s: slot(%s, 0x%x) is invalid.\n",
+						__FUNCTION__, name, indexes[i+ 1]);
+					continue;
+				}
+
+				slot = alloc_slot_struct();
+				if (!slot) {
+					retval = -ENOMEM;
+					goto exit;
+				}
+
+				slot->name = slot->hotplug_slot->name;
+				slot->index = indexes[i + 1];
+				strcpy(slot->name, name);
+				slot->type = simple_strtoul(type, NULL, 10);
+				if (slot->type < 1  || slot->type > 16)
+					slot->type = 0;
+
+				slot->power_domain = power_domains[i + 1];
+				slot->magic = SLOT_MAGIC;
+				slot->hotplug_slot->private = slot;
+				slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops;
+				slot->hotplug_slot->release = &rpaphp_release_slot;
+				slot->dn = dn;
+
+				/*
+			 	* Initilize the slot info structure with some known
+			 	* good values.
+			 	*/
+				if (setup_hotplug_slot_info(slot))
+					continue;
+
+				slot->bridge = rpaphp_find_bridge_pdev(slot);
+				if (!slot->bridge && slot_name) { /* slot being added doesn't have pci_dev yet*/
+					dbg("%s: no pci_dev for bridge dn %s\n",
+							__FUNCTION__, slot_name);
+					kfree(slot->hotplug_slot->info);
+					kfree(slot->hotplug_slot->name);
+					kfree(slot->hotplug_slot);
+					kfree(slot);
+					continue;
+				}
+
+				/* find slot's pci_dev if it's not empty*/
+				if (slot->hotplug_slot->info->adapter_status == EMPTY) {
+					slot->state = EMPTY;  /* slot is empty */
+					slot->dev = NULL;
+				} else {  /* slot is occupied */
+					if(!(slot->dn->child)) { /* non-empty slot has to have child */
+						err("%s: slot[%s]'s device_node doesn't have child for adapter\n",
+						__FUNCTION__, slot->name);
+						kfree(slot->hotplug_slot->info);
+						kfree(slot->hotplug_slot->name);
+						kfree(slot->hotplug_slot);
+						kfree(slot);
+						continue;
+
+					}
+
+					slot->dev = rpaphp_find_adapter_pdev(slot);
+					if(slot->dev) {
+						slot->state = CONFIGURED;
+						pci_dev_get(slot->dev);
+					} else {
+						/* DLPAR add as opposed to
+						 * boot time */
+						slot->state = NOT_CONFIGURED;
+						}
+				}
+				dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n",
+					__FUNCTION__, dn->full_name, slot->index, slot->name,
+					slot->power_domain, slot->type);
+
+				retval = register_slot(slot);
+				if (retval)
+					goto exit;
+
+				num_slots++;
+
+				if (slot_name)
+					goto exit;
+
+			}/* for indexes */
+		}/* "pci" */
+	}/* find_all_nodes */
+exit:
+	dbg("%s - Exit: num_slots=%d rc[%d]\n",
+		__FUNCTION__, num_slots, retval);
+	return retval;
+}
+
+/*
+ * init_slots - initialize 'struct slot' structures for each slot
+ *
+ */
+static int init_slots (void)
+{
+	int 			retval = 0;
+
+	retval = rpaphp_add_slot(NULL);
+
+	return retval;
+}
+
+
+static int init_rpa (void)
+{
+	int 			retval = 0;
+
+	init_MUTEX(&rpaphp_sem);
+
+	/* initialize internal data structure etc. */
+	retval = init_slots();
+	if (!num_slots)
+		retval = -ENODEV;
+
+	return retval;
+}
+
+static void cleanup_slots (void)
+{
+	struct list_head *tmp, *n;
+	struct slot *slot;
+
+	/*
+	 * Unregister all of our slots with the pci_hotplug subsystem,
+	 * and free up all memory that we had allocated.
+	 * memory will be freed in release_slot callback.
+	 */
+
+	list_for_each_safe (tmp, n, &rpaphp_slot_head) {
+		slot = list_entry(tmp, struct slot, rpaphp_slot_list);
+		sysfs_remove_link(slot->hotplug_slot->kobj.parent,
+			slot->bridge->slot_name);
+		list_del(&slot->rpaphp_slot_list);
+		pci_hp_deregister(slot->hotplug_slot);
+	}
+
+	return;
+}
+
+
+static int __init rpaphp_init(void)
+{
+	int retval = 0;
+
+	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+
+	rpaphp_debug = debug;
+
+	/* read all the PRA info from the system */
+	retval = init_rpa();
+
+	return retval;
+}
+
+
+static void __exit rpaphp_exit(void)
+{
+	cleanup_slots();
+}
+
+
+static int enable_slot(struct hotplug_slot *hotplug_slot)
+{
+	int retval = 0, state;
+
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	if (slot->state == CONFIGURED) {
+		dbg("%s: %s is already enabled\n",
+			__FUNCTION__, slot->name);
+		goto exit;
+	}
+
+	dbg("ENABLING SLOT %s\n", slot->name);
+
+	down(&rpaphp_sem);
+
+	retval = rpaphp_get_sensor_state(slot->index, &state);
+
+	if (retval)
+		goto exit;
+
+	dbg("%s: sensor state[%d]\n", __FUNCTION__, state);
+
+	/* if slot is not empty, enable the adapter */
+	if (state == PRESENT) {
+		dbg("%s : slot[%s] is occupid.\n", __FUNCTION__, slot->name);
+
+		
+		slot->dev = rpaphp_config_adapter(slot);
+		if (slot->dev != NULL) {
+			slot->state = CONFIGURED;
+
+			dbg("%s: adapter %s in slot[%s] has been configured\n",
+				__FUNCTION__, slot->dev->slot_name,
+				slot->name);
+		} else {
+			slot->state = NOT_CONFIGURED;
+
+			dbg("%s: no pci_dev struct for adapter in slot[%s]\n",
+				__FUNCTION__, slot->name);
+		}
+
+	} else if (state == EMPTY) {
+		dbg("%s : slot[%s] is empty\n", __FUNCTION__, slot->name);
+		slot->state = EMPTY;
+	} else {
+		err("%s: slot[%s] is in invalid state\n", __FUNCTION__, slot->name);
+		slot->state = NOT_VALID;
+		retval = -EINVAL;
+	}
+
+exit:
+	if (slot->state != NOT_VALID)
+		rpaphp_set_attention_status(slot, LED_ON);
+	else
+		rpaphp_set_attention_status(slot, LED_ID);
+
+	up(&rpaphp_sem);
+
+	return retval;
+}
+
+static int disable_slot(struct hotplug_slot *hotplug_slot)
+{
+	int	retval;
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("DISABLING SLOT %s\n", slot->name);
+
+	down(&rpaphp_sem);
+
+	rpaphp_set_attention_status(slot, LED_ID);
+
+	retval = rpaphp_unconfig_adapter(slot);
+
+	rpaphp_set_attention_status(slot, LED_OFF);
+
+	up(&rpaphp_sem);
+
+	return retval;
+}
+
+module_init(rpaphp_init);
+module_exit(rpaphp_exit);
+
+EXPORT_SYMBOL_GPL(rpaphp_add_slot);
+EXPORT_SYMBOL_GPL(rpaphp_remove_slot);
diff -Nru a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/pci/hotplug/rpaphp_pci.c	Fri Feb 20 10:44:56 2004
@@ -0,0 +1,75 @@
+/*
+ * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform.
+ * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <lxie@us.ibm.com>
+ *
+ */
+#include <linux/pci.h>
+#include <asm/pci-bridge.h>	/* for pci_controller */
+#include "rpaphp.h"
+
+
+struct pci_dev *rpaphp_find_pci_dev(struct device_node *dn)
+{
+	struct pci_dev		*retval_dev = NULL, *dev = NULL;
+
+	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+		if(!dev->bus)
+			continue;
+
+		if (dev->devfn != dn->devfn)
+			continue;
+
+		if (dn->phb->global_number == pci_domain_nr(dev->bus) &&
+		    dn->busno == dev->bus->number) {
+			retval_dev = dev;
+			break;
+		}
+	}
+
+	return retval_dev;
+
+}
+
+int rpaphp_claim_resource(struct pci_dev *dev, int resource)
+{
+	struct resource *res = &dev->resource[resource];
+	struct resource *root = pci_find_parent_resource(dev, res);
+	char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge";
+	int err;
+
+	err = -EINVAL;
+	if (root != NULL) {
+		err = request_resource(root, res);
+	}
+
+	if (err) {
+		err("PCI: %s region %d of %s %s [%lx:%lx]\n",
+			root ? "Address space collision on" :
+			"No parent found for",
+			resource, dtype, pci_name(dev), res->start, res->end);
+	}
+
+	return err;
+}
+
+EXPORT_SYMBOL_GPL(rpaphp_find_pci_dev);
+EXPORT_SYMBOL_GPL(rpaphp_claim_resource);


       reply	other threads:[~2004-02-20 19:16 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <10773039792482@kroah.com>
2004-02-20 19:06 ` Greg KH [this message]
2004-02-20 19:06   ` [PATCH] PCI update for 2.6.3 Greg KH
2004-02-20 19:06     ` Greg KH
2004-02-20 19:06       ` Greg KH
2004-02-20 19:06         ` Greg KH
2004-02-20 19:06           ` Greg KH
2004-02-20 19:04 [BK PATCH] " Greg KH
2004-02-20 19:06 ` [PATCH] " Greg KH
2004-02-20 19:06   ` Greg KH
2004-02-20 19:06     ` Greg KH
2004-02-20 19:06       ` Greg KH
2004-02-20 19:19     ` Christoph Hellwig
2004-02-20 19:41   ` Dave Jones
2004-02-20 19:53     ` Greg KH

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=10773039802021@kroah.com \
    --to=greg@kroah.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pcihpd-discuss@lists.sourceforge.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.