Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

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