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/kernel.h> 17 #include <linux/types.h> 18 #include <linux/pm_runtime.h> 19 #include <linux/pci.h> 20 #include "pciehp.h" 21 22 /* The following routines constitute the bulk of the 23 hotplug controller logic 24 */ 25 26 #define SAFE_REMOVAL true 27 #define SURPRISE_REMOVAL false 28 29 static void set_slot_off(struct controller *ctrl) 30 { 31 /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ 32 if (POWER_CTRL(ctrl)) { 33 pciehp_power_off_slot(ctrl); 34 35 /* 36 * After turning power off, we must wait for at least 1 second 37 * before taking any action that relies on power having been 38 * removed from the slot/adapter. 39 */ 40 msleep(1000); 41 } 42 43 pciehp_green_led_off(ctrl); 44 pciehp_set_attention_status(ctrl, 1); 45 } 46 47 /** 48 * board_added - Called after a board has been added to the system. 49 * @ctrl: PCIe hotplug controller where board is added 50 * 51 * Turns power on for the board. 52 * Configures board. 53 */ 54 static int board_added(struct controller *ctrl) 55 { 56 int retval = 0; 57 struct pci_bus *parent = ctrl->pcie->port->subordinate; 58 59 if (POWER_CTRL(ctrl)) { 60 /* Power on slot */ 61 retval = pciehp_power_on_slot(ctrl); 62 if (retval) 63 return retval; 64 } 65 66 pciehp_green_led_blink(ctrl); 67 68 /* Check link training status */ 69 retval = pciehp_check_link_status(ctrl); 70 if (retval) { 71 ctrl_err(ctrl, "Failed to check link status\n"); 72 goto err_exit; 73 } 74 75 /* Check for a power fault */ 76 if (ctrl->power_fault_detected || pciehp_query_power_fault(ctrl)) { 77 ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(ctrl)); 78 retval = -EIO; 79 goto err_exit; 80 } 81 82 retval = pciehp_configure_device(ctrl); 83 if (retval) { 84 if (retval != -EEXIST) { 85 ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n", 86 pci_domain_nr(parent), parent->number); 87 goto err_exit; 88 } 89 } 90 91 pciehp_green_led_on(ctrl); 92 pciehp_set_attention_status(ctrl, 0); 93 return 0; 94 95 err_exit: 96 set_slot_off(ctrl); 97 return retval; 98 } 99 100 /** 101 * remove_board - Turns off slot and LEDs 102 * @ctrl: PCIe hotplug controller where board is being removed 103 * @safe_removal: whether the board is safely removed (versus surprise removed) 104 */ 105 static void remove_board(struct controller *ctrl, bool safe_removal) 106 { 107 pciehp_unconfigure_device(ctrl, safe_removal); 108 109 if (POWER_CTRL(ctrl)) { 110 pciehp_power_off_slot(ctrl); 111 112 /* 113 * After turning power off, we must wait for at least 1 second 114 * before taking any action that relies on power having been 115 * removed from the slot/adapter. 116 */ 117 msleep(1000); 118 119 /* Ignore link or presence changes caused by power off */ 120 atomic_and(~(PCI_EXP_SLTSTA_DLLSC | PCI_EXP_SLTSTA_PDC), 121 &ctrl->pending_events); 122 } 123 124 /* turn off Green LED */ 125 pciehp_green_led_off(ctrl); 126 } 127 128 static int pciehp_enable_slot(struct controller *ctrl); 129 static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal); 130 131 void pciehp_request(struct controller *ctrl, int action) 132 { 133 atomic_or(action, &ctrl->pending_events); 134 if (!pciehp_poll_mode) 135 irq_wake_thread(ctrl->pcie->irq, ctrl); 136 } 137 138 void pciehp_queue_pushbutton_work(struct work_struct *work) 139 { 140 struct controller *ctrl = container_of(work, struct controller, 141 button_work.work); 142 143 mutex_lock(&ctrl->state_lock); 144 switch (ctrl->state) { 145 case BLINKINGOFF_STATE: 146 pciehp_request(ctrl, DISABLE_SLOT); 147 break; 148 case BLINKINGON_STATE: 149 pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC); 150 break; 151 default: 152 break; 153 } 154 mutex_unlock(&ctrl->state_lock); 155 } 156 157 void pciehp_handle_button_press(struct controller *ctrl) 158 { 159 mutex_lock(&ctrl->state_lock); 160 switch (ctrl->state) { 161 case OFF_STATE: 162 case ON_STATE: 163 if (ctrl->state == ON_STATE) { 164 ctrl->state = BLINKINGOFF_STATE; 165 ctrl_info(ctrl, "Slot(%s): Powering off due to button press\n", 166 slot_name(ctrl)); 167 } else { 168 ctrl->state = BLINKINGON_STATE; 169 ctrl_info(ctrl, "Slot(%s) Powering on due to button press\n", 170 slot_name(ctrl)); 171 } 172 /* blink green LED and turn off amber */ 173 pciehp_green_led_blink(ctrl); 174 pciehp_set_attention_status(ctrl, 0); 175 schedule_delayed_work(&ctrl->button_work, 5 * HZ); 176 break; 177 case BLINKINGOFF_STATE: 178 case BLINKINGON_STATE: 179 /* 180 * Cancel if we are still blinking; this means that we 181 * press the attention again before the 5 sec. limit 182 * expires to cancel hot-add or hot-remove 183 */ 184 ctrl_info(ctrl, "Slot(%s): Button cancel\n", slot_name(ctrl)); 185 cancel_delayed_work(&ctrl->button_work); 186 if (ctrl->state == BLINKINGOFF_STATE) { 187 ctrl->state = ON_STATE; 188 pciehp_green_led_on(ctrl); 189 } else { 190 ctrl->state = OFF_STATE; 191 pciehp_green_led_off(ctrl); 192 } 193 pciehp_set_attention_status(ctrl, 0); 194 ctrl_info(ctrl, "Slot(%s): Action canceled due to button press\n", 195 slot_name(ctrl)); 196 break; 197 default: 198 ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n", 199 slot_name(ctrl), ctrl->state); 200 break; 201 } 202 mutex_unlock(&ctrl->state_lock); 203 } 204 205 void pciehp_handle_disable_request(struct controller *ctrl) 206 { 207 mutex_lock(&ctrl->state_lock); 208 switch (ctrl->state) { 209 case BLINKINGON_STATE: 210 case BLINKINGOFF_STATE: 211 cancel_delayed_work(&ctrl->button_work); 212 break; 213 } 214 ctrl->state = POWEROFF_STATE; 215 mutex_unlock(&ctrl->state_lock); 216 217 ctrl->request_result = pciehp_disable_slot(ctrl, SAFE_REMOVAL); 218 } 219 220 void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events) 221 { 222 bool present, link_active; 223 224 /* 225 * If the slot is on and presence or link has changed, turn it off. 226 * Even if it's occupied again, we cannot assume the card is the same. 227 */ 228 mutex_lock(&ctrl->state_lock); 229 switch (ctrl->state) { 230 case BLINKINGOFF_STATE: 231 cancel_delayed_work(&ctrl->button_work); 232 /* fall through */ 233 case ON_STATE: 234 ctrl->state = POWEROFF_STATE; 235 mutex_unlock(&ctrl->state_lock); 236 if (events & PCI_EXP_SLTSTA_DLLSC) 237 ctrl_info(ctrl, "Slot(%s): Link Down\n", 238 slot_name(ctrl)); 239 if (events & PCI_EXP_SLTSTA_PDC) 240 ctrl_info(ctrl, "Slot(%s): Card not present\n", 241 slot_name(ctrl)); 242 pciehp_disable_slot(ctrl, SURPRISE_REMOVAL); 243 break; 244 default: 245 mutex_unlock(&ctrl->state_lock); 246 break; 247 } 248 249 /* Turn the slot on if it's occupied or link is up */ 250 mutex_lock(&ctrl->state_lock); 251 present = pciehp_card_present(ctrl); 252 link_active = pciehp_check_link_active(ctrl); 253 if (!present && !link_active) { 254 mutex_unlock(&ctrl->state_lock); 255 return; 256 } 257 258 switch (ctrl->state) { 259 case BLINKINGON_STATE: 260 cancel_delayed_work(&ctrl->button_work); 261 /* fall through */ 262 case OFF_STATE: 263 ctrl->state = POWERON_STATE; 264 mutex_unlock(&ctrl->state_lock); 265 if (present) 266 ctrl_info(ctrl, "Slot(%s): Card present\n", 267 slot_name(ctrl)); 268 if (link_active) 269 ctrl_info(ctrl, "Slot(%s): Link Up\n", 270 slot_name(ctrl)); 271 ctrl->request_result = pciehp_enable_slot(ctrl); 272 break; 273 default: 274 mutex_unlock(&ctrl->state_lock); 275 break; 276 } 277 } 278 279 static int __pciehp_enable_slot(struct controller *ctrl) 280 { 281 u8 getstatus = 0; 282 283 if (MRL_SENS(ctrl)) { 284 pciehp_get_latch_status(ctrl, &getstatus); 285 if (getstatus) { 286 ctrl_info(ctrl, "Slot(%s): Latch open\n", 287 slot_name(ctrl)); 288 return -ENODEV; 289 } 290 } 291 292 if (POWER_CTRL(ctrl)) { 293 pciehp_get_power_status(ctrl, &getstatus); 294 if (getstatus) { 295 ctrl_info(ctrl, "Slot(%s): Already enabled\n", 296 slot_name(ctrl)); 297 return 0; 298 } 299 } 300 301 return board_added(ctrl); 302 } 303 304 static int pciehp_enable_slot(struct controller *ctrl) 305 { 306 int ret; 307 308 pm_runtime_get_sync(&ctrl->pcie->port->dev); 309 ret = __pciehp_enable_slot(ctrl); 310 if (ret && ATTN_BUTTN(ctrl)) 311 pciehp_green_led_off(ctrl); /* may be blinking */ 312 pm_runtime_put(&ctrl->pcie->port->dev); 313 314 mutex_lock(&ctrl->state_lock); 315 ctrl->state = ret ? OFF_STATE : ON_STATE; 316 mutex_unlock(&ctrl->state_lock); 317 318 return ret; 319 } 320 321 static int __pciehp_disable_slot(struct controller *ctrl, bool safe_removal) 322 { 323 u8 getstatus = 0; 324 325 if (POWER_CTRL(ctrl)) { 326 pciehp_get_power_status(ctrl, &getstatus); 327 if (!getstatus) { 328 ctrl_info(ctrl, "Slot(%s): Already disabled\n", 329 slot_name(ctrl)); 330 return -EINVAL; 331 } 332 } 333 334 remove_board(ctrl, safe_removal); 335 return 0; 336 } 337 338 static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal) 339 { 340 int ret; 341 342 pm_runtime_get_sync(&ctrl->pcie->port->dev); 343 ret = __pciehp_disable_slot(ctrl, safe_removal); 344 pm_runtime_put(&ctrl->pcie->port->dev); 345 346 mutex_lock(&ctrl->state_lock); 347 ctrl->state = OFF_STATE; 348 mutex_unlock(&ctrl->state_lock); 349 350 return ret; 351 } 352 353 int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot) 354 { 355 struct controller *ctrl = to_ctrl(hotplug_slot); 356 357 mutex_lock(&ctrl->state_lock); 358 switch (ctrl->state) { 359 case BLINKINGON_STATE: 360 case OFF_STATE: 361 mutex_unlock(&ctrl->state_lock); 362 /* 363 * The IRQ thread becomes a no-op if the user pulls out the 364 * card before the thread wakes up, so initialize to -ENODEV. 365 */ 366 ctrl->request_result = -ENODEV; 367 pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC); 368 wait_event(ctrl->requester, 369 !atomic_read(&ctrl->pending_events)); 370 return ctrl->request_result; 371 case POWERON_STATE: 372 ctrl_info(ctrl, "Slot(%s): Already in powering on state\n", 373 slot_name(ctrl)); 374 break; 375 case BLINKINGOFF_STATE: 376 case ON_STATE: 377 case POWEROFF_STATE: 378 ctrl_info(ctrl, "Slot(%s): Already enabled\n", 379 slot_name(ctrl)); 380 break; 381 default: 382 ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n", 383 slot_name(ctrl), ctrl->state); 384 break; 385 } 386 mutex_unlock(&ctrl->state_lock); 387 388 return -ENODEV; 389 } 390 391 int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot) 392 { 393 struct controller *ctrl = to_ctrl(hotplug_slot); 394 395 mutex_lock(&ctrl->state_lock); 396 switch (ctrl->state) { 397 case BLINKINGOFF_STATE: 398 case ON_STATE: 399 mutex_unlock(&ctrl->state_lock); 400 pciehp_request(ctrl, DISABLE_SLOT); 401 wait_event(ctrl->requester, 402 !atomic_read(&ctrl->pending_events)); 403 return ctrl->request_result; 404 case POWEROFF_STATE: 405 ctrl_info(ctrl, "Slot(%s): Already in powering off state\n", 406 slot_name(ctrl)); 407 break; 408 case BLINKINGON_STATE: 409 case OFF_STATE: 410 case POWERON_STATE: 411 ctrl_info(ctrl, "Slot(%s): Already disabled\n", 412 slot_name(ctrl)); 413 break; 414 default: 415 ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n", 416 slot_name(ctrl), ctrl->state); 417 break; 418 } 419 mutex_unlock(&ctrl->state_lock); 420 421 return -ENODEV; 422 } 423