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