shpchp_ctrl.c revision 66f1705580f796a3f52c092e9dc92cbe5df41dd6
1/*
2 * Standard 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/kernel.h>
32#include <linux/types.h>
33#include <linux/pci.h>
34#include <linux/workqueue.h>
35#include "../pci.h"
36#include "shpchp.h"
37
38static void interrupt_event_handler(struct work_struct *work);
39static int shpchp_enable_slot(struct slot *p_slot);
40static int shpchp_disable_slot(struct slot *p_slot);
41
42static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
43{
44	struct event_info *info;
45
46	info = kmalloc(sizeof(*info), GFP_ATOMIC);
47	if (!info)
48		return -ENOMEM;
49
50	info->event_type = event_type;
51	info->p_slot = p_slot;
52	INIT_WORK(&info->work, interrupt_event_handler);
53
54	schedule_work(&info->work);
55
56	return 0;
57}
58
59u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
60{
61	struct slot *p_slot;
62	u32 event_type;
63
64	/* Attention Button Change */
65	dbg("shpchp:  Attention button interrupt received.\n");
66
67	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
68	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
69
70	/*
71	 *  Button pressed - See if need to TAKE ACTION!!!
72	 */
73	info("Button pressed on Slot(%s)\n", slot_name(p_slot));
74	event_type = INT_BUTTON_PRESS;
75
76	queue_interrupt_event(p_slot, event_type);
77
78	return 0;
79
80}
81
82u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
83{
84	struct slot *p_slot;
85	u8 getstatus;
86	u32 event_type;
87
88	/* Switch Change */
89	dbg("shpchp:  Switch interrupt received.\n");
90
91	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
92	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
93	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
94	dbg("%s: Card present %x Power status %x\n", __func__,
95		p_slot->presence_save, p_slot->pwr_save);
96
97	if (getstatus) {
98		/*
99		 * Switch opened
100		 */
101		info("Latch open on Slot(%s)\n", slot_name(p_slot));
102		event_type = INT_SWITCH_OPEN;
103		if (p_slot->pwr_save && p_slot->presence_save) {
104			event_type = INT_POWER_FAULT;
105			err("Surprise Removal of card\n");
106		}
107	} else {
108		/*
109		 *  Switch closed
110		 */
111		info("Latch close on Slot(%s)\n", slot_name(p_slot));
112		event_type = INT_SWITCH_CLOSE;
113	}
114
115	queue_interrupt_event(p_slot, event_type);
116
117	return 1;
118}
119
120u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
121{
122	struct slot *p_slot;
123	u32 event_type;
124
125	/* Presence Change */
126	dbg("shpchp:  Presence/Notify input change.\n");
127
128	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
129
130	/*
131	 * Save the presence state
132	 */
133	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
134	if (p_slot->presence_save) {
135		/*
136		 * Card Present
137		 */
138		info("Card present on Slot(%s)\n", slot_name(p_slot));
139		event_type = INT_PRESENCE_ON;
140	} else {
141		/*
142		 * Not Present
143		 */
144		info("Card not present on Slot(%s)\n", slot_name(p_slot));
145		event_type = INT_PRESENCE_OFF;
146	}
147
148	queue_interrupt_event(p_slot, event_type);
149
150	return 1;
151}
152
153u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
154{
155	struct slot *p_slot;
156	u32 event_type;
157
158	/* Power fault */
159	dbg("shpchp:  Power fault interrupt received.\n");
160
161	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
162
163	if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
164		/*
165		 * Power fault Cleared
166		 */
167		info("Power fault cleared on Slot(%s)\n", slot_name(p_slot));
168		p_slot->status = 0x00;
169		event_type = INT_POWER_FAULT_CLEAR;
170	} else {
171		/*
172		 *   Power fault
173		 */
174		info("Power fault on Slot(%s)\n", slot_name(p_slot));
175		event_type = INT_POWER_FAULT;
176		/* set power fault status for this board */
177		p_slot->status = 0xFF;
178		info("power fault bit %x set\n", hp_slot);
179	}
180
181	queue_interrupt_event(p_slot, event_type);
182
183	return 1;
184}
185
186/* The following routines constitute the bulk of the
187   hotplug controller logic
188 */
189static int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
190		enum pci_bus_speed speed)
191{
192	int rc = 0;
193
194	dbg("%s: change to speed %d\n", __func__, speed);
195	if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed))) {
196		err("%s: Issue of set bus speed mode command failed\n",
197		    __func__);
198		return WRONG_BUS_FREQUENCY;
199	}
200	return rc;
201}
202
203static int fix_bus_speed(struct controller *ctrl, struct slot *pslot,
204		u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp,
205		enum pci_bus_speed msp)
206{
207	int rc = 0;
208
209	/*
210	 * If other slots on the same bus are occupied, we cannot
211	 * change the bus speed.
212	 */
213	if (flag) {
214		if (asp < bsp) {
215			err("%s: speed of bus %x and adapter %x mismatch\n",
216			    __func__, bsp, asp);
217			rc = WRONG_BUS_FREQUENCY;
218		}
219		return rc;
220	}
221
222	if (asp < msp) {
223		if (bsp != asp)
224			rc = change_bus_speed(ctrl, pslot, asp);
225	} else {
226		if (bsp != msp)
227			rc = change_bus_speed(ctrl, pslot, msp);
228	}
229	return rc;
230}
231
232/**
233 * board_added - Called after a board has been added to the system.
234 * @p_slot: target &slot
235 *
236 * Turns power on for the board.
237 * Configures board.
238 */
239static int board_added(struct slot *p_slot)
240{
241	u8 hp_slot;
242	u8 slots_not_empty = 0;
243	int rc = 0;
244	enum pci_bus_speed asp, bsp, msp;
245	struct controller *ctrl = p_slot->ctrl;
246
247	hp_slot = p_slot->device - ctrl->slot_device_offset;
248
249	dbg("%s: p_slot->device, slot_offset, hp_slot = %d, %d ,%d\n",
250			__func__, p_slot->device,
251			ctrl->slot_device_offset, hp_slot);
252
253	/* Power on slot without connecting to bus */
254	rc = p_slot->hpc_ops->power_on_slot(p_slot);
255	if (rc) {
256		err("%s: Failed to power on slot\n", __func__);
257		return -1;
258	}
259
260	if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) {
261		if (slots_not_empty)
262			return WRONG_BUS_FREQUENCY;
263
264		if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) {
265			err("%s: Issue of set bus speed mode command failed\n", __func__);
266			return WRONG_BUS_FREQUENCY;
267		}
268
269		/* turn on board, blink green LED, turn off Amber LED */
270		if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
271			err("%s: Issue of Slot Enable command failed\n", __func__);
272			return rc;
273		}
274	}
275
276	rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &asp);
277	if (rc) {
278		err("%s: Can't get adapter speed or bus mode mismatch\n",
279		    __func__);
280		return WRONG_BUS_FREQUENCY;
281	}
282
283	rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bsp);
284	if (rc) {
285		err("%s: Can't get bus operation speed\n", __func__);
286		return WRONG_BUS_FREQUENCY;
287	}
288
289	rc = p_slot->hpc_ops->get_max_bus_speed(p_slot, &msp);
290	if (rc) {
291		err("%s: Can't get max bus operation speed\n", __func__);
292		msp = bsp;
293	}
294
295	/* Check if there are other slots or devices on the same bus */
296	if (!list_empty(&ctrl->pci_dev->subordinate->devices))
297		slots_not_empty = 1;
298
299	dbg("%s: slots_not_empty %d, adapter_speed %d, bus_speed %d, "
300	    "max_bus_speed %d\n", __func__, slots_not_empty, asp,
301	    bsp, msp);
302
303	rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, asp, bsp, msp);
304	if (rc)
305		return rc;
306
307	/* turn on board, blink green LED, turn off Amber LED */
308	if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
309		err("%s: Issue of Slot Enable command failed\n", __func__);
310		return rc;
311	}
312
313	/* Wait for ~1 second */
314	msleep(1000);
315
316	dbg("%s: slot status = %x\n", __func__, p_slot->status);
317	/* Check for a power fault */
318	if (p_slot->status == 0xFF) {
319		/* power fault occurred, but it was benign */
320		dbg("%s: power fault\n", __func__);
321		rc = POWER_FAILURE;
322		p_slot->status = 0;
323		goto err_exit;
324	}
325
326	if (shpchp_configure_device(p_slot)) {
327		err("Cannot add device at 0x%x:0x%x\n", p_slot->bus,
328				p_slot->device);
329		goto err_exit;
330	}
331
332	p_slot->status = 0;
333	p_slot->is_a_board = 0x01;
334	p_slot->pwr_save = 1;
335
336	p_slot->hpc_ops->green_led_on(p_slot);
337
338	return 0;
339
340err_exit:
341	/* turn off slot, turn on Amber LED, turn off Green LED */
342	rc = p_slot->hpc_ops->slot_disable(p_slot);
343	if (rc) {
344		err("%s: Issue of Slot Disable command failed\n", __func__);
345		return rc;
346	}
347
348	return(rc);
349}
350
351
352/**
353 * remove_board - Turns off slot and LEDs
354 * @p_slot: target &slot
355 */
356static int remove_board(struct slot *p_slot)
357{
358	struct controller *ctrl = p_slot->ctrl;
359	u8 hp_slot;
360	int rc;
361
362	if (shpchp_unconfigure_device(p_slot))
363		return(1);
364
365	hp_slot = p_slot->device - ctrl->slot_device_offset;
366	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
367
368	dbg("In %s, hp_slot = %d\n", __func__, hp_slot);
369
370	/* Change status to shutdown */
371	if (p_slot->is_a_board)
372		p_slot->status = 0x01;
373
374	/* turn off slot, turn on Amber LED, turn off Green LED */
375	rc = p_slot->hpc_ops->slot_disable(p_slot);
376	if (rc) {
377		err("%s: Issue of Slot Disable command failed\n", __func__);
378		return rc;
379	}
380
381	rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
382	if (rc) {
383		err("%s: Issue of Set Attention command failed\n", __func__);
384		return rc;
385	}
386
387	p_slot->pwr_save = 0;
388	p_slot->is_a_board = 0;
389
390	return 0;
391}
392
393
394struct pushbutton_work_info {
395	struct slot *p_slot;
396	struct work_struct work;
397};
398
399/**
400 * shpchp_pushbutton_thread - handle pushbutton events
401 * @work: &struct work_struct to be handled
402 *
403 * Scheduled procedure to handle blocking stuff for the pushbuttons.
404 * Handles all pending events and exits.
405 */
406static void shpchp_pushbutton_thread(struct work_struct *work)
407{
408	struct pushbutton_work_info *info =
409		container_of(work, struct pushbutton_work_info, work);
410	struct slot *p_slot = info->p_slot;
411
412	mutex_lock(&p_slot->lock);
413	switch (p_slot->state) {
414	case POWEROFF_STATE:
415		mutex_unlock(&p_slot->lock);
416		shpchp_disable_slot(p_slot);
417		mutex_lock(&p_slot->lock);
418		p_slot->state = STATIC_STATE;
419		break;
420	case POWERON_STATE:
421		mutex_unlock(&p_slot->lock);
422		if (shpchp_enable_slot(p_slot))
423			p_slot->hpc_ops->green_led_off(p_slot);
424		mutex_lock(&p_slot->lock);
425		p_slot->state = STATIC_STATE;
426		break;
427	default:
428		break;
429	}
430	mutex_unlock(&p_slot->lock);
431
432	kfree(info);
433}
434
435void shpchp_queue_pushbutton_work(struct work_struct *work)
436{
437	struct slot *p_slot = container_of(work, struct slot, work.work);
438	struct pushbutton_work_info *info;
439
440	info = kmalloc(sizeof(*info), GFP_KERNEL);
441	if (!info) {
442		err("%s: Cannot allocate memory\n", __func__);
443		return;
444	}
445	info->p_slot = p_slot;
446	INIT_WORK(&info->work, shpchp_pushbutton_thread);
447
448	mutex_lock(&p_slot->lock);
449	switch (p_slot->state) {
450	case BLINKINGOFF_STATE:
451		p_slot->state = POWEROFF_STATE;
452		break;
453	case BLINKINGON_STATE:
454		p_slot->state = POWERON_STATE;
455		break;
456	default:
457		goto out;
458	}
459	queue_work(shpchp_wq, &info->work);
460 out:
461	mutex_unlock(&p_slot->lock);
462}
463
464static int update_slot_info (struct slot *slot)
465{
466	struct hotplug_slot_info *info;
467	int result;
468
469	info = kmalloc(sizeof(*info), GFP_KERNEL);
470	if (!info)
471		return -ENOMEM;
472
473	slot->hpc_ops->get_power_status(slot, &(info->power_status));
474	slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
475	slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
476	slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
477
478	result = pci_hp_change_slot_info(slot->hotplug_slot, info);
479	kfree (info);
480	return result;
481}
482
483/*
484 * Note: This function must be called with slot->lock held
485 */
486static void handle_button_press_event(struct slot *p_slot)
487{
488	u8 getstatus;
489
490	switch (p_slot->state) {
491	case STATIC_STATE:
492		p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
493		if (getstatus) {
494			p_slot->state = BLINKINGOFF_STATE;
495			info("PCI slot #%s - powering off due to button "
496			     "press.\n", slot_name(p_slot));
497		} else {
498			p_slot->state = BLINKINGON_STATE;
499			info("PCI slot #%s - powering on due to button "
500			     "press.\n", slot_name(p_slot));
501		}
502		/* blink green LED and turn off amber */
503		p_slot->hpc_ops->green_led_blink(p_slot);
504		p_slot->hpc_ops->set_attention_status(p_slot, 0);
505
506		schedule_delayed_work(&p_slot->work, 5*HZ);
507		break;
508	case BLINKINGOFF_STATE:
509	case BLINKINGON_STATE:
510		/*
511		 * Cancel if we are still blinking; this means that we
512		 * press the attention again before the 5 sec. limit
513		 * expires to cancel hot-add or hot-remove
514		 */
515		info("Button cancel on Slot(%s)\n", slot_name(p_slot));
516		dbg("%s: button cancel\n", __func__);
517		cancel_delayed_work(&p_slot->work);
518		if (p_slot->state == BLINKINGOFF_STATE)
519			p_slot->hpc_ops->green_led_on(p_slot);
520		else
521			p_slot->hpc_ops->green_led_off(p_slot);
522		p_slot->hpc_ops->set_attention_status(p_slot, 0);
523		info("PCI slot #%s - action canceled due to button press\n",
524		     slot_name(p_slot));
525		p_slot->state = STATIC_STATE;
526		break;
527	case POWEROFF_STATE:
528	case POWERON_STATE:
529		/*
530		 * Ignore if the slot is on power-on or power-off state;
531		 * this means that the previous attention button action
532		 * to hot-add or hot-remove is undergoing
533		 */
534		info("Button ignore on Slot(%s)\n", slot_name(p_slot));
535		update_slot_info(p_slot);
536		break;
537	default:
538		warn("Not a valid state\n");
539		break;
540	}
541}
542
543static void interrupt_event_handler(struct work_struct *work)
544{
545	struct event_info *info = container_of(work, struct event_info, work);
546	struct slot *p_slot = info->p_slot;
547
548	mutex_lock(&p_slot->lock);
549	switch (info->event_type) {
550	case INT_BUTTON_PRESS:
551		handle_button_press_event(p_slot);
552		break;
553	case INT_POWER_FAULT:
554		dbg("%s: power fault\n", __func__);
555		p_slot->hpc_ops->set_attention_status(p_slot, 1);
556		p_slot->hpc_ops->green_led_off(p_slot);
557		break;
558	default:
559		update_slot_info(p_slot);
560		break;
561	}
562	mutex_unlock(&p_slot->lock);
563
564	kfree(info);
565}
566
567
568static int shpchp_enable_slot (struct slot *p_slot)
569{
570	u8 getstatus = 0;
571	int rc, retval = -ENODEV;
572
573	/* Check to see if (latch closed, card present, power off) */
574	mutex_lock(&p_slot->ctrl->crit_sect);
575	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
576	if (rc || !getstatus) {
577		info("No adapter on slot(%s)\n", slot_name(p_slot));
578		goto out;
579	}
580	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
581	if (rc || getstatus) {
582		info("Latch open on slot(%s)\n", slot_name(p_slot));
583		goto out;
584	}
585	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
586	if (rc || getstatus) {
587		info("Already enabled on slot(%s)\n", slot_name(p_slot));
588		goto out;
589	}
590
591	p_slot->is_a_board = 1;
592
593	/* We have to save the presence info for these slots */
594	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
595	p_slot->hpc_ops->get_power_status(p_slot, &(p_slot->pwr_save));
596	dbg("%s: p_slot->pwr_save %x\n", __func__, p_slot->pwr_save);
597	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
598
599	if(((p_slot->ctrl->pci_dev->vendor == PCI_VENDOR_ID_AMD) ||
600	    (p_slot->ctrl->pci_dev->device == PCI_DEVICE_ID_AMD_POGO_7458))
601	     && p_slot->ctrl->num_slots == 1) {
602		/* handle amd pogo errata; this must be done before enable  */
603		amd_pogo_errata_save_misc_reg(p_slot);
604		retval = board_added(p_slot);
605		/* handle amd pogo errata; this must be done after enable  */
606		amd_pogo_errata_restore_misc_reg(p_slot);
607	} else
608		retval = board_added(p_slot);
609
610	if (retval) {
611		p_slot->hpc_ops->get_adapter_status(p_slot,
612				&(p_slot->presence_save));
613		p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
614	}
615
616	update_slot_info(p_slot);
617 out:
618	mutex_unlock(&p_slot->ctrl->crit_sect);
619	return retval;
620}
621
622
623static int shpchp_disable_slot (struct slot *p_slot)
624{
625	u8 getstatus = 0;
626	int rc, retval = -ENODEV;
627
628	if (!p_slot->ctrl)
629		return -ENODEV;
630
631	/* Check to see if (latch closed, card present, power on) */
632	mutex_lock(&p_slot->ctrl->crit_sect);
633
634	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
635	if (rc || !getstatus) {
636		info("No adapter on slot(%s)\n", slot_name(p_slot));
637		goto out;
638	}
639	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
640	if (rc || getstatus) {
641		info("Latch open on slot(%s)\n", slot_name(p_slot));
642		goto out;
643	}
644	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
645	if (rc || !getstatus) {
646		info("Already disabled slot(%s)\n", slot_name(p_slot));
647		goto out;
648	}
649
650	retval = remove_board(p_slot);
651	update_slot_info(p_slot);
652 out:
653	mutex_unlock(&p_slot->ctrl->crit_sect);
654	return retval;
655}
656
657int shpchp_sysfs_enable_slot(struct slot *p_slot)
658{
659	int retval = -ENODEV;
660
661	mutex_lock(&p_slot->lock);
662	switch (p_slot->state) {
663	case BLINKINGON_STATE:
664		cancel_delayed_work(&p_slot->work);
665	case STATIC_STATE:
666		p_slot->state = POWERON_STATE;
667		mutex_unlock(&p_slot->lock);
668		retval = shpchp_enable_slot(p_slot);
669		mutex_lock(&p_slot->lock);
670		p_slot->state = STATIC_STATE;
671		break;
672	case POWERON_STATE:
673		info("Slot %s is already in powering on state\n",
674		     slot_name(p_slot));
675		break;
676	case BLINKINGOFF_STATE:
677	case POWEROFF_STATE:
678		info("Already enabled on slot %s\n", slot_name(p_slot));
679		break;
680	default:
681		err("Not a valid state on slot %s\n", slot_name(p_slot));
682		break;
683	}
684	mutex_unlock(&p_slot->lock);
685
686	return retval;
687}
688
689int shpchp_sysfs_disable_slot(struct slot *p_slot)
690{
691	int retval = -ENODEV;
692
693	mutex_lock(&p_slot->lock);
694	switch (p_slot->state) {
695	case BLINKINGOFF_STATE:
696		cancel_delayed_work(&p_slot->work);
697	case STATIC_STATE:
698		p_slot->state = POWEROFF_STATE;
699		mutex_unlock(&p_slot->lock);
700		retval = shpchp_disable_slot(p_slot);
701		mutex_lock(&p_slot->lock);
702		p_slot->state = STATIC_STATE;
703		break;
704	case POWEROFF_STATE:
705		info("Slot %s is already in powering off state\n",
706		     slot_name(p_slot));
707		break;
708	case BLINKINGON_STATE:
709	case POWERON_STATE:
710		info("Already disabled on slot %s\n", slot_name(p_slot));
711		break;
712	default:
713		err("Not a valid state on slot %s\n", slot_name(p_slot));
714		break;
715	}
716	mutex_unlock(&p_slot->lock);
717
718	return retval;
719}
720