899eed00274848be378ebc232acfbd08d6f7590d
[sfrench/cifs-2.6.git] / drivers / pci / hotplug / rpaphp_core.c
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/kernel.h>
26 #include <linux/module.h>
27 #include <linux/moduleparam.h>
28 #include <linux/pci.h>
29 #include <linux/pci_hotplug.h>
30 #include <linux/slab.h>
31 #include <linux/smp.h>
32 #include <linux/smp_lock.h>
33 #include <linux/init.h>
34 #include <asm/eeh.h>       /* for eeh_add_device() */
35 #include <asm/rtas.h>           /* rtas_call */
36 #include <asm/pci-bridge.h>     /* for pci_controller */
37 #include "../pci.h"             /* for pci_add_new_bus */
38                                 /* and pci_do_scan_bus */
39 #include "rpaphp.h"
40
41 int debug;
42 LIST_HEAD(rpaphp_slot_head);
43
44 #define DRIVER_VERSION  "0.1"
45 #define DRIVER_AUTHOR   "Linda Xie <lxie@us.ibm.com>"
46 #define DRIVER_DESC     "RPA HOT Plug PCI Controller Driver"
47
48 #define MAX_LOC_CODE 128
49
50 MODULE_AUTHOR(DRIVER_AUTHOR);
51 MODULE_DESCRIPTION(DRIVER_DESC);
52 MODULE_LICENSE("GPL");
53
54 module_param(debug, bool, 0644);
55
56 /**
57  * set_attention_status - set attention LED
58  * echo 0 > attention -- set LED OFF
59  * echo 1 > attention -- set LED ON
60  * echo 2 > attention -- set LED ID(identify, light is blinking)
61  *
62  */
63 static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value)
64 {
65         int rc;
66         struct slot *slot = (struct slot *)hotplug_slot->private;
67
68         switch (value) {
69         case 0:
70         case 1:
71         case 2:
72                 break;
73         default:
74                 value = 1;
75                 break;
76         }
77
78         rc = rtas_set_indicator(DR_INDICATOR, slot->index, value);
79         if (!rc)
80                 hotplug_slot->info->attention_status = value;
81
82         return rc;
83 }
84
85 /**
86  * get_power_status - get power status of a slot
87  * @hotplug_slot: slot to get status
88  * @value: pointer to store status
89  */
90 static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value)
91 {
92         int retval, level;
93         struct slot *slot = (struct slot *)hotplug_slot->private;
94
95         retval = rtas_get_power_level (slot->power_domain, &level);
96         if (!retval)
97                 *value = level;
98         return retval;
99 }
100
101 /**
102  * get_attention_status - get attention LED status
103  */
104 static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value)
105 {
106         struct slot *slot = (struct slot *)hotplug_slot->private;
107         *value = slot->hotplug_slot->info->attention_status;
108         return 0;
109 }
110
111 static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value)
112 {
113         struct slot *slot = (struct slot *)hotplug_slot->private;
114         int rc, state;
115
116         rc = rpaphp_get_sensor_state(slot, &state);
117
118         *value = NOT_VALID;
119         if (rc)
120                 return rc;
121
122         if (state == EMPTY)
123                 *value = EMPTY;
124         else if (state == PRESENT)
125                 *value = slot->state;
126
127         return 0;
128 }
129
130 static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
131 {
132         struct slot *slot = (struct slot *)hotplug_slot->private;
133
134         switch (slot->type) {
135         case 1:
136         case 2:
137         case 3:
138         case 4:
139         case 5:
140         case 6:
141                 *value = PCI_SPEED_33MHz;       /* speed for case 1-6 */
142                 break;
143         case 7:
144         case 8:
145                 *value = PCI_SPEED_66MHz;
146                 break;
147         case 11:
148         case 14:
149                 *value = PCI_SPEED_66MHz_PCIX;
150                 break;
151         case 12:
152         case 15:
153                 *value = PCI_SPEED_100MHz_PCIX;
154                 break;
155         case 13:
156         case 16:
157                 *value = PCI_SPEED_133MHz_PCIX;
158                 break;
159         default:
160                 *value = PCI_SPEED_UNKNOWN;
161                 break;
162
163         }
164         return 0;
165 }
166
167 static int get_children_props(struct device_node *dn, const int **drc_indexes,
168                 const int **drc_names, const int **drc_types,
169                 const int **drc_power_domains)
170 {
171         const int *indexes, *names, *types, *domains;
172
173         indexes = of_get_property(dn, "ibm,drc-indexes", NULL);
174         names = of_get_property(dn, "ibm,drc-names", NULL);
175         types = of_get_property(dn, "ibm,drc-types", NULL);
176         domains = of_get_property(dn, "ibm,drc-power-domains", NULL);
177
178         if (!indexes || !names || !types || !domains) {
179                 /* Slot does not have dynamically-removable children */
180                 return -EINVAL;
181         }
182         if (drc_indexes)
183                 *drc_indexes = indexes;
184         if (drc_names)
185                 /* &drc_names[1] contains NULL terminated slot names */
186                 *drc_names = names;
187         if (drc_types)
188                 /* &drc_types[1] contains NULL terminated slot types */
189                 *drc_types = types;
190         if (drc_power_domains)
191                 *drc_power_domains = domains;
192
193         return 0;
194 }
195
196 /* To get the DRC props describing the current node, first obtain it's
197  * my-drc-index property.  Next obtain the DRC list from it's parent.  Use
198  * the my-drc-index for correlation, and obtain the requested properties.
199  */
200 int rpaphp_get_drc_props(struct device_node *dn, int *drc_index,
201                 char **drc_name, char **drc_type, int *drc_power_domain)
202 {
203         const int *indexes, *names;
204         const int *types, *domains;
205         const unsigned int *my_index;
206         char *name_tmp, *type_tmp;
207         int i, rc;
208
209         my_index = of_get_property(dn, "ibm,my-drc-index", NULL);
210         if (!my_index) {
211                 /* Node isn't DLPAR/hotplug capable */
212                 return -EINVAL;
213         }
214
215         rc = get_children_props(dn->parent, &indexes, &names, &types, &domains);
216         if (rc < 0) {
217                 return -EINVAL;
218         }
219
220         name_tmp = (char *) &names[1];
221         type_tmp = (char *) &types[1];
222
223         /* Iterate through parent properties, looking for my-drc-index */
224         for (i = 0; i < indexes[0]; i++) {
225                 if ((unsigned int) indexes[i + 1] == *my_index) {
226                         if (drc_name)
227                                 *drc_name = name_tmp;
228                         if (drc_type)
229                                 *drc_type = type_tmp;
230                         if (drc_index)
231                                 *drc_index = *my_index;
232                         if (drc_power_domain)
233                                 *drc_power_domain = domains[i+1];
234                         return 0;
235                 }
236                 name_tmp += (strlen(name_tmp) + 1);
237                 type_tmp += (strlen(type_tmp) + 1);
238         }
239
240         return -EINVAL;
241 }
242
243 static int is_php_type(char *drc_type)
244 {
245         unsigned long value;
246         char *endptr;
247
248         /* PCI Hotplug nodes have an integer for drc_type */
249         value = simple_strtoul(drc_type, &endptr, 10);
250         if (endptr == drc_type)
251                 return 0;
252
253         return 1;
254 }
255
256 /**
257  * is_php_dn() - return 1 if this is a hotpluggable pci slot, else 0
258  *
259  * This routine will return true only if the device node is
260  * a hotpluggable slot. This routine will return false
261  * for built-in pci slots (even when the built-in slots are
262  * dlparable.)
263  */
264 static int is_php_dn(struct device_node *dn, const int **indexes,
265                 const int **names, const int **types, const int **power_domains)
266 {
267         const int *drc_types;
268         int rc;
269
270         rc = get_children_props(dn, indexes, names, &drc_types, power_domains);
271         if (rc < 0)
272                 return 0;
273
274         if (!is_php_type((char *) &drc_types[1]))
275                 return 0;
276
277         *types = drc_types;
278         return 1;
279 }
280
281 /**
282  * rpaphp_add_slot -- declare a hotplug slot to the hotplug subsystem.
283  * @dn device node of slot
284  *
285  * This subroutine will register a hotplugable slot with the
286  * PCI hotplug infrastructure. This routine is typicaly called
287  * during boot time, if the hotplug slots are present at boot time,
288  * or is called later, by the dlpar add code, if the slot is
289  * being dynamically added during runtime.
290  *
291  * If the device node points at an embedded (built-in) slot, this
292  * routine will just return without doing anything, since embedded
293  * slots cannot be hotplugged.
294  *
295  * To remove a slot, it suffices to call rpaphp_deregister_slot()
296  */
297 int rpaphp_add_slot(struct device_node *dn)
298 {
299         struct slot *slot;
300         int retval = 0;
301         int i;
302         const int *indexes, *names, *types, *power_domains;
303         char *name, *type;
304
305         if (!dn->name || strcmp(dn->name, "pci"))
306                 return 0;
307
308         /* If this is not a hotplug slot, return without doing anything. */
309         if (!is_php_dn(dn, &indexes, &names, &types, &power_domains))
310                 return 0;
311
312         dbg("Entry %s: dn->full_name=%s\n", __FUNCTION__, dn->full_name);
313
314         /* register PCI devices */
315         name = (char *) &names[1];
316         type = (char *) &types[1];
317         for (i = 0; i < indexes[0]; i++) {
318
319                 slot = alloc_slot_struct(dn, indexes[i + 1], name, power_domains[i + 1]);
320                 if (!slot)
321                         return -ENOMEM;
322
323                 slot->type = simple_strtoul(type, NULL, 10);
324                                 
325                 dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n",
326                                 indexes[i + 1], name, type);
327
328                 retval = rpaphp_enable_slot(slot);
329                 if (!retval)
330                         retval = rpaphp_register_slot(slot);
331
332                 if (retval)
333                         dealloc_slot_struct(slot);
334
335                 name += strlen(name) + 1;
336                 type += strlen(type) + 1;
337         }
338         dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
339
340         /* XXX FIXME: reports a failure only if last entry in loop failed */
341         return retval;
342 }
343
344 static void __exit cleanup_slots(void)
345 {
346         struct list_head *tmp, *n;
347         struct slot *slot;
348
349         /*
350          * Unregister all of our slots with the pci_hotplug subsystem,
351          * and free up all memory that we had allocated.
352          * memory will be freed in release_slot callback. 
353          */
354
355         list_for_each_safe(tmp, n, &rpaphp_slot_head) {
356                 slot = list_entry(tmp, struct slot, rpaphp_slot_list);
357                 list_del(&slot->rpaphp_slot_list);
358                 pci_hp_deregister(slot->hotplug_slot);
359         }
360         return;
361 }
362
363 static int __init rpaphp_init(void)
364 {
365         struct device_node *dn = NULL;
366
367         info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
368
369         while ((dn = of_find_node_by_name(dn, "pci")))
370                 rpaphp_add_slot(dn);
371
372         return 0;
373 }
374
375 static void __exit rpaphp_exit(void)
376 {
377         cleanup_slots();
378 }
379
380 static int enable_slot(struct hotplug_slot *hotplug_slot)
381 {
382         struct slot *slot = (struct slot *)hotplug_slot->private;
383         int state;
384         int retval;
385
386         if (slot->state == CONFIGURED)
387                 return 0;
388
389         retval = rpaphp_get_sensor_state(slot, &state);
390         if (retval)
391                 return retval;
392
393         if (state == PRESENT) {
394                 pcibios_add_pci_devices(slot->bus);
395                 slot->state = CONFIGURED;
396         } else if (state == EMPTY) {
397                 slot->state = EMPTY;
398         } else {
399                 err("%s: slot[%s] is in invalid state\n", __FUNCTION__, slot->name);
400                 slot->state = NOT_VALID;
401                 return -EINVAL;
402         }
403         return 0;
404 }
405
406 static int disable_slot(struct hotplug_slot *hotplug_slot)
407 {
408         struct slot *slot = (struct slot *)hotplug_slot->private;
409         if (slot->state == NOT_CONFIGURED)
410                 return -EINVAL;
411
412         pcibios_remove_pci_devices(slot->bus);
413         slot->state = NOT_CONFIGURED;
414         return 0;
415 }
416
417 struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
418         .owner = THIS_MODULE,
419         .enable_slot = enable_slot,
420         .disable_slot = disable_slot,
421         .set_attention_status = set_attention_status,
422         .get_power_status = get_power_status,
423         .get_attention_status = get_attention_status,
424         .get_adapter_status = get_adapter_status,
425         .get_max_bus_speed = get_max_bus_speed,
426 };
427
428 module_init(rpaphp_init);
429 module_exit(rpaphp_exit);
430
431 EXPORT_SYMBOL_GPL(rpaphp_add_slot);
432 EXPORT_SYMBOL_GPL(rpaphp_slot_head);
433 EXPORT_SYMBOL_GPL(rpaphp_get_drc_props);