pciehp_ctrl.c 15.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * PCI Express Hot Plug Controller Driver
 *
 * Copyright (C) 1995,2001 Compaq Computer Corporation
 * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
 * Copyright (C) 2001 IBM Corp.
 * Copyright (C) 2003-2004 Intel Corporation
 *
 * 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.
 *
26
 * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
L
Linus Torvalds 已提交
27 28 29 30 31 32 33 34
 *
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/smp_lock.h>
#include <linux/pci.h>
K
Kenji Kaneshige 已提交
35
#include <linux/workqueue.h>
L
Linus Torvalds 已提交
36 37 38
#include "../pci.h"
#include "pciehp.h"

K
Kenji Kaneshige 已提交
39
static void interrupt_event_handler(struct work_struct *work);
L
Linus Torvalds 已提交
40

K
Kenji Kaneshige 已提交
41
static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
42
{
K
Kenji Kaneshige 已提交
43 44 45 46 47 48 49 50 51 52 53 54 55
	struct event_info *info;

	info = kmalloc(sizeof(*info), GFP_ATOMIC);
	if (!info)
		return -ENOMEM;

	info->event_type = event_type;
	info->p_slot = p_slot;
	INIT_WORK(&info->work, interrupt_event_handler);

	schedule_work(&info->work);

	return 0;
56 57
}

58
u8 pciehp_handle_attention_button(struct slot *p_slot)
L
Linus Torvalds 已提交
59
{
K
Kenji Kaneshige 已提交
60
	u32 event_type;
L
Linus Torvalds 已提交
61 62 63 64 65 66 67

	/* Attention Button Change */
	dbg("pciehp:  Attention button interrupt received.\n");

	/*
	 *  Button pressed - See if need to TAKE ACTION!!!
	 */
K
Kenji Kaneshige 已提交
68 69
	info("Button pressed on Slot(%s)\n", p_slot->name);
	event_type = INT_BUTTON_PRESS;
L
Linus Torvalds 已提交
70

K
Kenji Kaneshige 已提交
71
	queue_interrupt_event(p_slot, event_type);
L
Linus Torvalds 已提交
72 73 74 75

	return 0;
}

76
u8 pciehp_handle_switch_change(struct slot *p_slot)
L
Linus Torvalds 已提交
77 78
{
	u8 getstatus;
K
Kenji Kaneshige 已提交
79
	u32 event_type;
L
Linus Torvalds 已提交
80 81 82 83 84 85 86 87 88

	/* Switch Change */
	dbg("pciehp:  Switch interrupt received.\n");

	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
	if (getstatus) {
		/*
		 * Switch opened
		 */
K
Kenji Kaneshige 已提交
89 90
		info("Latch open on Slot(%s)\n", p_slot->name);
		event_type = INT_SWITCH_OPEN;
L
Linus Torvalds 已提交
91 92 93 94
	} else {
		/*
		 *  Switch closed
		 */
K
Kenji Kaneshige 已提交
95 96
		info("Latch close on Slot(%s)\n", p_slot->name);
		event_type = INT_SWITCH_CLOSE;
L
Linus Torvalds 已提交
97 98
	}

K
Kenji Kaneshige 已提交
99
	queue_interrupt_event(p_slot, event_type);
L
Linus Torvalds 已提交
100

K
Kenji Kaneshige 已提交
101
	return 1;
L
Linus Torvalds 已提交
102 103
}

104
u8 pciehp_handle_presence_change(struct slot *p_slot)
L
Linus Torvalds 已提交
105
{
K
Kenji Kaneshige 已提交
106 107
	u32 event_type;
	u8 presence_save;
L
Linus Torvalds 已提交
108 109 110 111 112 113 114

	/* Presence Change */
	dbg("pciehp:  Presence/Notify input change.\n");

	/* Switch is open, assume a presence change
	 * Save the presence state
	 */
115 116
	p_slot->hpc_ops->get_adapter_status(p_slot, &presence_save);
	if (presence_save) {
L
Linus Torvalds 已提交
117 118 119
		/*
		 * Card Present
		 */
K
Kenji Kaneshige 已提交
120 121
		info("Card present on Slot(%s)\n", p_slot->name);
		event_type = INT_PRESENCE_ON;
L
Linus Torvalds 已提交
122 123 124 125
	} else {
		/*
		 * Not Present
		 */
K
Kenji Kaneshige 已提交
126 127
		info("Card not present on Slot(%s)\n", p_slot->name);
		event_type = INT_PRESENCE_OFF;
L
Linus Torvalds 已提交
128 129
	}

K
Kenji Kaneshige 已提交
130
	queue_interrupt_event(p_slot, event_type);
L
Linus Torvalds 已提交
131

K
Kenji Kaneshige 已提交
132
	return 1;
L
Linus Torvalds 已提交
133 134
}

135
u8 pciehp_handle_power_fault(struct slot *p_slot)
L
Linus Torvalds 已提交
136
{
K
Kenji Kaneshige 已提交
137
	u32 event_type;
L
Linus Torvalds 已提交
138 139 140 141 142 143 144 145

	/* power fault */
	dbg("pciehp:  Power fault interrupt received.\n");

	if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
		/*
		 * power fault Cleared
		 */
K
Kenji Kaneshige 已提交
146 147
		info("Power fault cleared on Slot(%s)\n", p_slot->name);
		event_type = INT_POWER_FAULT_CLEAR;
L
Linus Torvalds 已提交
148 149 150 151
	} else {
		/*
		 *   power fault
		 */
K
Kenji Kaneshige 已提交
152 153
		info("Power fault on Slot(%s)\n", p_slot->name);
		event_type = INT_POWER_FAULT;
154
		info("power fault bit %x set\n", 0);
L
Linus Torvalds 已提交
155 156
	}

K
Kenji Kaneshige 已提交
157 158 159
	queue_interrupt_event(p_slot, event_type);

	return 1;
L
Linus Torvalds 已提交
160 161
}

162
/* The following routines constitute the bulk of the
L
Linus Torvalds 已提交
163 164 165 166 167 168
   hotplug controller logic
 */

static void set_slot_off(struct controller *ctrl, struct slot * pslot)
{
	/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
169
	if (POWER_CTRL(ctrl)) {
170
		if (pslot->hpc_ops->power_off_slot(pslot)) {
171
			err("%s: Issue of Slot Power Off command failed\n",
172
			    __func__);
L
Linus Torvalds 已提交
173 174 175 176
			return;
		}
	}

177 178 179 180 181 182 183
	/*
	 * After turning power off, we must wait for at least 1 second
	 * before taking any action that relies on power having been
	 * removed from the slot/adapter.
	 */
	msleep(1000);

184
	if (PWR_LED(ctrl))
185
		pslot->hpc_ops->green_led_off(pslot);
L
Linus Torvalds 已提交
186

187
	if (ATTN_LED(ctrl)) {
188 189
		if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
			err("%s: Issue of Set Attention Led command failed\n",
190
			    __func__);
L
Linus Torvalds 已提交
191 192 193 194 195 196 197
			return;
		}
	}
}

/**
 * board_added - Called after a board has been added to the system.
R
Randy Dunlap 已提交
198
 * @p_slot: &slot where board is added
L
Linus Torvalds 已提交
199
 *
R
Randy Dunlap 已提交
200 201
 * Turns power on for the board.
 * Configures board.
L
Linus Torvalds 已提交
202
 */
203
static int board_added(struct slot *p_slot)
L
Linus Torvalds 已提交
204
{
205
	int retval = 0;
206
	struct controller *ctrl = p_slot->ctrl;
L
Linus Torvalds 已提交
207

208
	dbg("%s: slot device, slot offset, hp slot = %d, %d ,%d\n",
209
			__func__, p_slot->device,
210
			ctrl->slot_device_offset, p_slot->hp_slot);
L
Linus Torvalds 已提交
211

212
	if (POWER_CTRL(ctrl)) {
L
Linus Torvalds 已提交
213
		/* Power on slot */
214 215 216
		retval = p_slot->hpc_ops->power_on_slot(p_slot);
		if (retval)
			return retval;
L
Linus Torvalds 已提交
217
	}
218

219
	if (PWR_LED(ctrl))
L
Linus Torvalds 已提交
220 221 222
		p_slot->hpc_ops->green_led_blink(p_slot);

	/* Wait for ~1 second */
223
	msleep(1000);
L
Linus Torvalds 已提交
224

225 226 227
	/* Check link training status */
	retval = p_slot->hpc_ops->check_lnk_status(ctrl);
	if (retval) {
228
		err("%s: Failed to check link status\n", __func__);
L
Linus Torvalds 已提交
229
		set_slot_off(ctrl, p_slot);
230
		return retval;
L
Linus Torvalds 已提交
231 232 233
	}

	/* Check for a power fault */
234
	if (p_slot->hpc_ops->query_power_fault(p_slot)) {
235
		dbg("%s: power fault detected\n", __func__);
236
		retval = POWER_FAILURE;
237
		goto err_exit;
L
Linus Torvalds 已提交
238 239
	}

240 241
	retval = pciehp_configure_device(p_slot);
	if (retval) {
242
		err("Cannot add device 0x%x:%x\n", p_slot->bus,
243
		    p_slot->device);
244 245
		goto err_exit;
	}
L
Linus Torvalds 已提交
246

247 248 249 250 251
	/*
	 * Some PCI Express root ports require fixup after hot-plug operation.
	 */
	if (pcie_mch_quirk)
		pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
252
	if (PWR_LED(ctrl))
253
  		p_slot->hpc_ops->green_led_on(p_slot);
254

L
Linus Torvalds 已提交
255
	return 0;
256 257 258

err_exit:
	set_slot_off(ctrl, p_slot);
259
	return retval;
L
Linus Torvalds 已提交
260 261 262
}

/**
R
Randy Dunlap 已提交
263 264
 * remove_board - Turns off slot and LEDs
 * @p_slot: slot where board is being removed
L
Linus Torvalds 已提交
265
 */
266
static int remove_board(struct slot *p_slot)
L
Linus Torvalds 已提交
267
{
268
	int retval = 0;
269
	struct controller *ctrl = p_slot->ctrl;
L
Linus Torvalds 已提交
270

271 272 273
	retval = pciehp_unconfigure_device(p_slot);
	if (retval)
		return retval;
L
Linus Torvalds 已提交
274

275
	dbg("In %s, hp_slot = %d\n", __func__, p_slot->hp_slot);
L
Linus Torvalds 已提交
276

277
	if (POWER_CTRL(ctrl)) {
L
Linus Torvalds 已提交
278
		/* power off slot */
279 280 281
		retval = p_slot->hpc_ops->power_off_slot(p_slot);
		if (retval) {
			err("%s: Issue of Slot Disable command failed\n",
282
			    __func__);
283
			return retval;
L
Linus Torvalds 已提交
284 285 286
		}
	}

287 288 289 290 291 292 293
	/*
	 * After turning power off, we must wait for at least 1 second
	 * before taking any action that relies on power having been
	 * removed from the slot/adapter.
	 */
	msleep(1000);

294
	if (PWR_LED(ctrl))
L
Linus Torvalds 已提交
295 296 297 298 299 300
		/* turn off Green LED */
		p_slot->hpc_ops->green_led_off(p_slot);

	return 0;
}

K
Kenji Kaneshige 已提交
301 302 303 304
struct power_work_info {
	struct slot *p_slot;
	struct work_struct work;
};
L
Linus Torvalds 已提交
305 306

/**
R
Randy Dunlap 已提交
307 308
 * pciehp_power_thread - handle pushbutton events
 * @work: &struct work_struct describing work to be done
L
Linus Torvalds 已提交
309
 *
R
Randy Dunlap 已提交
310
 * Scheduled procedure to handle blocking stuff for the pushbuttons.
L
Linus Torvalds 已提交
311 312
 * Handles all pending events and exits.
 */
K
Kenji Kaneshige 已提交
313
static void pciehp_power_thread(struct work_struct *work)
L
Linus Torvalds 已提交
314
{
K
Kenji Kaneshige 已提交
315 316 317 318 319 320 321 322 323
	struct power_work_info *info =
		container_of(work, struct power_work_info, work);
	struct slot *p_slot = info->p_slot;

	mutex_lock(&p_slot->lock);
	switch (p_slot->state) {
	case POWEROFF_STATE:
		mutex_unlock(&p_slot->lock);
		dbg("%s: disabling bus:device(%x:%x)\n",
324
		    __func__, p_slot->bus, p_slot->device);
L
Linus Torvalds 已提交
325
		pciehp_disable_slot(p_slot);
K
Kenji Kaneshige 已提交
326
		mutex_lock(&p_slot->lock);
L
Linus Torvalds 已提交
327
		p_slot->state = STATIC_STATE;
K
Kenji Kaneshige 已提交
328 329 330
		break;
	case POWERON_STATE:
		mutex_unlock(&p_slot->lock);
331
		if (pciehp_enable_slot(p_slot) &&
332
		    PWR_LED(p_slot->ctrl))
L
Linus Torvalds 已提交
333
			p_slot->hpc_ops->green_led_off(p_slot);
K
Kenji Kaneshige 已提交
334
		mutex_lock(&p_slot->lock);
L
Linus Torvalds 已提交
335
		p_slot->state = STATIC_STATE;
K
Kenji Kaneshige 已提交
336 337 338
		break;
	default:
		break;
L
Linus Torvalds 已提交
339
	}
K
Kenji Kaneshige 已提交
340
	mutex_unlock(&p_slot->lock);
L
Linus Torvalds 已提交
341

K
Kenji Kaneshige 已提交
342
	kfree(info);
L
Linus Torvalds 已提交
343 344
}

345
void pciehp_queue_pushbutton_work(struct work_struct *work)
L
Linus Torvalds 已提交
346
{
K
Kenji Kaneshige 已提交
347 348
	struct slot *p_slot = container_of(work, struct slot, work.work);
	struct power_work_info *info;
L
Linus Torvalds 已提交
349

K
Kenji Kaneshige 已提交
350 351
	info = kmalloc(sizeof(*info), GFP_KERNEL);
	if (!info) {
352
		err("%s: Cannot allocate memory\n", __func__);
L
Linus Torvalds 已提交
353 354
		return;
	}
K
Kenji Kaneshige 已提交
355 356
	info->p_slot = p_slot;
	INIT_WORK(&info->work, pciehp_power_thread);
L
Linus Torvalds 已提交
357

K
Kenji Kaneshige 已提交
358 359 360
	mutex_lock(&p_slot->lock);
	switch (p_slot->state) {
	case BLINKINGOFF_STATE:
L
Linus Torvalds 已提交
361
		p_slot->state = POWEROFF_STATE;
K
Kenji Kaneshige 已提交
362 363
		break;
	case BLINKINGON_STATE:
L
Linus Torvalds 已提交
364
		p_slot->state = POWERON_STATE;
K
Kenji Kaneshige 已提交
365 366 367
		break;
	default:
		goto out;
L
Linus Torvalds 已提交
368
	}
K
Kenji Kaneshige 已提交
369 370 371
	queue_work(pciehp_wq, &info->work);
 out:
	mutex_unlock(&p_slot->lock);
L
Linus Torvalds 已提交
372 373 374 375 376 377 378
}

static int update_slot_info(struct slot *slot)
{
	struct hotplug_slot_info *info;
	int result;

K
Kenji Kaneshige 已提交
379
	info = kmalloc(sizeof(*info), GFP_KERNEL);
L
Linus Torvalds 已提交
380 381 382 383 384 385 386 387 388 389 390 391 392
	if (!info)
		return -ENOMEM;

	slot->hpc_ops->get_power_status(slot, &(info->power_status));
	slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
	slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
	slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));

	result = pci_hp_change_slot_info(slot->hotplug_slot, info);
	kfree (info);
	return result;
}

K
Kenji Kaneshige 已提交
393 394 395 396
/*
 * Note: This function must be called with slot->lock held
 */
static void handle_button_press_event(struct slot *p_slot)
L
Linus Torvalds 已提交
397
{
K
Kenji Kaneshige 已提交
398
	struct controller *ctrl = p_slot->ctrl;
L
Linus Torvalds 已提交
399 400
	u8 getstatus;

K
Kenji Kaneshige 已提交
401 402 403 404 405 406 407 408 409 410 411 412 413
	switch (p_slot->state) {
	case STATIC_STATE:
		p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
		if (getstatus) {
			p_slot->state = BLINKINGOFF_STATE;
			info("PCI slot #%s - powering off due to button "
			     "press.\n", p_slot->name);
		} else {
			p_slot->state = BLINKINGON_STATE;
			info("PCI slot #%s - powering on due to button "
			     "press.\n", p_slot->name);
		}
		/* blink green LED and turn off amber */
414
		if (PWR_LED(ctrl))
K
Kenji Kaneshige 已提交
415
			p_slot->hpc_ops->green_led_blink(p_slot);
416
		if (ATTN_LED(ctrl))
K
Kenji Kaneshige 已提交
417 418 419 420 421 422 423 424 425 426 427 428
			p_slot->hpc_ops->set_attention_status(p_slot, 0);

		schedule_delayed_work(&p_slot->work, 5*HZ);
		break;
	case BLINKINGOFF_STATE:
	case BLINKINGON_STATE:
		/*
		 * Cancel if we are still blinking; this means that we
		 * press the attention again before the 5 sec. limit
		 * expires to cancel hot-add or hot-remove
		 */
		info("Button cancel on Slot(%s)\n", p_slot->name);
429
		dbg("%s: button cancel\n", __func__);
K
Kenji Kaneshige 已提交
430 431
		cancel_delayed_work(&p_slot->work);
		if (p_slot->state == BLINKINGOFF_STATE) {
432
			if (PWR_LED(ctrl))
K
Kenji Kaneshige 已提交
433 434
				p_slot->hpc_ops->green_led_on(p_slot);
		} else {
435
			if (PWR_LED(ctrl))
K
Kenji Kaneshige 已提交
436 437
				p_slot->hpc_ops->green_led_off(p_slot);
		}
438
		if (ATTN_LED(ctrl))
K
Kenji Kaneshige 已提交
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
			p_slot->hpc_ops->set_attention_status(p_slot, 0);
		info("PCI slot #%s - action canceled due to button press\n",
		     p_slot->name);
		p_slot->state = STATIC_STATE;
		break;
	case POWEROFF_STATE:
	case POWERON_STATE:
		/*
		 * Ignore if the slot is on power-on or power-off state;
		 * this means that the previous attention button action
		 * to hot-add or hot-remove is undergoing
		 */
		info("Button ignore on Slot(%s)\n", p_slot->name);
		update_slot_info(p_slot);
		break;
	default:
		warn("Not a valid state\n");
		break;
L
Linus Torvalds 已提交
457 458 459
	}
}

K
Kenji Kaneshige 已提交
460 461 462 463 464 465 466 467 468 469
/*
 * Note: This function must be called with slot->lock held
 */
static void handle_surprise_event(struct slot *p_slot)
{
	u8 getstatus;
	struct power_work_info *info;

	info = kmalloc(sizeof(*info), GFP_KERNEL);
	if (!info) {
470
		err("%s: Cannot allocate memory\n", __func__);
K
Kenji Kaneshige 已提交
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
		return;
	}
	info->p_slot = p_slot;
	INIT_WORK(&info->work, pciehp_power_thread);

	p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
	if (!getstatus)
		p_slot->state = POWEROFF_STATE;
	else
		p_slot->state = POWERON_STATE;

	queue_work(pciehp_wq, &info->work);
}

static void interrupt_event_handler(struct work_struct *work)
{
	struct event_info *info = container_of(work, struct event_info, work);
	struct slot *p_slot = info->p_slot;
	struct controller *ctrl = p_slot->ctrl;

	mutex_lock(&p_slot->lock);
	switch (info->event_type) {
	case INT_BUTTON_PRESS:
		handle_button_press_event(p_slot);
		break;
	case INT_POWER_FAULT:
497
		if (!POWER_CTRL(ctrl))
K
Kenji Kaneshige 已提交
498
			break;
499
		if (ATTN_LED(ctrl))
K
Kenji Kaneshige 已提交
500
			p_slot->hpc_ops->set_attention_status(p_slot, 1);
501
		if (PWR_LED(ctrl))
K
Kenji Kaneshige 已提交
502 503 504 505
			p_slot->hpc_ops->green_led_off(p_slot);
		break;
	case INT_PRESENCE_ON:
	case INT_PRESENCE_OFF:
506
		if (!HP_SUPR_RM(ctrl))
K
Kenji Kaneshige 已提交
507 508 509 510 511 512 513 514 515 516 517 518 519 520
			break;
		dbg("Surprise Removal\n");
		update_slot_info(p_slot);
		handle_surprise_event(p_slot);
		break;
	default:
		update_slot_info(p_slot);
		break;
	}
	mutex_unlock(&p_slot->lock);

	kfree(info);
}

L
Linus Torvalds 已提交
521 522 523 524 525 526
int pciehp_enable_slot(struct slot *p_slot)
{
	u8 getstatus = 0;
	int rc;

	/* Check to see if (latch closed, card present, power off) */
527
	mutex_lock(&p_slot->ctrl->crit_sect);
L
Linus Torvalds 已提交
528 529 530

	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
	if (rc || !getstatus) {
531
		info("%s: no adapter on slot(%s)\n", __func__,
K
Kenji Kaneshige 已提交
532
		     p_slot->name);
533
		mutex_unlock(&p_slot->ctrl->crit_sect);
534
		return -ENODEV;
L
Linus Torvalds 已提交
535
	}
536
	if (MRL_SENS(p_slot->ctrl)) {
L
Linus Torvalds 已提交
537 538
		rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
		if (rc || getstatus) {
539
			info("%s: latch open on slot(%s)\n", __func__,
K
Kenji Kaneshige 已提交
540
			     p_slot->name);
541
			mutex_unlock(&p_slot->ctrl->crit_sect);
542
			return -ENODEV;
L
Linus Torvalds 已提交
543 544
		}
	}
545

546
	if (POWER_CTRL(p_slot->ctrl)) {
L
Linus Torvalds 已提交
547 548
		rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
		if (rc || getstatus) {
549
			info("%s: already enabled on slot(%s)\n", __func__,
K
Kenji Kaneshige 已提交
550
			     p_slot->name);
551
			mutex_unlock(&p_slot->ctrl->crit_sect);
552
			return -EINVAL;
L
Linus Torvalds 已提交
553 554 555 556 557
		}
	}

	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);

558
	rc = board_added(p_slot);
L
Linus Torvalds 已提交
559 560 561 562
	if (rc) {
		p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
	}

563
	update_slot_info(p_slot);
L
Linus Torvalds 已提交
564

K
Kenji Kaneshige 已提交
565
	mutex_unlock(&p_slot->ctrl->crit_sect);
L
Linus Torvalds 已提交
566 567 568 569 570 571 572 573 574 575 576 577 578
	return rc;
}


int pciehp_disable_slot(struct slot *p_slot)
{
	u8 getstatus = 0;
	int ret = 0;

	if (!p_slot->ctrl)
		return 1;

	/* Check to see if (latch closed, card present, power on) */
579
	mutex_lock(&p_slot->ctrl->crit_sect);
L
Linus Torvalds 已提交
580

581
	if (!HP_SUPR_RM(p_slot->ctrl)) {
L
Linus Torvalds 已提交
582 583
		ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
		if (ret || !getstatus) {
584
			info("%s: no adapter on slot(%s)\n", __func__,
K
Kenji Kaneshige 已提交
585
			     p_slot->name);
586
			mutex_unlock(&p_slot->ctrl->crit_sect);
587
			return -ENODEV;
L
Linus Torvalds 已提交
588 589 590
		}
	}

591
	if (MRL_SENS(p_slot->ctrl)) {
L
Linus Torvalds 已提交
592 593
		ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
		if (ret || getstatus) {
594
			info("%s: latch open on slot(%s)\n", __func__,
K
Kenji Kaneshige 已提交
595
			     p_slot->name);
596
			mutex_unlock(&p_slot->ctrl->crit_sect);
597
			return -ENODEV;
L
Linus Torvalds 已提交
598 599 600
		}
	}

601
	if (POWER_CTRL(p_slot->ctrl)) {
L
Linus Torvalds 已提交
602 603
		ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
		if (ret || !getstatus) {
604
			info("%s: already disabled slot(%s)\n", __func__,
K
Kenji Kaneshige 已提交
605
			     p_slot->name);
606
			mutex_unlock(&p_slot->ctrl->crit_sect);
607
			return -EINVAL;
L
Linus Torvalds 已提交
608 609 610
		}
	}

611 612
	ret = remove_board(p_slot);
	update_slot_info(p_slot);
K
Kenji Kaneshige 已提交
613 614

	mutex_unlock(&p_slot->ctrl->crit_sect);
615
	return ret;
L
Linus Torvalds 已提交
616 617
}

K
Kenji Kaneshige 已提交
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
int pciehp_sysfs_enable_slot(struct slot *p_slot)
{
	int retval = -ENODEV;

	mutex_lock(&p_slot->lock);
	switch (p_slot->state) {
	case BLINKINGON_STATE:
		cancel_delayed_work(&p_slot->work);
	case STATIC_STATE:
		p_slot->state = POWERON_STATE;
		mutex_unlock(&p_slot->lock);
		retval = pciehp_enable_slot(p_slot);
		mutex_lock(&p_slot->lock);
		p_slot->state = STATIC_STATE;
		break;
	case POWERON_STATE:
		info("Slot %s is already in powering on state\n",
		     p_slot->name);
		break;
	case BLINKINGOFF_STATE:
	case POWEROFF_STATE:
		info("Already enabled on slot %s\n", p_slot->name);
		break;
	default:
		err("Not a valid state on slot %s\n", p_slot->name);
		break;
	}
	mutex_unlock(&p_slot->lock);

	return retval;
}

int pciehp_sysfs_disable_slot(struct slot *p_slot)
{
	int retval = -ENODEV;

	mutex_lock(&p_slot->lock);
	switch (p_slot->state) {
	case BLINKINGOFF_STATE:
		cancel_delayed_work(&p_slot->work);
	case STATIC_STATE:
		p_slot->state = POWEROFF_STATE;
		mutex_unlock(&p_slot->lock);
		retval = pciehp_disable_slot(p_slot);
		mutex_lock(&p_slot->lock);
		p_slot->state = STATIC_STATE;
		break;
	case POWEROFF_STATE:
		info("Slot %s is already in powering off state\n",
		     p_slot->name);
		break;
	case BLINKINGON_STATE:
	case POWERON_STATE:
		info("Already disabled on slot %s\n", p_slot->name);
		break;
	default:
		err("Not a valid state on slot %s\n", p_slot->name);
		break;
	}
	mutex_unlock(&p_slot->lock);

	return retval;
}