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

Configure Feed

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

at v5.6-rc3 365 lines 9.6 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/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 * 157 * On probe and resume, an explicit presence check is necessary to bring up an 158 * occupied slot or bring down an unoccupied slot. This can't be triggered by 159 * events in the Slot Status register, they may be stale and are therefore 160 * cleared. Secondly, sending an interrupt for "events that occur while 161 * interrupt generation is disabled [when] interrupt generation is subsequently 162 * enabled" is optional per PCIe r4.0, sec 6.7.3.4. 163 */ 164static void pciehp_check_presence(struct controller *ctrl) 165{ 166 int occupied; 167 168 down_read(&ctrl->reset_lock); 169 mutex_lock(&ctrl->state_lock); 170 171 occupied = pciehp_card_present_or_link_active(ctrl); 172 if ((occupied > 0 && (ctrl->state == OFF_STATE || 173 ctrl->state == BLINKINGON_STATE)) || 174 (!occupied && (ctrl->state == ON_STATE || 175 ctrl->state == BLINKINGOFF_STATE))) 176 pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC); 177 178 mutex_unlock(&ctrl->state_lock); 179 up_read(&ctrl->reset_lock); 180} 181 182static int pciehp_probe(struct pcie_device *dev) 183{ 184 int rc; 185 struct controller *ctrl; 186 187 /* If this is not a "hotplug" service, we have no business here. */ 188 if (dev->service != PCIE_PORT_SERVICE_HP) 189 return -ENODEV; 190 191 if (!dev->port->subordinate) { 192 /* Can happen if we run out of bus numbers during probe */ 193 pci_err(dev->port, 194 "Hotplug bridge without secondary bus, ignoring\n"); 195 return -ENODEV; 196 } 197 198 ctrl = pcie_init(dev); 199 if (!ctrl) { 200 pci_err(dev->port, "Controller initialization failed\n"); 201 return -ENODEV; 202 } 203 set_service_data(dev, ctrl); 204 205 /* Setup the slot information structures */ 206 rc = init_slot(ctrl); 207 if (rc) { 208 if (rc == -EBUSY) 209 ctrl_warn(ctrl, "Slot already registered by another hotplug driver\n"); 210 else 211 ctrl_err(ctrl, "Slot initialization failed (%d)\n", rc); 212 goto err_out_release_ctlr; 213 } 214 215 /* Enable events after we have setup the data structures */ 216 rc = pcie_init_notification(ctrl); 217 if (rc) { 218 ctrl_err(ctrl, "Notification initialization failed (%d)\n", rc); 219 goto err_out_free_ctrl_slot; 220 } 221 222 /* Publish to user space */ 223 rc = pci_hp_add(&ctrl->hotplug_slot); 224 if (rc) { 225 ctrl_err(ctrl, "Publication to user space failed (%d)\n", rc); 226 goto err_out_shutdown_notification; 227 } 228 229 pciehp_check_presence(ctrl); 230 231 return 0; 232 233err_out_shutdown_notification: 234 pcie_shutdown_notification(ctrl); 235err_out_free_ctrl_slot: 236 cleanup_slot(ctrl); 237err_out_release_ctlr: 238 pciehp_release_ctrl(ctrl); 239 return -ENODEV; 240} 241 242static void pciehp_remove(struct pcie_device *dev) 243{ 244 struct controller *ctrl = get_service_data(dev); 245 246 pci_hp_del(&ctrl->hotplug_slot); 247 pcie_shutdown_notification(ctrl); 248 cleanup_slot(ctrl); 249 pciehp_release_ctrl(ctrl); 250} 251 252#ifdef CONFIG_PM 253static bool pme_is_native(struct pcie_device *dev) 254{ 255 const struct pci_host_bridge *host; 256 257 host = pci_find_host_bridge(dev->port->bus); 258 return pcie_ports_native || host->native_pme; 259} 260 261static void pciehp_disable_interrupt(struct pcie_device *dev) 262{ 263 /* 264 * Disable hotplug interrupt so that it does not trigger 265 * immediately when the downstream link goes down. 266 */ 267 if (pme_is_native(dev)) 268 pcie_disable_interrupt(get_service_data(dev)); 269} 270 271#ifdef CONFIG_PM_SLEEP 272static int pciehp_suspend(struct pcie_device *dev) 273{ 274 /* 275 * If the port is already runtime suspended we can keep it that 276 * way. 277 */ 278 if (dev_pm_smart_suspend_and_suspended(&dev->port->dev)) 279 return 0; 280 281 pciehp_disable_interrupt(dev); 282 return 0; 283} 284 285static int pciehp_resume_noirq(struct pcie_device *dev) 286{ 287 struct controller *ctrl = get_service_data(dev); 288 289 /* pci_restore_state() just wrote to the Slot Control register */ 290 ctrl->cmd_started = jiffies; 291 ctrl->cmd_busy = true; 292 293 /* clear spurious events from rediscovery of inserted card */ 294 if (ctrl->state == ON_STATE || ctrl->state == BLINKINGOFF_STATE) 295 pcie_clear_hotplug_events(ctrl); 296 297 return 0; 298} 299#endif 300 301static int pciehp_resume(struct pcie_device *dev) 302{ 303 struct controller *ctrl = get_service_data(dev); 304 305 if (pme_is_native(dev)) 306 pcie_enable_interrupt(ctrl); 307 308 pciehp_check_presence(ctrl); 309 310 return 0; 311} 312 313static int pciehp_runtime_suspend(struct pcie_device *dev) 314{ 315 pciehp_disable_interrupt(dev); 316 return 0; 317} 318 319static int pciehp_runtime_resume(struct pcie_device *dev) 320{ 321 struct controller *ctrl = get_service_data(dev); 322 323 /* pci_restore_state() just wrote to the Slot Control register */ 324 ctrl->cmd_started = jiffies; 325 ctrl->cmd_busy = true; 326 327 /* clear spurious events from rediscovery of inserted card */ 328 if ((ctrl->state == ON_STATE || ctrl->state == BLINKINGOFF_STATE) && 329 pme_is_native(dev)) 330 pcie_clear_hotplug_events(ctrl); 331 332 return pciehp_resume(dev); 333} 334#endif /* PM */ 335 336static struct pcie_port_service_driver hpdriver_portdrv = { 337 .name = "pciehp", 338 .port_type = PCIE_ANY_PORT, 339 .service = PCIE_PORT_SERVICE_HP, 340 341 .probe = pciehp_probe, 342 .remove = pciehp_remove, 343 344#ifdef CONFIG_PM 345#ifdef CONFIG_PM_SLEEP 346 .suspend = pciehp_suspend, 347 .resume_noirq = pciehp_resume_noirq, 348 .resume = pciehp_resume, 349#endif 350 .runtime_suspend = pciehp_runtime_suspend, 351 .runtime_resume = pciehp_runtime_resume, 352#endif /* PM */ 353}; 354 355int __init pcie_hp_init(void) 356{ 357 int retval = 0; 358 359 retval = pcie_port_service_register(&hpdriver_portdrv); 360 pr_debug("pcie_port_service_register = %d\n", retval); 361 if (retval) 362 pr_debug("Failure to register service\n"); 363 364 return retval; 365}