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