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