410 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * PCI Express Hot Plug Controller Driver4 *5 * Copyright (C) 1995,2001 Compaq Computer Corporation6 * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)7 * Copyright (C) 2001 IBM Corp.8 * Copyright (C) 2003-2004 Intel Corporation9 *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: " fmt21#define dev_fmt pr_fmt22 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 existing39 * 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(sizeof(*ops), GFP_KERNEL);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, 0, name);83 if (retval) {84 ctrl_err(ctrl, "pci_hp_initialize failed: error %d\n", retval);85 kfree(ops);86 }87 return retval;88}89 90static void cleanup_slot(struct controller *ctrl)91{92 struct hotplug_slot *hotplug_slot = &ctrl->hotplug_slot;93 94 pci_hp_destroy(hotplug_slot);95 kfree(hotplug_slot->ops);96}97 98/*99 * set_attention_status - Turns the Attention Indicator on, off or blinking100 */101static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)102{103 struct controller *ctrl = to_ctrl(hotplug_slot);104 struct pci_dev *pdev = ctrl->pcie->port;105 106 if (status)107 status = FIELD_PREP(PCI_EXP_SLTCTL_AIC, status);108 else109 status = PCI_EXP_SLTCTL_ATTN_IND_OFF;110 111 pci_config_pm_runtime_get(pdev);112 pciehp_set_indicators(ctrl, INDICATOR_NOOP, status);113 pci_config_pm_runtime_put(pdev);114 return 0;115}116 117static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)118{119 struct controller *ctrl = to_ctrl(hotplug_slot);120 struct pci_dev *pdev = ctrl->pcie->port;121 122 pci_config_pm_runtime_get(pdev);123 pciehp_get_power_status(ctrl, value);124 pci_config_pm_runtime_put(pdev);125 return 0;126}127 128static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)129{130 struct controller *ctrl = to_ctrl(hotplug_slot);131 struct pci_dev *pdev = ctrl->pcie->port;132 133 pci_config_pm_runtime_get(pdev);134 pciehp_get_latch_status(ctrl, value);135 pci_config_pm_runtime_put(pdev);136 return 0;137}138 139static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)140{141 struct controller *ctrl = to_ctrl(hotplug_slot);142 struct pci_dev *pdev = ctrl->pcie->port;143 int ret;144 145 pci_config_pm_runtime_get(pdev);146 ret = pciehp_card_present_or_link_active(ctrl);147 pci_config_pm_runtime_put(pdev);148 if (ret < 0)149 return ret;150 151 *value = ret;152 return 0;153}154 155/**156 * pciehp_check_presence() - synthesize event if presence has changed157 * @ctrl: controller to check158 *159 * On probe and resume, an explicit presence check is necessary to bring up an160 * occupied slot or bring down an unoccupied slot. This can't be triggered by161 * events in the Slot Status register, they may be stale and are therefore162 * cleared. Secondly, sending an interrupt for "events that occur while163 * interrupt generation is disabled [when] interrupt generation is subsequently164 * enabled" is optional per PCIe r4.0, sec 6.7.3.4.165 */166static void pciehp_check_presence(struct controller *ctrl)167{168 int occupied;169 170 down_read_nested(&ctrl->reset_lock, ctrl->depth);171 mutex_lock(&ctrl->state_lock);172 173 occupied = pciehp_card_present_or_link_active(ctrl);174 if ((occupied > 0 && (ctrl->state == OFF_STATE ||175 ctrl->state == BLINKINGON_STATE)) ||176 (!occupied && (ctrl->state == ON_STATE ||177 ctrl->state == BLINKINGOFF_STATE)))178 pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);179 180 mutex_unlock(&ctrl->state_lock);181 up_read(&ctrl->reset_lock);182}183 184static int pciehp_probe(struct pcie_device *dev)185{186 int rc;187 struct controller *ctrl;188 189 /* If this is not a "hotplug" service, we have no business here. */190 if (dev->service != PCIE_PORT_SERVICE_HP)191 return -ENODEV;192 193 if (!dev->port->subordinate) {194 /* Can happen if we run out of bus numbers during probe */195 pci_err(dev->port,196 "Hotplug bridge without secondary bus, ignoring\n");197 return -ENODEV;198 }199 200 ctrl = pcie_init(dev);201 if (!ctrl) {202 pci_err(dev->port, "Controller initialization failed\n");203 return -ENODEV;204 }205 set_service_data(dev, ctrl);206 207 /* Setup the slot information structures */208 rc = init_slot(ctrl);209 if (rc) {210 if (rc == -EBUSY)211 ctrl_warn(ctrl, "Slot already registered by another hotplug driver\n");212 else213 ctrl_err(ctrl, "Slot initialization failed (%d)\n", rc);214 goto err_out_release_ctlr;215 }216 217 /* Enable events after we have setup the data structures */218 rc = pcie_init_notification(ctrl);219 if (rc) {220 ctrl_err(ctrl, "Notification initialization failed (%d)\n", rc);221 goto err_out_free_ctrl_slot;222 }223 224 /* Publish to user space */225 rc = pci_hp_add(&ctrl->hotplug_slot);226 if (rc) {227 ctrl_err(ctrl, "Publication to user space failed (%d)\n", rc);228 goto err_out_shutdown_notification;229 }230 231 pciehp_check_presence(ctrl);232 233 return 0;234 235err_out_shutdown_notification:236 pcie_shutdown_notification(ctrl);237err_out_free_ctrl_slot:238 cleanup_slot(ctrl);239err_out_release_ctlr:240 pciehp_release_ctrl(ctrl);241 return -ENODEV;242}243 244static void pciehp_remove(struct pcie_device *dev)245{246 struct controller *ctrl = get_service_data(dev);247 248 pci_hp_del(&ctrl->hotplug_slot);249 pcie_shutdown_notification(ctrl);250 cleanup_slot(ctrl);251 pciehp_release_ctrl(ctrl);252}253 254#ifdef CONFIG_PM255static bool pme_is_native(struct pcie_device *dev)256{257 const struct pci_host_bridge *host;258 259 host = pci_find_host_bridge(dev->port->bus);260 return pcie_ports_native || host->native_pme;261}262 263static void pciehp_disable_interrupt(struct pcie_device *dev)264{265 /*266 * Disable hotplug interrupt so that it does not trigger267 * immediately when the downstream link goes down.268 */269 if (pme_is_native(dev))270 pcie_disable_interrupt(get_service_data(dev));271}272 273#ifdef CONFIG_PM_SLEEP274static int pciehp_suspend(struct pcie_device *dev)275{276 /*277 * If the port is already runtime suspended we can keep it that278 * way.279 */280 if (dev_pm_skip_suspend(&dev->port->dev))281 return 0;282 283 pciehp_disable_interrupt(dev);284 return 0;285}286 287static bool pciehp_device_replaced(struct controller *ctrl)288{289 struct pci_dev *pdev __free(pci_dev_put);290 u32 reg;291 292 pdev = pci_get_slot(ctrl->pcie->port->subordinate, PCI_DEVFN(0, 0));293 if (!pdev)294 return true;295 296 if (pci_read_config_dword(pdev, PCI_VENDOR_ID, ®) ||297 reg != (pdev->vendor | (pdev->device << 16)) ||298 pci_read_config_dword(pdev, PCI_CLASS_REVISION, ®) ||299 reg != (pdev->revision | (pdev->class << 8)))300 return true;301 302 if (pdev->hdr_type == PCI_HEADER_TYPE_NORMAL &&303 (pci_read_config_dword(pdev, PCI_SUBSYSTEM_VENDOR_ID, ®) ||304 reg != (pdev->subsystem_vendor | (pdev->subsystem_device << 16))))305 return true;306 307 if (pci_get_dsn(pdev) != ctrl->dsn)308 return true;309 310 return false;311}312 313static int pciehp_resume_noirq(struct pcie_device *dev)314{315 struct controller *ctrl = get_service_data(dev);316 317 /* pci_restore_state() just wrote to the Slot Control register */318 ctrl->cmd_started = jiffies;319 ctrl->cmd_busy = true;320 321 /* clear spurious events from rediscovery of inserted card */322 if (ctrl->state == ON_STATE || ctrl->state == BLINKINGOFF_STATE) {323 pcie_clear_hotplug_events(ctrl);324 325 /*326 * If hotplugged device was replaced with a different one327 * during system sleep, mark the old device disconnected328 * (to prevent its driver from accessing the new device)329 * and synthesize a Presence Detect Changed event.330 */331 if (pciehp_device_replaced(ctrl)) {332 ctrl_dbg(ctrl, "device replaced during system sleep\n");333 pci_walk_bus(ctrl->pcie->port->subordinate,334 pci_dev_set_disconnected, NULL);335 pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);336 }337 }338 339 return 0;340}341#endif342 343static int pciehp_resume(struct pcie_device *dev)344{345 struct controller *ctrl = get_service_data(dev);346 347 if (pme_is_native(dev))348 pcie_enable_interrupt(ctrl);349 350 pciehp_check_presence(ctrl);351 352 return 0;353}354 355static int pciehp_runtime_suspend(struct pcie_device *dev)356{357 pciehp_disable_interrupt(dev);358 return 0;359}360 361static int pciehp_runtime_resume(struct pcie_device *dev)362{363 struct controller *ctrl = get_service_data(dev);364 365 /* pci_restore_state() just wrote to the Slot Control register */366 ctrl->cmd_started = jiffies;367 ctrl->cmd_busy = true;368 369 /* clear spurious events from rediscovery of inserted card */370 if ((ctrl->state == ON_STATE || ctrl->state == BLINKINGOFF_STATE) &&371 pme_is_native(dev))372 pcie_clear_hotplug_events(ctrl);373 374 return pciehp_resume(dev);375}376#endif /* PM */377 378static struct pcie_port_service_driver hpdriver_portdrv = {379 .name = "pciehp",380 .port_type = PCIE_ANY_PORT,381 .service = PCIE_PORT_SERVICE_HP,382 383 .probe = pciehp_probe,384 .remove = pciehp_remove,385 386#ifdef CONFIG_PM387#ifdef CONFIG_PM_SLEEP388 .suspend = pciehp_suspend,389 .resume_noirq = pciehp_resume_noirq,390 .resume = pciehp_resume,391#endif392 .runtime_suspend = pciehp_runtime_suspend,393 .runtime_resume = pciehp_runtime_resume,394#endif /* PM */395 396 .slot_reset = pciehp_slot_reset,397};398 399int __init pcie_hp_init(void)400{401 int retval = 0;402 403 retval = pcie_port_service_register(&hpdriver_portdrv);404 pr_debug("pcie_port_service_register = %d\n", retval);405 if (retval)406 pr_debug("Failure to register service\n");407 408 return retval;409}410