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 38 static void interrupt_event_handler(struct work_struct *work); 39 40 void 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 60 static 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 */ 85 static 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 125 err_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 */ 134 static 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 159 struct 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 */ 174 static 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 207 void pciehp_queue_pushbutton_work(struct work_struct *work) 208 { 209 struct slot *p_slot = container_of(work, struct slot, work.work); 210 struct power_work_info *info; 211 212 info = kmalloc(sizeof(*info), GFP_KERNEL); 213 if (!info) { 214 ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n", 215 __func__); 216 return; 217 } 218 info->p_slot = p_slot; 219 INIT_WORK(&info->work, pciehp_power_thread); 220 221 mutex_lock(&p_slot->lock); 222 switch (p_slot->state) { 223 case BLINKINGOFF_STATE: 224 p_slot->state = POWEROFF_STATE; 225 info->req = DISABLE_REQ; 226 break; 227 case BLINKINGON_STATE: 228 p_slot->state = POWERON_STATE; 229 info->req = ENABLE_REQ; 230 break; 231 default: 232 kfree(info); 233 goto out; 234 } 235 queue_work(p_slot->wq, &info->work); 236 out: 237 mutex_unlock(&p_slot->lock); 238 } 239 240 /* 241 * Note: This function must be called with slot->lock held 242 */ 243 static void handle_button_press_event(struct slot *p_slot) 244 { 245 struct controller *ctrl = p_slot->ctrl; 246 u8 getstatus; 247 248 switch (p_slot->state) { 249 case STATIC_STATE: 250 pciehp_get_power_status(p_slot, &getstatus); 251 if (getstatus) { 252 p_slot->state = BLINKINGOFF_STATE; 253 ctrl_info(ctrl, "PCI slot #%s - powering off due to button press\n", 254 slot_name(p_slot)); 255 } else { 256 p_slot->state = BLINKINGON_STATE; 257 ctrl_info(ctrl, "PCI slot #%s - powering on due to button press\n", 258 slot_name(p_slot)); 259 } 260 /* blink green LED and turn off amber */ 261 pciehp_green_led_blink(p_slot); 262 pciehp_set_attention_status(p_slot, 0); 263 queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ); 264 break; 265 case BLINKINGOFF_STATE: 266 case BLINKINGON_STATE: 267 /* 268 * Cancel if we are still blinking; this means that we 269 * press the attention again before the 5 sec. limit 270 * expires to cancel hot-add or hot-remove 271 */ 272 ctrl_info(ctrl, "Button cancel on Slot(%s)\n", slot_name(p_slot)); 273 cancel_delayed_work(&p_slot->work); 274 if (p_slot->state == BLINKINGOFF_STATE) 275 pciehp_green_led_on(p_slot); 276 else 277 pciehp_green_led_off(p_slot); 278 pciehp_set_attention_status(p_slot, 0); 279 ctrl_info(ctrl, "PCI slot #%s - action canceled due to button press\n", 280 slot_name(p_slot)); 281 p_slot->state = STATIC_STATE; 282 break; 283 case POWEROFF_STATE: 284 case POWERON_STATE: 285 /* 286 * Ignore if the slot is on power-on or power-off state; 287 * this means that the previous attention button action 288 * to hot-add or hot-remove is undergoing 289 */ 290 ctrl_info(ctrl, "Button ignore on Slot(%s)\n", slot_name(p_slot)); 291 break; 292 default: 293 ctrl_warn(ctrl, "ignoring invalid state %#x\n", p_slot->state); 294 break; 295 } 296 } 297 298 /* 299 * Note: This function must be called with slot->lock held 300 */ 301 static void handle_surprise_event(struct slot *p_slot) 302 { 303 u8 getstatus; 304 struct power_work_info *info; 305 306 info = kmalloc(sizeof(*info), GFP_KERNEL); 307 if (!info) { 308 ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n", 309 __func__); 310 return; 311 } 312 info->p_slot = p_slot; 313 INIT_WORK(&info->work, pciehp_power_thread); 314 315 pciehp_get_adapter_status(p_slot, &getstatus); 316 if (!getstatus) { 317 p_slot->state = POWEROFF_STATE; 318 info->req = DISABLE_REQ; 319 } else { 320 p_slot->state = POWERON_STATE; 321 info->req = ENABLE_REQ; 322 } 323 324 queue_work(p_slot->wq, &info->work); 325 } 326 327 /* 328 * Note: This function must be called with slot->lock held 329 */ 330 static void handle_link_event(struct slot *p_slot, u32 event) 331 { 332 struct controller *ctrl = p_slot->ctrl; 333 struct power_work_info *info; 334 335 info = kmalloc(sizeof(*info), GFP_KERNEL); 336 if (!info) { 337 ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n", 338 __func__); 339 return; 340 } 341 info->p_slot = p_slot; 342 info->req = event == INT_LINK_UP ? ENABLE_REQ : DISABLE_REQ; 343 INIT_WORK(&info->work, pciehp_power_thread); 344 345 switch (p_slot->state) { 346 case BLINKINGON_STATE: 347 case BLINKINGOFF_STATE: 348 cancel_delayed_work(&p_slot->work); 349 /* Fall through */ 350 case STATIC_STATE: 351 p_slot->state = event == INT_LINK_UP ? 352 POWERON_STATE : POWEROFF_STATE; 353 queue_work(p_slot->wq, &info->work); 354 break; 355 case POWERON_STATE: 356 if (event == INT_LINK_UP) { 357 ctrl_info(ctrl, 358 "Link Up event ignored on slot(%s): already powering on\n", 359 slot_name(p_slot)); 360 kfree(info); 361 } else { 362 ctrl_info(ctrl, 363 "Link Down event queued on slot(%s): currently getting powered on\n", 364 slot_name(p_slot)); 365 p_slot->state = POWEROFF_STATE; 366 queue_work(p_slot->wq, &info->work); 367 } 368 break; 369 case POWEROFF_STATE: 370 if (event == INT_LINK_UP) { 371 ctrl_info(ctrl, 372 "Link Up event queued on slot(%s): currently getting powered off\n", 373 slot_name(p_slot)); 374 p_slot->state = POWERON_STATE; 375 queue_work(p_slot->wq, &info->work); 376 } else { 377 ctrl_info(ctrl, 378 "Link Down event ignored on slot(%s): already powering off\n", 379 slot_name(p_slot)); 380 kfree(info); 381 } 382 break; 383 default: 384 ctrl_err(ctrl, "ignoring invalid state %#x on slot(%s)\n", 385 p_slot->state, slot_name(p_slot)); 386 kfree(info); 387 break; 388 } 389 } 390 391 static void interrupt_event_handler(struct work_struct *work) 392 { 393 struct event_info *info = container_of(work, struct event_info, work); 394 struct slot *p_slot = info->p_slot; 395 struct controller *ctrl = p_slot->ctrl; 396 397 mutex_lock(&p_slot->lock); 398 switch (info->event_type) { 399 case INT_BUTTON_PRESS: 400 handle_button_press_event(p_slot); 401 break; 402 case INT_POWER_FAULT: 403 if (!POWER_CTRL(ctrl)) 404 break; 405 pciehp_set_attention_status(p_slot, 1); 406 pciehp_green_led_off(p_slot); 407 break; 408 case INT_PRESENCE_ON: 409 handle_surprise_event(p_slot); 410 break; 411 case INT_PRESENCE_OFF: 412 /* 413 * Regardless of surprise capability, we need to 414 * definitely remove a card that has been pulled out! 415 */ 416 handle_surprise_event(p_slot); 417 break; 418 case INT_LINK_UP: 419 case INT_LINK_DOWN: 420 handle_link_event(p_slot, info->event_type); 421 break; 422 default: 423 break; 424 } 425 mutex_unlock(&p_slot->lock); 426 427 kfree(info); 428 } 429 430 /* 431 * Note: This function must be called with slot->hotplug_lock held 432 */ 433 int pciehp_enable_slot(struct slot *p_slot) 434 { 435 u8 getstatus = 0; 436 int rc; 437 struct controller *ctrl = p_slot->ctrl; 438 439 pciehp_get_adapter_status(p_slot, &getstatus); 440 if (!getstatus) { 441 ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot)); 442 return -ENODEV; 443 } 444 if (MRL_SENS(p_slot->ctrl)) { 445 pciehp_get_latch_status(p_slot, &getstatus); 446 if (getstatus) { 447 ctrl_info(ctrl, "Latch open on slot(%s)\n", 448 slot_name(p_slot)); 449 return -ENODEV; 450 } 451 } 452 453 if (POWER_CTRL(p_slot->ctrl)) { 454 pciehp_get_power_status(p_slot, &getstatus); 455 if (getstatus) { 456 ctrl_info(ctrl, "Already enabled on slot(%s)\n", 457 slot_name(p_slot)); 458 return -EINVAL; 459 } 460 } 461 462 pciehp_get_latch_status(p_slot, &getstatus); 463 464 rc = board_added(p_slot); 465 if (rc) 466 pciehp_get_latch_status(p_slot, &getstatus); 467 468 return rc; 469 } 470 471 /* 472 * Note: This function must be called with slot->hotplug_lock held 473 */ 474 int pciehp_disable_slot(struct slot *p_slot) 475 { 476 u8 getstatus = 0; 477 struct controller *ctrl = p_slot->ctrl; 478 479 if (!p_slot->ctrl) 480 return 1; 481 482 if (POWER_CTRL(p_slot->ctrl)) { 483 pciehp_get_power_status(p_slot, &getstatus); 484 if (!getstatus) { 485 ctrl_info(ctrl, "Already disabled on slot(%s)\n", 486 slot_name(p_slot)); 487 return -EINVAL; 488 } 489 } 490 491 return remove_board(p_slot); 492 } 493 494 int pciehp_sysfs_enable_slot(struct slot *p_slot) 495 { 496 int retval = -ENODEV; 497 struct controller *ctrl = p_slot->ctrl; 498 499 mutex_lock(&p_slot->lock); 500 switch (p_slot->state) { 501 case BLINKINGON_STATE: 502 cancel_delayed_work(&p_slot->work); 503 case STATIC_STATE: 504 p_slot->state = POWERON_STATE; 505 mutex_unlock(&p_slot->lock); 506 mutex_lock(&p_slot->hotplug_lock); 507 retval = pciehp_enable_slot(p_slot); 508 mutex_unlock(&p_slot->hotplug_lock); 509 mutex_lock(&p_slot->lock); 510 p_slot->state = STATIC_STATE; 511 break; 512 case POWERON_STATE: 513 ctrl_info(ctrl, "Slot %s is already in powering on state\n", 514 slot_name(p_slot)); 515 break; 516 case BLINKINGOFF_STATE: 517 case POWEROFF_STATE: 518 ctrl_info(ctrl, "Already enabled on slot %s\n", 519 slot_name(p_slot)); 520 break; 521 default: 522 ctrl_err(ctrl, "invalid state %#x on slot %s\n", 523 p_slot->state, slot_name(p_slot)); 524 break; 525 } 526 mutex_unlock(&p_slot->lock); 527 528 return retval; 529 } 530 531 int pciehp_sysfs_disable_slot(struct slot *p_slot) 532 { 533 int retval = -ENODEV; 534 struct controller *ctrl = p_slot->ctrl; 535 536 mutex_lock(&p_slot->lock); 537 switch (p_slot->state) { 538 case BLINKINGOFF_STATE: 539 cancel_delayed_work(&p_slot->work); 540 case STATIC_STATE: 541 p_slot->state = POWEROFF_STATE; 542 mutex_unlock(&p_slot->lock); 543 retval = pciehp_disable_slot(p_slot); 544 mutex_lock(&p_slot->lock); 545 p_slot->state = STATIC_STATE; 546 break; 547 case POWEROFF_STATE: 548 ctrl_info(ctrl, "Slot %s is already in powering off state\n", 549 slot_name(p_slot)); 550 break; 551 case BLINKINGON_STATE: 552 case POWERON_STATE: 553 ctrl_info(ctrl, "Already disabled on slot %s\n", 554 slot_name(p_slot)); 555 break; 556 default: 557 ctrl_err(ctrl, "invalid state %#x on slot %s\n", 558 p_slot->state, slot_name(p_slot)); 559 break; 560 } 561 mutex_unlock(&p_slot->lock); 562 563 return retval; 564 } 565