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