xref: /openbmc/linux/drivers/pci/hotplug/rpaphp_slot.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds  * RPA Virtual I/O device functions
3*1da177e4SLinus Torvalds  * Copyright (C) 2004 Linda Xie <lxie@us.ibm.com>
4*1da177e4SLinus Torvalds  *
5*1da177e4SLinus Torvalds  * All rights reserved.
6*1da177e4SLinus Torvalds  *
7*1da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify
8*1da177e4SLinus Torvalds  * it under the terms of the GNU General Public License as published by
9*1da177e4SLinus Torvalds  * the Free Software Foundation; either version 2 of the License, or (at
10*1da177e4SLinus Torvalds  * your option) any later version.
11*1da177e4SLinus Torvalds  *
12*1da177e4SLinus Torvalds  * This program is distributed in the hope that it will be useful, but
13*1da177e4SLinus Torvalds  * WITHOUT ANY WARRANTY; without even the implied warranty of
14*1da177e4SLinus Torvalds  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
15*1da177e4SLinus Torvalds  * NON INFRINGEMENT.  See the GNU General Public License for more
16*1da177e4SLinus Torvalds  * details.
17*1da177e4SLinus Torvalds  *
18*1da177e4SLinus Torvalds  * You should have received a copy of the GNU General Public License
19*1da177e4SLinus Torvalds  * along with this program; if not, write to the Free Software
20*1da177e4SLinus Torvalds  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*1da177e4SLinus Torvalds  *
22*1da177e4SLinus Torvalds  * Send feedback to <lxie@us.ibm.com>
23*1da177e4SLinus Torvalds  *
24*1da177e4SLinus Torvalds  */
25*1da177e4SLinus Torvalds #include <linux/kernel.h>
26*1da177e4SLinus Torvalds #include <linux/module.h>
27*1da177e4SLinus Torvalds #include <linux/kobject.h>
28*1da177e4SLinus Torvalds #include <linux/sysfs.h>
29*1da177e4SLinus Torvalds #include <linux/pci.h>
30*1da177e4SLinus Torvalds #include <asm/rtas.h>
31*1da177e4SLinus Torvalds #include "rpaphp.h"
32*1da177e4SLinus Torvalds 
33*1da177e4SLinus Torvalds static ssize_t removable_read_file (struct hotplug_slot *php_slot, char *buf)
34*1da177e4SLinus Torvalds {
35*1da177e4SLinus Torvalds 	u8 value;
36*1da177e4SLinus Torvalds 	int retval = -ENOENT;
37*1da177e4SLinus Torvalds 	struct slot *slot = (struct slot *)php_slot->private;
38*1da177e4SLinus Torvalds 
39*1da177e4SLinus Torvalds 	if (!slot)
40*1da177e4SLinus Torvalds 		return retval;
41*1da177e4SLinus Torvalds 
42*1da177e4SLinus Torvalds 	value = slot->removable;
43*1da177e4SLinus Torvalds 	retval = sprintf (buf, "%d\n", value);
44*1da177e4SLinus Torvalds 	return retval;
45*1da177e4SLinus Torvalds }
46*1da177e4SLinus Torvalds 
47*1da177e4SLinus Torvalds static struct hotplug_slot_attribute hotplug_slot_attr_removable = {
48*1da177e4SLinus Torvalds 	.attr = {.name = "phy_removable", .mode = S_IFREG | S_IRUGO},
49*1da177e4SLinus Torvalds 	.show = removable_read_file,
50*1da177e4SLinus Torvalds };
51*1da177e4SLinus Torvalds 
52*1da177e4SLinus Torvalds static void rpaphp_sysfs_add_attr_removable (struct hotplug_slot *slot)
53*1da177e4SLinus Torvalds {
54*1da177e4SLinus Torvalds 	sysfs_create_file(&slot->kobj, &hotplug_slot_attr_removable.attr);
55*1da177e4SLinus Torvalds }
56*1da177e4SLinus Torvalds 
57*1da177e4SLinus Torvalds static void rpaphp_sysfs_remove_attr_removable (struct hotplug_slot *slot)
58*1da177e4SLinus Torvalds {
59*1da177e4SLinus Torvalds 	sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_removable.attr);
60*1da177e4SLinus Torvalds }
61*1da177e4SLinus Torvalds 
62*1da177e4SLinus Torvalds static ssize_t location_read_file (struct hotplug_slot *php_slot, char *buf)
63*1da177e4SLinus Torvalds {
64*1da177e4SLinus Torvalds         char *value;
65*1da177e4SLinus Torvalds         int retval = -ENOENT;
66*1da177e4SLinus Torvalds 	struct slot *slot = (struct slot *)php_slot->private;
67*1da177e4SLinus Torvalds 
68*1da177e4SLinus Torvalds 	if (!slot)
69*1da177e4SLinus Torvalds 		return retval;
70*1da177e4SLinus Torvalds 
71*1da177e4SLinus Torvalds         value = slot->location;
72*1da177e4SLinus Torvalds         retval = sprintf (buf, "%s\n", value);
73*1da177e4SLinus Torvalds         return retval;
74*1da177e4SLinus Torvalds }
75*1da177e4SLinus Torvalds 
76*1da177e4SLinus Torvalds static struct hotplug_slot_attribute hotplug_slot_attr_location = {
77*1da177e4SLinus Torvalds 	.attr = {.name = "phy_location", .mode = S_IFREG | S_IRUGO},
78*1da177e4SLinus Torvalds 	.show = location_read_file,
79*1da177e4SLinus Torvalds };
80*1da177e4SLinus Torvalds 
81*1da177e4SLinus Torvalds static void rpaphp_sysfs_add_attr_location (struct hotplug_slot *slot)
82*1da177e4SLinus Torvalds {
83*1da177e4SLinus Torvalds 	sysfs_create_file(&slot->kobj, &hotplug_slot_attr_location.attr);
84*1da177e4SLinus Torvalds }
85*1da177e4SLinus Torvalds 
86*1da177e4SLinus Torvalds static void rpaphp_sysfs_remove_attr_location (struct hotplug_slot *slot)
87*1da177e4SLinus Torvalds {
88*1da177e4SLinus Torvalds 	sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_location.attr);
89*1da177e4SLinus Torvalds }
90*1da177e4SLinus Torvalds 
91*1da177e4SLinus Torvalds /* free up the memory used by a slot */
92*1da177e4SLinus Torvalds static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot)
93*1da177e4SLinus Torvalds {
94*1da177e4SLinus Torvalds 	struct slot *slot = (struct slot *) hotplug_slot->private;
95*1da177e4SLinus Torvalds 
96*1da177e4SLinus Torvalds 	dealloc_slot_struct(slot);
97*1da177e4SLinus Torvalds }
98*1da177e4SLinus Torvalds 
99*1da177e4SLinus Torvalds void dealloc_slot_struct(struct slot *slot)
100*1da177e4SLinus Torvalds {
101*1da177e4SLinus Torvalds 	kfree(slot->hotplug_slot->info);
102*1da177e4SLinus Torvalds 	kfree(slot->hotplug_slot->name);
103*1da177e4SLinus Torvalds 	kfree(slot->hotplug_slot);
104*1da177e4SLinus Torvalds 	kfree(slot);
105*1da177e4SLinus Torvalds 	return;
106*1da177e4SLinus Torvalds }
107*1da177e4SLinus Torvalds 
108*1da177e4SLinus Torvalds struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name,
109*1da177e4SLinus Torvalds 		  int power_domain)
110*1da177e4SLinus Torvalds {
111*1da177e4SLinus Torvalds 	struct slot *slot;
112*1da177e4SLinus Torvalds 
113*1da177e4SLinus Torvalds 	slot = kmalloc(sizeof (struct slot), GFP_KERNEL);
114*1da177e4SLinus Torvalds 	if (!slot)
115*1da177e4SLinus Torvalds 		goto error_nomem;
116*1da177e4SLinus Torvalds 	memset(slot, 0, sizeof (struct slot));
117*1da177e4SLinus Torvalds 	slot->hotplug_slot = kmalloc(sizeof (struct hotplug_slot), GFP_KERNEL);
118*1da177e4SLinus Torvalds 	if (!slot->hotplug_slot)
119*1da177e4SLinus Torvalds 		goto error_slot;
120*1da177e4SLinus Torvalds 	memset(slot->hotplug_slot, 0, sizeof (struct hotplug_slot));
121*1da177e4SLinus Torvalds 	slot->hotplug_slot->info = kmalloc(sizeof (struct hotplug_slot_info),
122*1da177e4SLinus Torvalds 					   GFP_KERNEL);
123*1da177e4SLinus Torvalds 	if (!slot->hotplug_slot->info)
124*1da177e4SLinus Torvalds 		goto error_hpslot;
125*1da177e4SLinus Torvalds 	memset(slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info));
126*1da177e4SLinus Torvalds 	slot->hotplug_slot->name = kmalloc(BUS_ID_SIZE + 1, GFP_KERNEL);
127*1da177e4SLinus Torvalds 	if (!slot->hotplug_slot->name)
128*1da177e4SLinus Torvalds 		goto error_info;
129*1da177e4SLinus Torvalds 	slot->location = kmalloc(strlen(drc_name) + 1, GFP_KERNEL);
130*1da177e4SLinus Torvalds 	if (!slot->location)
131*1da177e4SLinus Torvalds 		goto error_name;
132*1da177e4SLinus Torvalds 	slot->name = slot->hotplug_slot->name;
133*1da177e4SLinus Torvalds 	slot->dn = dn;
134*1da177e4SLinus Torvalds 	slot->index = drc_index;
135*1da177e4SLinus Torvalds 	strcpy(slot->location, drc_name);
136*1da177e4SLinus Torvalds 	slot->power_domain = power_domain;
137*1da177e4SLinus Torvalds 	slot->hotplug_slot->private = slot;
138*1da177e4SLinus Torvalds 	slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops;
139*1da177e4SLinus Torvalds 	slot->hotplug_slot->release = &rpaphp_release_slot;
140*1da177e4SLinus Torvalds 
141*1da177e4SLinus Torvalds 	return (slot);
142*1da177e4SLinus Torvalds 
143*1da177e4SLinus Torvalds error_name:
144*1da177e4SLinus Torvalds 	kfree(slot->hotplug_slot->name);
145*1da177e4SLinus Torvalds error_info:
146*1da177e4SLinus Torvalds 	kfree(slot->hotplug_slot->info);
147*1da177e4SLinus Torvalds error_hpslot:
148*1da177e4SLinus Torvalds 	kfree(slot->hotplug_slot);
149*1da177e4SLinus Torvalds error_slot:
150*1da177e4SLinus Torvalds 	kfree(slot);
151*1da177e4SLinus Torvalds error_nomem:
152*1da177e4SLinus Torvalds 	return NULL;
153*1da177e4SLinus Torvalds }
154*1da177e4SLinus Torvalds 
155*1da177e4SLinus Torvalds static int is_registered(struct slot *slot)
156*1da177e4SLinus Torvalds {
157*1da177e4SLinus Torvalds 	struct slot             *tmp_slot;
158*1da177e4SLinus Torvalds 
159*1da177e4SLinus Torvalds 	list_for_each_entry(tmp_slot, &rpaphp_slot_head, rpaphp_slot_list) {
160*1da177e4SLinus Torvalds 		if (!strcmp(tmp_slot->name, slot->name))
161*1da177e4SLinus Torvalds 			return 1;
162*1da177e4SLinus Torvalds 	}
163*1da177e4SLinus Torvalds 	return 0;
164*1da177e4SLinus Torvalds }
165*1da177e4SLinus Torvalds 
166*1da177e4SLinus Torvalds int deregister_slot(struct slot *slot)
167*1da177e4SLinus Torvalds {
168*1da177e4SLinus Torvalds 	int retval = 0;
169*1da177e4SLinus Torvalds 	struct hotplug_slot *php_slot = slot->hotplug_slot;
170*1da177e4SLinus Torvalds 
171*1da177e4SLinus Torvalds 	 dbg("%s - Entry: deregistering slot=%s\n",
172*1da177e4SLinus Torvalds 		__FUNCTION__, slot->name);
173*1da177e4SLinus Torvalds 
174*1da177e4SLinus Torvalds 	list_del(&slot->rpaphp_slot_list);
175*1da177e4SLinus Torvalds 
176*1da177e4SLinus Torvalds 	/* remove "phy_location" file */
177*1da177e4SLinus Torvalds 	rpaphp_sysfs_remove_attr_location(php_slot);
178*1da177e4SLinus Torvalds 
179*1da177e4SLinus Torvalds 	/* remove "phy_removable" file */
180*1da177e4SLinus Torvalds 	rpaphp_sysfs_remove_attr_removable(php_slot);
181*1da177e4SLinus Torvalds 
182*1da177e4SLinus Torvalds 	retval = pci_hp_deregister(php_slot);
183*1da177e4SLinus Torvalds 	if (retval)
184*1da177e4SLinus Torvalds 		err("Problem unregistering a slot %s\n", slot->name);
185*1da177e4SLinus Torvalds 	else
186*1da177e4SLinus Torvalds 		num_slots--;
187*1da177e4SLinus Torvalds 
188*1da177e4SLinus Torvalds 	dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
189*1da177e4SLinus Torvalds 	return retval;
190*1da177e4SLinus Torvalds }
191*1da177e4SLinus Torvalds 
192*1da177e4SLinus Torvalds int register_slot(struct slot *slot)
193*1da177e4SLinus Torvalds {
194*1da177e4SLinus Torvalds 	int retval;
195*1da177e4SLinus Torvalds 
196*1da177e4SLinus Torvalds 	dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n",
197*1da177e4SLinus Torvalds 		__FUNCTION__, slot->dn->full_name, slot->index, slot->name,
198*1da177e4SLinus Torvalds 		slot->power_domain, slot->type);
199*1da177e4SLinus Torvalds 	/* should not try to register the same slot twice */
200*1da177e4SLinus Torvalds 	if (is_registered(slot)) { /* should't be here */
201*1da177e4SLinus Torvalds 		err("register_slot: slot[%s] is already registered\n", slot->name);
202*1da177e4SLinus Torvalds 		rpaphp_release_slot(slot->hotplug_slot);
203*1da177e4SLinus Torvalds 		return -EAGAIN;
204*1da177e4SLinus Torvalds 	}
205*1da177e4SLinus Torvalds 	retval = pci_hp_register(slot->hotplug_slot);
206*1da177e4SLinus Torvalds 	if (retval) {
207*1da177e4SLinus Torvalds 		err("pci_hp_register failed with error %d\n", retval);
208*1da177e4SLinus Torvalds 		rpaphp_release_slot(slot->hotplug_slot);
209*1da177e4SLinus Torvalds 		return retval;
210*1da177e4SLinus Torvalds 	}
211*1da177e4SLinus Torvalds 
212*1da177e4SLinus Torvalds 	/* create "phy_locatoin" file */
213*1da177e4SLinus Torvalds 	rpaphp_sysfs_add_attr_location(slot->hotplug_slot);
214*1da177e4SLinus Torvalds 
215*1da177e4SLinus Torvalds 	/* create "phy_removable" file */
216*1da177e4SLinus Torvalds 	rpaphp_sysfs_add_attr_removable(slot->hotplug_slot);
217*1da177e4SLinus Torvalds 
218*1da177e4SLinus Torvalds 	/* add slot to our internal list */
219*1da177e4SLinus Torvalds 	dbg("%s adding slot[%s] to rpaphp_slot_list\n",
220*1da177e4SLinus Torvalds 	    __FUNCTION__, slot->name);
221*1da177e4SLinus Torvalds 
222*1da177e4SLinus Torvalds 	list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head);
223*1da177e4SLinus Torvalds 
224*1da177e4SLinus Torvalds 	if (slot->dev_type == VIO_DEV)
225*1da177e4SLinus Torvalds 		info("Slot [%s](VIO location=%s) registered\n",
226*1da177e4SLinus Torvalds 		     slot->name, slot->location);
227*1da177e4SLinus Torvalds 	else
228*1da177e4SLinus Torvalds 		info("Slot [%s](PCI location=%s) registered\n",
229*1da177e4SLinus Torvalds 		     slot->name, slot->location);
230*1da177e4SLinus Torvalds 	num_slots++;
231*1da177e4SLinus Torvalds 	return 0;
232*1da177e4SLinus Torvalds }
233*1da177e4SLinus Torvalds 
234*1da177e4SLinus Torvalds int rpaphp_get_power_status(struct slot *slot, u8 * value)
235*1da177e4SLinus Torvalds {
236*1da177e4SLinus Torvalds 	int rc = 0, level;
237*1da177e4SLinus Torvalds 
238*1da177e4SLinus Torvalds 	if (slot->type == HOTPLUG) {
239*1da177e4SLinus Torvalds 		rc = rtas_get_power_level(slot->power_domain, &level);
240*1da177e4SLinus Torvalds 		if (!rc) {
241*1da177e4SLinus Torvalds 			dbg("%s the power level of slot %s(pwd-domain:0x%x) is %d\n",
242*1da177e4SLinus Torvalds 				__FUNCTION__, slot->name, slot->power_domain, level);
243*1da177e4SLinus Torvalds 			*value = level;
244*1da177e4SLinus Torvalds 		} else
245*1da177e4SLinus Torvalds 			err("failed to get power-level for slot(%s), rc=0x%x\n",
246*1da177e4SLinus Torvalds 				slot->location, rc);
247*1da177e4SLinus Torvalds 	} else {
248*1da177e4SLinus Torvalds 		dbg("%s report POWER_ON for EMBEDDED or PHB slot %s\n",
249*1da177e4SLinus Torvalds 			__FUNCTION__, slot->location);
250*1da177e4SLinus Torvalds 		*value = (u8) POWER_ON;
251*1da177e4SLinus Torvalds 	}
252*1da177e4SLinus Torvalds 
253*1da177e4SLinus Torvalds 	return rc;
254*1da177e4SLinus Torvalds }
255*1da177e4SLinus Torvalds 
256*1da177e4SLinus Torvalds int rpaphp_set_attention_status(struct slot *slot, u8 status)
257*1da177e4SLinus Torvalds {
258*1da177e4SLinus Torvalds 	int rc;
259*1da177e4SLinus Torvalds 
260*1da177e4SLinus Torvalds 	/* status: LED_OFF or LED_ON */
261*1da177e4SLinus Torvalds 	rc = rtas_set_indicator(DR_INDICATOR, slot->index, status);
262*1da177e4SLinus Torvalds 	if (rc < 0)
263*1da177e4SLinus Torvalds 		err("slot(name=%s location=%s index=0x%x) set attention-status(%d) failed! rc=0x%x\n",
264*1da177e4SLinus Torvalds 		    slot->name, slot->location, slot->index, status, rc);
265*1da177e4SLinus Torvalds 
266*1da177e4SLinus Torvalds 	return rc;
267*1da177e4SLinus Torvalds }
268