Showing error 936

User: Jiri Slaby
Error type: Leaving function in locked state
Error type description: Some lock is not unlocked on all paths of a function, so it is leaked
File location: drivers/pci/hotplug/pciehp_core.c
Line in file: 130
Project: Linux Kernel
Project version: 2.6.28
Confirmation: Fixed by c2fdd36b550659f5ac2240d1f5a83ffa1a092289
Tools: Stanse (1.2)
Entered: 2012-03-02 21:35:17 UTC


Source:

  1/*
  2 * PCI Express Hot Plug Controller Driver
  3 *
  4 * Copyright (C) 1995,2001 Compaq Computer Corporation
  5 * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
  6 * Copyright (C) 2001 IBM Corp.
  7 * Copyright (C) 2003-2004 Intel Corporation
  8 *
  9 * All rights reserved.
 10 *
 11 * This program is free software; you can redistribute it and/or modify
 12 * it under the terms of the GNU General Public License as published by
 13 * the Free Software Foundation; either version 2 of the License, or (at
 14 * your option) any later version.
 15 *
 16 * This program is distributed in the hope that it will be useful, but
 17 * WITHOUT ANY WARRANTY; without even the implied warranty of
 18 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
 19 * NON INFRINGEMENT.  See the GNU General Public License for more
 20 * details.
 21 *
 22 * You should have received a copy of the GNU General Public License
 23 * along with this program; if not, write to the Free Software
 24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 25 *
 26 * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
 27 *
 28 */
 29
 30#include <linux/module.h>
 31#include <linux/moduleparam.h>
 32#include <linux/kernel.h>
 33#include <linux/types.h>
 34#include <linux/pci.h>
 35#include "pciehp.h"
 36#include <linux/interrupt.h>
 37#include <linux/time.h>
 38
 39/* Global variables */
 40int pciehp_debug;
 41int pciehp_poll_mode;
 42int pciehp_poll_time;
 43int pciehp_force;
 44struct workqueue_struct *pciehp_wq;
 45
 46#define DRIVER_VERSION        "0.4"
 47#define DRIVER_AUTHOR        "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
 48#define DRIVER_DESC        "PCI Express Hot Plug Controller Driver"
 49
 50MODULE_AUTHOR(DRIVER_AUTHOR);
 51MODULE_DESCRIPTION(DRIVER_DESC);
 52MODULE_LICENSE("GPL");
 53
 54module_param(pciehp_debug, bool, 0644);
 55module_param(pciehp_poll_mode, bool, 0644);
 56module_param(pciehp_poll_time, int, 0644);
 57module_param(pciehp_force, bool, 0644);
 58MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not");
 59MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not");
 60MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds");
 61MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing");
 62
 63#define PCIE_MODULE_NAME "pciehp"
 64
 65static int set_attention_status (struct hotplug_slot *slot, u8 value);
 66static int enable_slot                (struct hotplug_slot *slot);
 67static int disable_slot                (struct hotplug_slot *slot);
 68static int get_power_status        (struct hotplug_slot *slot, u8 *value);
 69static int get_attention_status        (struct hotplug_slot *slot, u8 *value);
 70static int get_latch_status        (struct hotplug_slot *slot, u8 *value);
 71static int get_adapter_status        (struct hotplug_slot *slot, u8 *value);
 72static int get_max_bus_speed        (struct hotplug_slot *slot, enum pci_bus_speed *value);
 73static int get_cur_bus_speed        (struct hotplug_slot *slot, enum pci_bus_speed *value);
 74
 75static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
 76        .owner =                THIS_MODULE,
 77        .set_attention_status =        set_attention_status,
 78        .enable_slot =                enable_slot,
 79        .disable_slot =                disable_slot,
 80        .get_power_status =        get_power_status,
 81        .get_attention_status =        get_attention_status,
 82        .get_latch_status =        get_latch_status,
 83        .get_adapter_status =        get_adapter_status,
 84          .get_max_bus_speed =        get_max_bus_speed,
 85          .get_cur_bus_speed =        get_cur_bus_speed,
 86};
 87
 88/*
 89 * Check the status of the Electro Mechanical Interlock (EMI)
 90 */
 91static int get_lock_status(struct hotplug_slot *hotplug_slot, u8 *value)
 92{
 93        struct slot *slot = hotplug_slot->private;
 94        return (slot->hpc_ops->get_emi_status(slot, value));
 95}
 96
 97/*
 98 * sysfs interface for the Electro Mechanical Interlock (EMI)
 99 * 1 == locked, 0 == unlocked
100 */
101static ssize_t lock_read_file(struct hotplug_slot *slot, char *buf)
102{
103        int retval;
104        u8 value;
105
106        retval = get_lock_status(slot, &value);
107        if (retval)
108                goto lock_read_exit;
109        retval = sprintf (buf, "%d\n", value);
110
111lock_read_exit:
112        return retval;
113}
114
115/*
116 * Change the status of the Electro Mechanical Interlock (EMI)
117 * This is a toggle - in addition there must be at least 1 second
118 * in between toggles.
119 */
120static int set_lock_status(struct hotplug_slot *hotplug_slot, u8 status)
121{
122        struct slot *slot = hotplug_slot->private;
123        int retval;
124        u8 value;
125
126        mutex_lock(&slot->ctrl->crit_sect);
127
128        /* has it been >1 sec since our last toggle? */
129        if ((get_seconds() - slot->last_emi_toggle) < 1)
130                return -EINVAL;
131
132        /* see what our current state is */
133        retval = get_lock_status(hotplug_slot, &value);
134        if (retval || (value == status))
135                goto set_lock_exit;
136
137        slot->hpc_ops->toggle_emi(slot);
138set_lock_exit:
139        mutex_unlock(&slot->ctrl->crit_sect);
140        return 0;
141}
142
143/*
144 * sysfs interface which allows the user to toggle the Electro Mechanical
145 * Interlock.  Valid values are either 0 or 1.  0 == unlock, 1 == lock
146 */
147static ssize_t lock_write_file(struct hotplug_slot *hotplug_slot,
148                const char *buf, size_t count)
149{
150        struct slot *slot = hotplug_slot->private;
151        unsigned long llock;
152        u8 lock;
153        int retval = 0;
154
155        llock = simple_strtoul(buf, NULL, 10);
156        lock = (u8)(llock & 0xff);
157
158        switch (lock) {
159                case 0:
160                case 1:
161                        retval = set_lock_status(hotplug_slot, lock);
162                        break;
163                default:
164                        ctrl_err(slot->ctrl, "%d is an invalid lock value\n",
165                                 lock);
166                        retval = -EINVAL;
167        }
168        if (retval)
169                return retval;
170        return count;
171}
172
173static struct hotplug_slot_attribute hotplug_slot_attr_lock = {
174        .attr = {.name = "lock", .mode = S_IFREG | S_IRUGO | S_IWUSR},
175        .show = lock_read_file,
176        .store = lock_write_file
177};
178
179/**
180 * release_slot - free up the memory used by a slot
181 * @hotplug_slot: slot to free
182 */
183static void release_slot(struct hotplug_slot *hotplug_slot)
184{
185        struct slot *slot = hotplug_slot->private;
186
187        ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
188                 __func__, hotplug_slot_name(hotplug_slot));
189
190        kfree(hotplug_slot->info);
191        kfree(hotplug_slot);
192}
193
194static int init_slots(struct controller *ctrl)
195{
196        struct slot *slot;
197        struct hotplug_slot *hotplug_slot;
198        struct hotplug_slot_info *info;
199        char name[SLOT_NAME_SIZE];
200        int retval = -ENOMEM;
201
202        list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
203                hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL);
204                if (!hotplug_slot)
205                        goto error;
206
207                info = kzalloc(sizeof(*info), GFP_KERNEL);
208                if (!info)
209                        goto error_hpslot;
210
211                /* register this slot with the hotplug pci core */
212                hotplug_slot->info = info;
213                hotplug_slot->private = slot;
214                hotplug_slot->release = &release_slot;
215                hotplug_slot->ops = &pciehp_hotplug_slot_ops;
216                slot->hotplug_slot = hotplug_slot;
217                snprintf(name, SLOT_NAME_SIZE, "%u", slot->number);
218
219                 ctrl_dbg(ctrl, "Registering domain:bus:dev=%04x:%02x:%02x "
220                          "hp_slot=%x sun=%x slot_device_offset=%x\n",
221                          pci_domain_nr(ctrl->pci_dev->subordinate),
222                          slot->bus, slot->device, slot->hp_slot, slot->number,
223                          ctrl->slot_device_offset);
224                retval = pci_hp_register(hotplug_slot,
225                                         ctrl->pci_dev->subordinate,
226                                         slot->device,
227                                         name);
228                if (retval) {
229                        ctrl_err(ctrl, "pci_hp_register failed with error %d\n",
230                                 retval);
231                        goto error_info;
232                }
233                get_power_status(hotplug_slot, &info->power_status);
234                get_attention_status(hotplug_slot, &info->attention_status);
235                get_latch_status(hotplug_slot, &info->latch_status);
236                get_adapter_status(hotplug_slot, &info->adapter_status);
237                /* create additional sysfs entries */
238                if (EMI(ctrl)) {
239                        retval = sysfs_create_file(&hotplug_slot->pci_slot->kobj,
240                                &hotplug_slot_attr_lock.attr);
241                        if (retval) {
242                                pci_hp_deregister(hotplug_slot);
243                                ctrl_err(ctrl, "Cannot create additional sysfs "
244                                         "entries\n");
245                                goto error_info;
246                        }
247                }
248        }
249
250        return 0;
251error_info:
252        kfree(info);
253error_hpslot:
254        kfree(hotplug_slot);
255error:
256        return retval;
257}
258
259static void cleanup_slots(struct controller *ctrl)
260{
261        struct slot *slot;
262
263        list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
264                if (EMI(ctrl))
265                        sysfs_remove_file(&slot->hotplug_slot->pci_slot->kobj,
266                                &hotplug_slot_attr_lock.attr);
267                pci_hp_deregister(slot->hotplug_slot);
268        }
269}
270
271/*
272 * set_attention_status - Turns the Amber LED for a slot on, off or blink
273 */
274static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
275{
276        struct slot *slot = hotplug_slot->private;
277
278        ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
279                  __func__, slot_name(slot));
280
281        hotplug_slot->info->attention_status = status;
282
283        if (ATTN_LED(slot->ctrl))
284                slot->hpc_ops->set_attention_status(slot, status);
285
286        return 0;
287}
288
289
290static int enable_slot(struct hotplug_slot *hotplug_slot)
291{
292        struct slot *slot = hotplug_slot->private;
293
294        ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
295                 __func__, slot_name(slot));
296
297        return pciehp_sysfs_enable_slot(slot);
298}
299
300
301static int disable_slot(struct hotplug_slot *hotplug_slot)
302{
303        struct slot *slot = hotplug_slot->private;
304
305        ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
306                  __func__, slot_name(slot));
307
308        return pciehp_sysfs_disable_slot(slot);
309}
310
311static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
312{
313        struct slot *slot = hotplug_slot->private;
314        int retval;
315
316        ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
317                  __func__, slot_name(slot));
318
319        retval = slot->hpc_ops->get_power_status(slot, value);
320        if (retval < 0)
321                *value = hotplug_slot->info->power_status;
322
323        return 0;
324}
325
326static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
327{
328        struct slot *slot = hotplug_slot->private;
329        int retval;
330
331        ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
332                  __func__, slot_name(slot));
333
334        retval = slot->hpc_ops->get_attention_status(slot, value);
335        if (retval < 0)
336                *value = hotplug_slot->info->attention_status;
337
338        return 0;
339}
340
341static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
342{
343        struct slot *slot = hotplug_slot->private;
344        int retval;
345
346        ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
347                 __func__, slot_name(slot));
348
349        retval = slot->hpc_ops->get_latch_status(slot, value);
350        if (retval < 0)
351                *value = hotplug_slot->info->latch_status;
352
353        return 0;
354}
355
356static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
357{
358        struct slot *slot = hotplug_slot->private;
359        int retval;
360
361        ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
362                 __func__, slot_name(slot));
363
364        retval = slot->hpc_ops->get_adapter_status(slot, value);
365        if (retval < 0)
366                *value = hotplug_slot->info->adapter_status;
367
368        return 0;
369}
370
371static int get_max_bus_speed(struct hotplug_slot *hotplug_slot,
372                                enum pci_bus_speed *value)
373{
374        struct slot *slot = hotplug_slot->private;
375        int retval;
376
377        ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
378                 __func__, slot_name(slot));
379
380        retval = slot->hpc_ops->get_max_bus_speed(slot, value);
381        if (retval < 0)
382                *value = PCI_SPEED_UNKNOWN;
383
384        return 0;
385}
386
387static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
388{
389        struct slot *slot = hotplug_slot->private;
390        int retval;
391
392        ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
393                 __func__, slot_name(slot));
394
395        retval = slot->hpc_ops->get_cur_bus_speed(slot, value);
396        if (retval < 0)
397                *value = PCI_SPEED_UNKNOWN;
398
399        return 0;
400}
401
402static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_id *id)
403{
404        int rc;
405        struct controller *ctrl;
406        struct slot *t_slot;
407        u8 value;
408        struct pci_dev *pdev = dev->port;
409
410        if (pciehp_force)
411                dev_info(&dev->device,
412                         "Bypassing BIOS check for pciehp use on %s\n",
413                         pci_name(pdev));
414        else if (pciehp_get_hp_hw_control_from_firmware(pdev))
415                goto err_out_none;
416
417        ctrl = pcie_init(dev);
418        if (!ctrl) {
419                dev_err(&dev->device, "Controller initialization failed\n");
420                goto err_out_none;
421        }
422        set_service_data(dev, ctrl);
423
424        /* Setup the slot information structures */
425        rc = init_slots(ctrl);
426        if (rc) {
427                if (rc == -EBUSY)
428                        ctrl_warn(ctrl, "Slot already registered by another "
429                                  "hotplug driver\n");
430                else
431                        ctrl_err(ctrl, "Slot initialization failed\n");
432                goto err_out_release_ctlr;
433        }
434
435        /* Check if slot is occupied */
436        t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
437        t_slot->hpc_ops->get_adapter_status(t_slot, &value);
438        if (value) {
439                if (pciehp_force)
440                        pciehp_enable_slot(t_slot);
441        } else {
442                /* Power off slot if not occupied */
443                if (POWER_CTRL(ctrl)) {
444                        rc = t_slot->hpc_ops->power_off_slot(t_slot);
445                        if (rc)
446                                goto err_out_free_ctrl_slot;
447                }
448        }
449
450        return 0;
451
452err_out_free_ctrl_slot:
453        cleanup_slots(ctrl);
454err_out_release_ctlr:
455        ctrl->hpc_ops->release_ctlr(ctrl);
456err_out_none:
457        return -ENODEV;
458}
459
460static void pciehp_remove (struct pcie_device *dev)
461{
462        struct controller *ctrl = get_service_data(dev);
463
464        cleanup_slots(ctrl);
465        ctrl->hpc_ops->release_ctlr(ctrl);
466}
467
468#ifdef CONFIG_PM
469static int pciehp_suspend (struct pcie_device *dev, pm_message_t state)
470{
471        dev_info(&dev->device, "%s ENTRY\n", __func__);
472        return 0;
473}
474
475static int pciehp_resume (struct pcie_device *dev)
476{
477        dev_info(&dev->device, "%s ENTRY\n", __func__);
478        if (pciehp_force) {
479                struct controller *ctrl = get_service_data(dev);
480                struct slot *t_slot;
481                u8 status;
482
483                /* reinitialize the chipset's event detection logic */
484                pcie_enable_notification(ctrl);
485
486                t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
487
488                /* Check if slot is occupied */
489                t_slot->hpc_ops->get_adapter_status(t_slot, &status);
490                if (status)
491                        pciehp_enable_slot(t_slot);
492                else
493                        pciehp_disable_slot(t_slot);
494        }
495        return 0;
496}
497#endif
498
499static struct pcie_port_service_id port_pci_ids[] = { {
500        .vendor = PCI_ANY_ID,
501        .device = PCI_ANY_ID,
502        .port_type = PCIE_ANY_PORT,
503        .service_type = PCIE_PORT_SERVICE_HP,
504        .driver_data =        0,
505        }, { /* end: all zeroes */ }
506};
507
508static struct pcie_port_service_driver hpdriver_portdrv = {
509        .name                = PCIE_MODULE_NAME,
510        .id_table        = &port_pci_ids[0],
511
512        .probe                = pciehp_probe,
513        .remove                = pciehp_remove,
514
515#ifdef        CONFIG_PM
516        .suspend        = pciehp_suspend,
517        .resume                = pciehp_resume,
518#endif        /* PM */
519};
520
521static int __init pcied_init(void)
522{
523        int retval = 0;
524
525        retval = pcie_port_service_register(&hpdriver_portdrv);
526         dbg("pcie_port_service_register = %d\n", retval);
527          info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
528         if (retval)
529                dbg("Failure to register service\n");
530        return retval;
531}
532
533static void __exit pcied_cleanup(void)
534{
535        dbg("unload_pciehpd()\n");
536        pcie_port_service_unregister(&hpdriver_portdrv);
537        info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
538}
539
540module_init(pcied_init);
541module_exit(pcied_cleanup);