pciehp_core.c (9643B)
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 * Authors: 15 * Dan Zink <dan.zink@compaq.com> 16 * Greg Kroah-Hartman <greg@kroah.com> 17 * Dely Sy <dely.l.sy@intel.com>" 18 */ 19 20#define pr_fmt(fmt) "pciehp: " fmt 21#define dev_fmt pr_fmt 22 23#include <linux/moduleparam.h> 24#include <linux/kernel.h> 25#include <linux/slab.h> 26#include <linux/types.h> 27#include <linux/pci.h> 28#include "pciehp.h" 29 30#include "../pci.h" 31 32/* Global variables */ 33bool pciehp_poll_mode; 34int pciehp_poll_time; 35 36/* 37 * not really modular, but the easiest way to keep compat with existing 38 * bootargs behaviour is to continue using module_param here. 39 */ 40module_param(pciehp_poll_mode, bool, 0644); 41module_param(pciehp_poll_time, int, 0644); 42MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); 43MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); 44 45static int set_attention_status(struct hotplug_slot *slot, u8 value); 46static int get_power_status(struct hotplug_slot *slot, u8 *value); 47static int get_latch_status(struct hotplug_slot *slot, u8 *value); 48static int get_adapter_status(struct hotplug_slot *slot, u8 *value); 49 50static int init_slot(struct controller *ctrl) 51{ 52 struct hotplug_slot_ops *ops; 53 char name[SLOT_NAME_SIZE]; 54 int retval; 55 56 /* Setup hotplug slot ops */ 57 ops = kzalloc(sizeof(*ops), GFP_KERNEL); 58 if (!ops) 59 return -ENOMEM; 60 61 ops->enable_slot = pciehp_sysfs_enable_slot; 62 ops->disable_slot = pciehp_sysfs_disable_slot; 63 ops->get_power_status = get_power_status; 64 ops->get_adapter_status = get_adapter_status; 65 ops->reset_slot = pciehp_reset_slot; 66 if (MRL_SENS(ctrl)) 67 ops->get_latch_status = get_latch_status; 68 if (ATTN_LED(ctrl)) { 69 ops->get_attention_status = pciehp_get_attention_status; 70 ops->set_attention_status = set_attention_status; 71 } else if (ctrl->pcie->port->hotplug_user_indicators) { 72 ops->get_attention_status = pciehp_get_raw_indicator_status; 73 ops->set_attention_status = pciehp_set_raw_indicator_status; 74 } 75 76 /* register this slot with the hotplug pci core */ 77 ctrl->hotplug_slot.ops = ops; 78 snprintf(name, SLOT_NAME_SIZE, "%u", PSN(ctrl)); 79 80 retval = pci_hp_initialize(&ctrl->hotplug_slot, 81 ctrl->pcie->port->subordinate, 0, name); 82 if (retval) { 83 ctrl_err(ctrl, "pci_hp_initialize failed: error %d\n", retval); 84 kfree(ops); 85 } 86 return retval; 87} 88 89static void cleanup_slot(struct controller *ctrl) 90{ 91 struct hotplug_slot *hotplug_slot = &ctrl->hotplug_slot; 92 93 pci_hp_destroy(hotplug_slot); 94 kfree(hotplug_slot->ops); 95} 96 97/* 98 * set_attention_status - Turns the Attention Indicator on, off or blinking 99 */ 100static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) 101{ 102 struct controller *ctrl = to_ctrl(hotplug_slot); 103 struct pci_dev *pdev = ctrl->pcie->port; 104 105 if (status) 106 status <<= PCI_EXP_SLTCTL_ATTN_IND_SHIFT; 107 else 108 status = PCI_EXP_SLTCTL_ATTN_IND_OFF; 109 110 pci_config_pm_runtime_get(pdev); 111 pciehp_set_indicators(ctrl, INDICATOR_NOOP, status); 112 pci_config_pm_runtime_put(pdev); 113 return 0; 114} 115 116static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) 117{ 118 struct controller *ctrl = to_ctrl(hotplug_slot); 119 struct pci_dev *pdev = ctrl->pcie->port; 120 121 pci_config_pm_runtime_get(pdev); 122 pciehp_get_power_status(ctrl, value); 123 pci_config_pm_runtime_put(pdev); 124 return 0; 125} 126 127static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) 128{ 129 struct controller *ctrl = to_ctrl(hotplug_slot); 130 struct pci_dev *pdev = ctrl->pcie->port; 131 132 pci_config_pm_runtime_get(pdev); 133 pciehp_get_latch_status(ctrl, value); 134 pci_config_pm_runtime_put(pdev); 135 return 0; 136} 137 138static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) 139{ 140 struct controller *ctrl = to_ctrl(hotplug_slot); 141 struct pci_dev *pdev = ctrl->pcie->port; 142 int ret; 143 144 pci_config_pm_runtime_get(pdev); 145 ret = pciehp_card_present_or_link_active(ctrl); 146 pci_config_pm_runtime_put(pdev); 147 if (ret < 0) 148 return ret; 149 150 *value = ret; 151 return 0; 152} 153 154/** 155 * pciehp_check_presence() - synthesize event if presence has changed 156 * @ctrl: controller to check 157 * 158 * On probe and resume, an explicit presence check is necessary to bring up an 159 * occupied slot or bring down an unoccupied slot. This can't be triggered by 160 * events in the Slot Status register, they may be stale and are therefore 161 * cleared. Secondly, sending an interrupt for "events that occur while 162 * interrupt generation is disabled [when] interrupt generation is subsequently 163 * enabled" is optional per PCIe r4.0, sec 6.7.3.4. 164 */ 165static void pciehp_check_presence(struct controller *ctrl) 166{ 167 int occupied; 168 169 down_read_nested(&ctrl->reset_lock, ctrl->depth); 170 mutex_lock(&ctrl->state_lock); 171 172 occupied = pciehp_card_present_or_link_active(ctrl); 173 if ((occupied > 0 && (ctrl->state == OFF_STATE || 174 ctrl->state == BLINKINGON_STATE)) || 175 (!occupied && (ctrl->state == ON_STATE || 176 ctrl->state == BLINKINGOFF_STATE))) 177 pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC); 178 179 mutex_unlock(&ctrl->state_lock); 180 up_read(&ctrl->reset_lock); 181} 182 183static int pciehp_probe(struct pcie_device *dev) 184{ 185 int rc; 186 struct controller *ctrl; 187 188 /* If this is not a "hotplug" service, we have no business here. */ 189 if (dev->service != PCIE_PORT_SERVICE_HP) 190 return -ENODEV; 191 192 if (!dev->port->subordinate) { 193 /* Can happen if we run out of bus numbers during probe */ 194 pci_err(dev->port, 195 "Hotplug bridge without secondary bus, ignoring\n"); 196 return -ENODEV; 197 } 198 199 ctrl = pcie_init(dev); 200 if (!ctrl) { 201 pci_err(dev->port, "Controller initialization failed\n"); 202 return -ENODEV; 203 } 204 set_service_data(dev, ctrl); 205 206 /* Setup the slot information structures */ 207 rc = init_slot(ctrl); 208 if (rc) { 209 if (rc == -EBUSY) 210 ctrl_warn(ctrl, "Slot already registered by another hotplug driver\n"); 211 else 212 ctrl_err(ctrl, "Slot initialization failed (%d)\n", rc); 213 goto err_out_release_ctlr; 214 } 215 216 /* Enable events after we have setup the data structures */ 217 rc = pcie_init_notification(ctrl); 218 if (rc) { 219 ctrl_err(ctrl, "Notification initialization failed (%d)\n", rc); 220 goto err_out_free_ctrl_slot; 221 } 222 223 /* Publish to user space */ 224 rc = pci_hp_add(&ctrl->hotplug_slot); 225 if (rc) { 226 ctrl_err(ctrl, "Publication to user space failed (%d)\n", rc); 227 goto err_out_shutdown_notification; 228 } 229 230 pciehp_check_presence(ctrl); 231 232 return 0; 233 234err_out_shutdown_notification: 235 pcie_shutdown_notification(ctrl); 236err_out_free_ctrl_slot: 237 cleanup_slot(ctrl); 238err_out_release_ctlr: 239 pciehp_release_ctrl(ctrl); 240 return -ENODEV; 241} 242 243static void pciehp_remove(struct pcie_device *dev) 244{ 245 struct controller *ctrl = get_service_data(dev); 246 247 pci_hp_del(&ctrl->hotplug_slot); 248 pcie_shutdown_notification(ctrl); 249 cleanup_slot(ctrl); 250 pciehp_release_ctrl(ctrl); 251} 252 253#ifdef CONFIG_PM 254static bool pme_is_native(struct pcie_device *dev) 255{ 256 const struct pci_host_bridge *host; 257 258 host = pci_find_host_bridge(dev->port->bus); 259 return pcie_ports_native || host->native_pme; 260} 261 262static void pciehp_disable_interrupt(struct pcie_device *dev) 263{ 264 /* 265 * Disable hotplug interrupt so that it does not trigger 266 * immediately when the downstream link goes down. 267 */ 268 if (pme_is_native(dev)) 269 pcie_disable_interrupt(get_service_data(dev)); 270} 271 272#ifdef CONFIG_PM_SLEEP 273static int pciehp_suspend(struct pcie_device *dev) 274{ 275 /* 276 * If the port is already runtime suspended we can keep it that 277 * way. 278 */ 279 if (dev_pm_skip_suspend(&dev->port->dev)) 280 return 0; 281 282 pciehp_disable_interrupt(dev); 283 return 0; 284} 285 286static int pciehp_resume_noirq(struct pcie_device *dev) 287{ 288 struct controller *ctrl = get_service_data(dev); 289 290 /* pci_restore_state() just wrote to the Slot Control register */ 291 ctrl->cmd_started = jiffies; 292 ctrl->cmd_busy = true; 293 294 /* clear spurious events from rediscovery of inserted card */ 295 if (ctrl->state == ON_STATE || ctrl->state == BLINKINGOFF_STATE) 296 pcie_clear_hotplug_events(ctrl); 297 298 return 0; 299} 300#endif 301 302static int pciehp_resume(struct pcie_device *dev) 303{ 304 struct controller *ctrl = get_service_data(dev); 305 306 if (pme_is_native(dev)) 307 pcie_enable_interrupt(ctrl); 308 309 pciehp_check_presence(ctrl); 310 311 return 0; 312} 313 314static int pciehp_runtime_suspend(struct pcie_device *dev) 315{ 316 pciehp_disable_interrupt(dev); 317 return 0; 318} 319 320static int pciehp_runtime_resume(struct pcie_device *dev) 321{ 322 struct controller *ctrl = get_service_data(dev); 323 324 /* pci_restore_state() just wrote to the Slot Control register */ 325 ctrl->cmd_started = jiffies; 326 ctrl->cmd_busy = true; 327 328 /* clear spurious events from rediscovery of inserted card */ 329 if ((ctrl->state == ON_STATE || ctrl->state == BLINKINGOFF_STATE) && 330 pme_is_native(dev)) 331 pcie_clear_hotplug_events(ctrl); 332 333 return pciehp_resume(dev); 334} 335#endif /* PM */ 336 337static struct pcie_port_service_driver hpdriver_portdrv = { 338 .name = "pciehp", 339 .port_type = PCIE_ANY_PORT, 340 .service = PCIE_PORT_SERVICE_HP, 341 342 .probe = pciehp_probe, 343 .remove = pciehp_remove, 344 345#ifdef CONFIG_PM 346#ifdef CONFIG_PM_SLEEP 347 .suspend = pciehp_suspend, 348 .resume_noirq = pciehp_resume_noirq, 349 .resume = pciehp_resume, 350#endif 351 .runtime_suspend = pciehp_runtime_suspend, 352 .runtime_resume = pciehp_runtime_resume, 353#endif /* PM */ 354 355 .slot_reset = pciehp_slot_reset, 356}; 357 358int __init pcie_hp_init(void) 359{ 360 int retval = 0; 361 362 retval = pcie_port_service_register(&hpdriver_portdrv); 363 pr_debug("pcie_port_service_register = %d\n", retval); 364 if (retval) 365 pr_debug("Failure to register service\n"); 366 367 return retval; 368}