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