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/kernel.h> 32#include <linux/types.h> 33#include <linux/slab.h> 34#include <linux/pci.h> 35#include "../pci.h" 36#include "pciehp.h" 37 38static void interrupt_event_handler(struct work_struct *work); 39 40void pciehp_queue_interrupt_event(struct slot *p_slot, u32 event_type) 41{ 42 struct event_info *info; 43 44 info = kmalloc(sizeof(*info), GFP_ATOMIC); 45 if (!info) { 46 ctrl_err(p_slot->ctrl, "dropped event %d (ENOMEM)\n", event_type); 47 return; 48 } 49 50 INIT_WORK(&info->work, interrupt_event_handler); 51 info->event_type = event_type; 52 info->p_slot = p_slot; 53 queue_work(p_slot->wq, &info->work); 54} 55 56/* The following routines constitute the bulk of the 57 hotplug controller logic 58 */ 59 60static void set_slot_off(struct controller *ctrl, struct slot *pslot) 61{ 62 /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ 63 if (POWER_CTRL(ctrl)) { 64 pciehp_power_off_slot(pslot); 65 66 /* 67 * After turning power off, we must wait for at least 1 second 68 * before taking any action that relies on power having been 69 * removed from the slot/adapter. 70 */ 71 msleep(1000); 72 } 73 74 pciehp_green_led_off(pslot); 75 pciehp_set_attention_status(pslot, 1); 76} 77 78/** 79 * board_added - Called after a board has been added to the system. 80 * @p_slot: &slot where board is added 81 * 82 * Turns power on for the board. 83 * Configures board. 84 */ 85static int board_added(struct slot *p_slot) 86{ 87 int retval = 0; 88 struct controller *ctrl = p_slot->ctrl; 89 struct pci_bus *parent = ctrl->pcie->port->subordinate; 90 91 if (POWER_CTRL(ctrl)) { 92 /* Power on slot */ 93 retval = pciehp_power_on_slot(p_slot); 94 if (retval) 95 return retval; 96 } 97 98 pciehp_green_led_blink(p_slot); 99 100 /* Check link training status */ 101 retval = pciehp_check_link_status(ctrl); 102 if (retval) { 103 ctrl_err(ctrl, "Failed to check link status\n"); 104 goto err_exit; 105 } 106 107 /* Check for a power fault */ 108 if (ctrl->power_fault_detected || pciehp_query_power_fault(p_slot)) { 109 ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot)); 110 retval = -EIO; 111 goto err_exit; 112 } 113 114 retval = pciehp_configure_device(p_slot); 115 if (retval) { 116 ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n", 117 pci_domain_nr(parent), parent->number); 118 if (retval != -EEXIST) 119 goto err_exit; 120 } 121 122 pciehp_green_led_on(p_slot); 123 return 0; 124 125err_exit: 126 set_slot_off(ctrl, p_slot); 127 return retval; 128} 129 130/** 131 * remove_board - Turns off slot and LEDs 132 * @p_slot: slot where board is being removed 133 */ 134static int remove_board(struct slot *p_slot) 135{ 136 int retval; 137 struct controller *ctrl = p_slot->ctrl; 138 139 retval = pciehp_unconfigure_device(p_slot); 140 if (retval) 141 return retval; 142 143 if (POWER_CTRL(ctrl)) { 144 pciehp_power_off_slot(p_slot); 145 146 /* 147 * After turning power off, we must wait for at least 1 second 148 * before taking any action that relies on power having been 149 * removed from the slot/adapter. 150 */ 151 msleep(1000); 152 } 153 154 /* turn off Green LED */ 155 pciehp_green_led_off(p_slot); 156 return 0; 157} 158 159struct power_work_info { 160 struct slot *p_slot; 161 struct work_struct work; 162 unsigned int req; 163#define DISABLE_REQ 0 164#define ENABLE_REQ 1 165}; 166 167/** 168 * pciehp_power_thread - handle pushbutton events 169 * @work: &struct work_struct describing work to be done 170 * 171 * Scheduled procedure to handle blocking stuff for the pushbuttons. 172 * Handles all pending events and exits. 173 */ 174static void pciehp_power_thread(struct work_struct *work) 175{ 176 struct power_work_info *info = 177 container_of(work, struct power_work_info, work); 178 struct slot *p_slot = info->p_slot; 179 int ret; 180 181 switch (info->req) { 182 case DISABLE_REQ: 183 mutex_lock(&p_slot->hotplug_lock); 184 pciehp_disable_slot(p_slot); 185 mutex_unlock(&p_slot->hotplug_lock); 186 mutex_lock(&p_slot->lock); 187 p_slot->state = STATIC_STATE; 188 mutex_unlock(&p_slot->lock); 189 break; 190 case ENABLE_REQ: 191 mutex_lock(&p_slot->hotplug_lock); 192 ret = pciehp_enable_slot(p_slot); 193 mutex_unlock(&p_slot->hotplug_lock); 194 if (ret) 195 pciehp_green_led_off(p_slot); 196 mutex_lock(&p_slot->lock); 197 p_slot->state = STATIC_STATE; 198 mutex_unlock(&p_slot->lock); 199 break; 200 default: 201 break; 202 } 203 204 kfree(info); 205} 206 207static void pciehp_queue_power_work(struct slot *p_slot, int req) 208{ 209 struct power_work_info *info; 210 211 p_slot->state = (req == ENABLE_REQ) ? POWERON_STATE : POWEROFF_STATE; 212 213 info = kmalloc(sizeof(*info), GFP_KERNEL); 214 if (!info) { 215 ctrl_err(p_slot->ctrl, "no memory to queue %s request\n", 216 (req == ENABLE_REQ) ? "poweron" : "poweroff"); 217 return; 218 } 219 info->p_slot = p_slot; 220 INIT_WORK(&info->work, pciehp_power_thread); 221 info->req = req; 222 queue_work(p_slot->wq, &info->work); 223} 224 225void pciehp_queue_pushbutton_work(struct work_struct *work) 226{ 227 struct slot *p_slot = container_of(work, struct slot, work.work); 228 229 mutex_lock(&p_slot->lock); 230 switch (p_slot->state) { 231 case BLINKINGOFF_STATE: 232 pciehp_queue_power_work(p_slot, DISABLE_REQ); 233 break; 234 case BLINKINGON_STATE: 235 pciehp_queue_power_work(p_slot, ENABLE_REQ); 236 break; 237 default: 238 break; 239 } 240 mutex_unlock(&p_slot->lock); 241} 242 243/* 244 * Note: This function must be called with slot->lock held 245 */ 246static void handle_button_press_event(struct slot *p_slot) 247{ 248 struct controller *ctrl = p_slot->ctrl; 249 u8 getstatus; 250 251 switch (p_slot->state) { 252 case STATIC_STATE: 253 pciehp_get_power_status(p_slot, &getstatus); 254 if (getstatus) { 255 p_slot->state = BLINKINGOFF_STATE; 256 ctrl_info(ctrl, "PCI slot #%s - powering off due to button press\n", 257 slot_name(p_slot)); 258 } else { 259 p_slot->state = BLINKINGON_STATE; 260 ctrl_info(ctrl, "PCI slot #%s - powering on due to button press\n", 261 slot_name(p_slot)); 262 } 263 /* blink green LED and turn off amber */ 264 pciehp_green_led_blink(p_slot); 265 pciehp_set_attention_status(p_slot, 0); 266 queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ); 267 break; 268 case BLINKINGOFF_STATE: 269 case BLINKINGON_STATE: 270 /* 271 * Cancel if we are still blinking; this means that we 272 * press the attention again before the 5 sec. limit 273 * expires to cancel hot-add or hot-remove 274 */ 275 ctrl_info(ctrl, "Button cancel on Slot(%s)\n", slot_name(p_slot)); 276 cancel_delayed_work(&p_slot->work); 277 if (p_slot->state == BLINKINGOFF_STATE) 278 pciehp_green_led_on(p_slot); 279 else 280 pciehp_green_led_off(p_slot); 281 pciehp_set_attention_status(p_slot, 0); 282 ctrl_info(ctrl, "PCI slot #%s - action canceled due to button press\n", 283 slot_name(p_slot)); 284 p_slot->state = STATIC_STATE; 285 break; 286 case POWEROFF_STATE: 287 case POWERON_STATE: 288 /* 289 * Ignore if the slot is on power-on or power-off state; 290 * this means that the previous attention button action 291 * to hot-add or hot-remove is undergoing 292 */ 293 ctrl_info(ctrl, "Button ignore on Slot(%s)\n", slot_name(p_slot)); 294 break; 295 default: 296 ctrl_warn(ctrl, "ignoring invalid state %#x\n", p_slot->state); 297 break; 298 } 299} 300 301/* 302 * Note: This function must be called with slot->lock held 303 */ 304static void handle_surprise_event(struct slot *p_slot) 305{ 306 u8 getstatus; 307 308 pciehp_get_adapter_status(p_slot, &getstatus); 309 if (!getstatus) 310 pciehp_queue_power_work(p_slot, DISABLE_REQ); 311 else 312 pciehp_queue_power_work(p_slot, ENABLE_REQ); 313} 314 315/* 316 * Note: This function must be called with slot->lock held 317 */ 318static void handle_link_event(struct slot *p_slot, u32 event) 319{ 320 struct controller *ctrl = p_slot->ctrl; 321 322 switch (p_slot->state) { 323 case BLINKINGON_STATE: 324 case BLINKINGOFF_STATE: 325 cancel_delayed_work(&p_slot->work); 326 /* Fall through */ 327 case STATIC_STATE: 328 pciehp_queue_power_work(p_slot, event == INT_LINK_UP ? 329 ENABLE_REQ : DISABLE_REQ); 330 break; 331 case POWERON_STATE: 332 if (event == INT_LINK_UP) { 333 ctrl_info(ctrl, 334 "Link Up event ignored on slot(%s): already powering on\n", 335 slot_name(p_slot)); 336 } else { 337 ctrl_info(ctrl, 338 "Link Down event queued on slot(%s): currently getting powered on\n", 339 slot_name(p_slot)); 340 pciehp_queue_power_work(p_slot, DISABLE_REQ); 341 } 342 break; 343 case POWEROFF_STATE: 344 if (event == INT_LINK_UP) { 345 ctrl_info(ctrl, 346 "Link Up event queued on slot(%s): currently getting powered off\n", 347 slot_name(p_slot)); 348 pciehp_queue_power_work(p_slot, ENABLE_REQ); 349 } else { 350 ctrl_info(ctrl, 351 "Link Down event ignored on slot(%s): already powering off\n", 352 slot_name(p_slot)); 353 } 354 break; 355 default: 356 ctrl_err(ctrl, "ignoring invalid state %#x on slot(%s)\n", 357 p_slot->state, slot_name(p_slot)); 358 break; 359 } 360} 361 362static void interrupt_event_handler(struct work_struct *work) 363{ 364 struct event_info *info = container_of(work, struct event_info, work); 365 struct slot *p_slot = info->p_slot; 366 struct controller *ctrl = p_slot->ctrl; 367 368 mutex_lock(&p_slot->lock); 369 switch (info->event_type) { 370 case INT_BUTTON_PRESS: 371 handle_button_press_event(p_slot); 372 break; 373 case INT_POWER_FAULT: 374 if (!POWER_CTRL(ctrl)) 375 break; 376 pciehp_set_attention_status(p_slot, 1); 377 pciehp_green_led_off(p_slot); 378 break; 379 case INT_PRESENCE_ON: 380 handle_surprise_event(p_slot); 381 break; 382 case INT_PRESENCE_OFF: 383 /* 384 * Regardless of surprise capability, we need to 385 * definitely remove a card that has been pulled out! 386 */ 387 handle_surprise_event(p_slot); 388 break; 389 case INT_LINK_UP: 390 case INT_LINK_DOWN: 391 handle_link_event(p_slot, info->event_type); 392 break; 393 default: 394 break; 395 } 396 mutex_unlock(&p_slot->lock); 397 398 kfree(info); 399} 400 401/* 402 * Note: This function must be called with slot->hotplug_lock held 403 */ 404int pciehp_enable_slot(struct slot *p_slot) 405{ 406 u8 getstatus = 0; 407 int rc; 408 struct controller *ctrl = p_slot->ctrl; 409 410 pciehp_get_adapter_status(p_slot, &getstatus); 411 if (!getstatus) { 412 ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot)); 413 return -ENODEV; 414 } 415 if (MRL_SENS(p_slot->ctrl)) { 416 pciehp_get_latch_status(p_slot, &getstatus); 417 if (getstatus) { 418 ctrl_info(ctrl, "Latch open on slot(%s)\n", 419 slot_name(p_slot)); 420 return -ENODEV; 421 } 422 } 423 424 if (POWER_CTRL(p_slot->ctrl)) { 425 pciehp_get_power_status(p_slot, &getstatus); 426 if (getstatus) { 427 ctrl_info(ctrl, "Already enabled on slot(%s)\n", 428 slot_name(p_slot)); 429 return -EINVAL; 430 } 431 } 432 433 pciehp_get_latch_status(p_slot, &getstatus); 434 435 rc = board_added(p_slot); 436 if (rc) 437 pciehp_get_latch_status(p_slot, &getstatus); 438 439 return rc; 440} 441 442/* 443 * Note: This function must be called with slot->hotplug_lock held 444 */ 445int pciehp_disable_slot(struct slot *p_slot) 446{ 447 u8 getstatus = 0; 448 struct controller *ctrl = p_slot->ctrl; 449 450 if (!p_slot->ctrl) 451 return 1; 452 453 if (POWER_CTRL(p_slot->ctrl)) { 454 pciehp_get_power_status(p_slot, &getstatus); 455 if (!getstatus) { 456 ctrl_info(ctrl, "Already disabled on slot(%s)\n", 457 slot_name(p_slot)); 458 return -EINVAL; 459 } 460 } 461 462 return remove_board(p_slot); 463} 464 465int pciehp_sysfs_enable_slot(struct slot *p_slot) 466{ 467 int retval = -ENODEV; 468 struct controller *ctrl = p_slot->ctrl; 469 470 mutex_lock(&p_slot->lock); 471 switch (p_slot->state) { 472 case BLINKINGON_STATE: 473 cancel_delayed_work(&p_slot->work); 474 case STATIC_STATE: 475 p_slot->state = POWERON_STATE; 476 mutex_unlock(&p_slot->lock); 477 mutex_lock(&p_slot->hotplug_lock); 478 retval = pciehp_enable_slot(p_slot); 479 mutex_unlock(&p_slot->hotplug_lock); 480 mutex_lock(&p_slot->lock); 481 p_slot->state = STATIC_STATE; 482 break; 483 case POWERON_STATE: 484 ctrl_info(ctrl, "Slot %s is already in powering on state\n", 485 slot_name(p_slot)); 486 break; 487 case BLINKINGOFF_STATE: 488 case POWEROFF_STATE: 489 ctrl_info(ctrl, "Already enabled on slot %s\n", 490 slot_name(p_slot)); 491 break; 492 default: 493 ctrl_err(ctrl, "invalid state %#x on slot %s\n", 494 p_slot->state, slot_name(p_slot)); 495 break; 496 } 497 mutex_unlock(&p_slot->lock); 498 499 return retval; 500} 501 502int pciehp_sysfs_disable_slot(struct slot *p_slot) 503{ 504 int retval = -ENODEV; 505 struct controller *ctrl = p_slot->ctrl; 506 507 mutex_lock(&p_slot->lock); 508 switch (p_slot->state) { 509 case BLINKINGOFF_STATE: 510 cancel_delayed_work(&p_slot->work); 511 case STATIC_STATE: 512 p_slot->state = POWEROFF_STATE; 513 mutex_unlock(&p_slot->lock); 514 retval = pciehp_disable_slot(p_slot); 515 mutex_lock(&p_slot->lock); 516 p_slot->state = STATIC_STATE; 517 break; 518 case POWEROFF_STATE: 519 ctrl_info(ctrl, "Slot %s is already in powering off state\n", 520 slot_name(p_slot)); 521 break; 522 case BLINKINGON_STATE: 523 case POWERON_STATE: 524 ctrl_info(ctrl, "Already disabled on slot %s\n", 525 slot_name(p_slot)); 526 break; 527 default: 528 ctrl_err(ctrl, "invalid state %#x on slot %s\n", 529 p_slot->state, slot_name(p_slot)); 530 break; 531 } 532 mutex_unlock(&p_slot->lock); 533 534 return retval; 535} 536