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 ctrl_err(ctrl, "Failed to check link status\n"); 78 goto err_exit; 79 } 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 134 static int pciehp_enable_slot(struct controller *ctrl); 135 static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal); 136 137 void pciehp_request(struct controller *ctrl, int action) 138 { 139 atomic_or(action, &ctrl->pending_events); 140 if (!pciehp_poll_mode) 141 irq_wake_thread(ctrl->pcie->irq, ctrl); 142 } 143 144 void pciehp_queue_pushbutton_work(struct work_struct *work) 145 { 146 struct controller *ctrl = container_of(work, struct controller, 147 button_work.work); 148 149 mutex_lock(&ctrl->state_lock); 150 switch (ctrl->state) { 151 case BLINKINGOFF_STATE: 152 pciehp_request(ctrl, DISABLE_SLOT); 153 break; 154 case BLINKINGON_STATE: 155 pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC); 156 break; 157 default: 158 break; 159 } 160 mutex_unlock(&ctrl->state_lock); 161 } 162 163 void pciehp_handle_button_press(struct controller *ctrl) 164 { 165 mutex_lock(&ctrl->state_lock); 166 switch (ctrl->state) { 167 case OFF_STATE: 168 case ON_STATE: 169 if (ctrl->state == ON_STATE) { 170 ctrl->state = BLINKINGOFF_STATE; 171 ctrl_info(ctrl, "Slot(%s): Powering off due to button press\n", 172 slot_name(ctrl)); 173 } else { 174 ctrl->state = BLINKINGON_STATE; 175 ctrl_info(ctrl, "Slot(%s) Powering on due to button press\n", 176 slot_name(ctrl)); 177 } 178 /* blink power indicator and turn off attention */ 179 pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK, 180 PCI_EXP_SLTCTL_ATTN_IND_OFF); 181 schedule_delayed_work(&ctrl->button_work, 5 * HZ); 182 break; 183 case BLINKINGOFF_STATE: 184 case BLINKINGON_STATE: 185 /* 186 * Cancel if we are still blinking; this means that we 187 * press the attention again before the 5 sec. limit 188 * expires to cancel hot-add or hot-remove 189 */ 190 ctrl_info(ctrl, "Slot(%s): Button cancel\n", slot_name(ctrl)); 191 cancel_delayed_work(&ctrl->button_work); 192 if (ctrl->state == BLINKINGOFF_STATE) { 193 ctrl->state = ON_STATE; 194 pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON, 195 PCI_EXP_SLTCTL_ATTN_IND_OFF); 196 } else { 197 ctrl->state = OFF_STATE; 198 pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF, 199 PCI_EXP_SLTCTL_ATTN_IND_OFF); 200 } 201 ctrl_info(ctrl, "Slot(%s): Action canceled due to button press\n", 202 slot_name(ctrl)); 203 break; 204 default: 205 ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n", 206 slot_name(ctrl), ctrl->state); 207 break; 208 } 209 mutex_unlock(&ctrl->state_lock); 210 } 211 212 void pciehp_handle_disable_request(struct controller *ctrl) 213 { 214 mutex_lock(&ctrl->state_lock); 215 switch (ctrl->state) { 216 case BLINKINGON_STATE: 217 case BLINKINGOFF_STATE: 218 cancel_delayed_work(&ctrl->button_work); 219 break; 220 } 221 ctrl->state = POWEROFF_STATE; 222 mutex_unlock(&ctrl->state_lock); 223 224 ctrl->request_result = pciehp_disable_slot(ctrl, SAFE_REMOVAL); 225 } 226 227 void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events) 228 { 229 bool present, link_active; 230 231 /* 232 * If the slot is on and presence or link has changed, turn it off. 233 * Even if it's occupied again, we cannot assume the card is the same. 234 */ 235 mutex_lock(&ctrl->state_lock); 236 switch (ctrl->state) { 237 case BLINKINGOFF_STATE: 238 cancel_delayed_work(&ctrl->button_work); 239 /* fall through */ 240 case ON_STATE: 241 ctrl->state = POWEROFF_STATE; 242 mutex_unlock(&ctrl->state_lock); 243 if (events & PCI_EXP_SLTSTA_DLLSC) 244 ctrl_info(ctrl, "Slot(%s): Link Down\n", 245 slot_name(ctrl)); 246 if (events & PCI_EXP_SLTSTA_PDC) 247 ctrl_info(ctrl, "Slot(%s): Card not present\n", 248 slot_name(ctrl)); 249 pciehp_disable_slot(ctrl, SURPRISE_REMOVAL); 250 break; 251 default: 252 mutex_unlock(&ctrl->state_lock); 253 break; 254 } 255 256 /* Turn the slot on if it's occupied or link is up */ 257 mutex_lock(&ctrl->state_lock); 258 present = pciehp_card_present(ctrl); 259 link_active = pciehp_check_link_active(ctrl); 260 if (!present && !link_active) { 261 mutex_unlock(&ctrl->state_lock); 262 return; 263 } 264 265 switch (ctrl->state) { 266 case BLINKINGON_STATE: 267 cancel_delayed_work(&ctrl->button_work); 268 /* fall through */ 269 case OFF_STATE: 270 ctrl->state = POWERON_STATE; 271 mutex_unlock(&ctrl->state_lock); 272 if (present) 273 ctrl_info(ctrl, "Slot(%s): Card present\n", 274 slot_name(ctrl)); 275 if (link_active) 276 ctrl_info(ctrl, "Slot(%s): Link Up\n", 277 slot_name(ctrl)); 278 ctrl->request_result = pciehp_enable_slot(ctrl); 279 break; 280 default: 281 mutex_unlock(&ctrl->state_lock); 282 break; 283 } 284 } 285 286 static int __pciehp_enable_slot(struct controller *ctrl) 287 { 288 u8 getstatus = 0; 289 290 if (MRL_SENS(ctrl)) { 291 pciehp_get_latch_status(ctrl, &getstatus); 292 if (getstatus) { 293 ctrl_info(ctrl, "Slot(%s): Latch open\n", 294 slot_name(ctrl)); 295 return -ENODEV; 296 } 297 } 298 299 if (POWER_CTRL(ctrl)) { 300 pciehp_get_power_status(ctrl, &getstatus); 301 if (getstatus) { 302 ctrl_info(ctrl, "Slot(%s): Already enabled\n", 303 slot_name(ctrl)); 304 return 0; 305 } 306 } 307 308 return board_added(ctrl); 309 } 310 311 static int pciehp_enable_slot(struct controller *ctrl) 312 { 313 int ret; 314 315 pm_runtime_get_sync(&ctrl->pcie->port->dev); 316 ret = __pciehp_enable_slot(ctrl); 317 if (ret && ATTN_BUTTN(ctrl)) 318 /* may be blinking */ 319 pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF, 320 INDICATOR_NOOP); 321 pm_runtime_put(&ctrl->pcie->port->dev); 322 323 mutex_lock(&ctrl->state_lock); 324 ctrl->state = ret ? OFF_STATE : ON_STATE; 325 mutex_unlock(&ctrl->state_lock); 326 327 return ret; 328 } 329 330 static int __pciehp_disable_slot(struct controller *ctrl, bool safe_removal) 331 { 332 u8 getstatus = 0; 333 334 if (POWER_CTRL(ctrl)) { 335 pciehp_get_power_status(ctrl, &getstatus); 336 if (!getstatus) { 337 ctrl_info(ctrl, "Slot(%s): Already disabled\n", 338 slot_name(ctrl)); 339 return -EINVAL; 340 } 341 } 342 343 remove_board(ctrl, safe_removal); 344 return 0; 345 } 346 347 static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal) 348 { 349 int ret; 350 351 pm_runtime_get_sync(&ctrl->pcie->port->dev); 352 ret = __pciehp_disable_slot(ctrl, safe_removal); 353 pm_runtime_put(&ctrl->pcie->port->dev); 354 355 mutex_lock(&ctrl->state_lock); 356 ctrl->state = OFF_STATE; 357 mutex_unlock(&ctrl->state_lock); 358 359 return ret; 360 } 361 362 int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot) 363 { 364 struct controller *ctrl = to_ctrl(hotplug_slot); 365 366 mutex_lock(&ctrl->state_lock); 367 switch (ctrl->state) { 368 case BLINKINGON_STATE: 369 case OFF_STATE: 370 mutex_unlock(&ctrl->state_lock); 371 /* 372 * The IRQ thread becomes a no-op if the user pulls out the 373 * card before the thread wakes up, so initialize to -ENODEV. 374 */ 375 ctrl->request_result = -ENODEV; 376 pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC); 377 wait_event(ctrl->requester, 378 !atomic_read(&ctrl->pending_events)); 379 return ctrl->request_result; 380 case POWERON_STATE: 381 ctrl_info(ctrl, "Slot(%s): Already in powering on state\n", 382 slot_name(ctrl)); 383 break; 384 case BLINKINGOFF_STATE: 385 case ON_STATE: 386 case POWEROFF_STATE: 387 ctrl_info(ctrl, "Slot(%s): Already enabled\n", 388 slot_name(ctrl)); 389 break; 390 default: 391 ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n", 392 slot_name(ctrl), ctrl->state); 393 break; 394 } 395 mutex_unlock(&ctrl->state_lock); 396 397 return -ENODEV; 398 } 399 400 int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot) 401 { 402 struct controller *ctrl = to_ctrl(hotplug_slot); 403 404 mutex_lock(&ctrl->state_lock); 405 switch (ctrl->state) { 406 case BLINKINGOFF_STATE: 407 case ON_STATE: 408 mutex_unlock(&ctrl->state_lock); 409 pciehp_request(ctrl, DISABLE_SLOT); 410 wait_event(ctrl->requester, 411 !atomic_read(&ctrl->pending_events)); 412 return ctrl->request_result; 413 case POWEROFF_STATE: 414 ctrl_info(ctrl, "Slot(%s): Already in powering off state\n", 415 slot_name(ctrl)); 416 break; 417 case BLINKINGON_STATE: 418 case OFF_STATE: 419 case POWERON_STATE: 420 ctrl_info(ctrl, "Slot(%s): Already disabled\n", 421 slot_name(ctrl)); 422 break; 423 default: 424 ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n", 425 slot_name(ctrl), ctrl->state); 426 break; 427 } 428 mutex_unlock(&ctrl->state_lock); 429 430 return -ENODEV; 431 } 432