Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * PCI Express Hot Plug Controller Driver
0004  *
0005  * Copyright (C) 1995,2001 Compaq Computer Corporation
0006  * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
0007  * Copyright (C) 2001 IBM Corp.
0008  * Copyright (C) 2003-2004 Intel Corporation
0009  *
0010  * All rights reserved.
0011  *
0012  * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
0013  *
0014  */
0015 
0016 #define dev_fmt(fmt) "pciehp: " fmt
0017 
0018 #include <linux/kernel.h>
0019 #include <linux/types.h>
0020 #include <linux/pm_runtime.h>
0021 #include <linux/pci.h>
0022 #include "pciehp.h"
0023 
0024 /* The following routines constitute the bulk of the
0025    hotplug controller logic
0026  */
0027 
0028 #define SAFE_REMOVAL     true
0029 #define SURPRISE_REMOVAL false
0030 
0031 static void set_slot_off(struct controller *ctrl)
0032 {
0033     /*
0034      * Turn off slot, turn on attention indicator, turn off power
0035      * indicator
0036      */
0037     if (POWER_CTRL(ctrl)) {
0038         pciehp_power_off_slot(ctrl);
0039 
0040         /*
0041          * After turning power off, we must wait for at least 1 second
0042          * before taking any action that relies on power having been
0043          * removed from the slot/adapter.
0044          */
0045         msleep(1000);
0046     }
0047 
0048     pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
0049                   PCI_EXP_SLTCTL_ATTN_IND_ON);
0050 }
0051 
0052 /**
0053  * board_added - Called after a board has been added to the system.
0054  * @ctrl: PCIe hotplug controller where board is added
0055  *
0056  * Turns power on for the board.
0057  * Configures board.
0058  */
0059 static int board_added(struct controller *ctrl)
0060 {
0061     int retval = 0;
0062     struct pci_bus *parent = ctrl->pcie->port->subordinate;
0063 
0064     if (POWER_CTRL(ctrl)) {
0065         /* Power on slot */
0066         retval = pciehp_power_on_slot(ctrl);
0067         if (retval)
0068             return retval;
0069     }
0070 
0071     pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK,
0072                   INDICATOR_NOOP);
0073 
0074     /* Check link training status */
0075     retval = pciehp_check_link_status(ctrl);
0076     if (retval)
0077         goto err_exit;
0078 
0079     /* Check for a power fault */
0080     if (ctrl->power_fault_detected || pciehp_query_power_fault(ctrl)) {
0081         ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(ctrl));
0082         retval = -EIO;
0083         goto err_exit;
0084     }
0085 
0086     retval = pciehp_configure_device(ctrl);
0087     if (retval) {
0088         if (retval != -EEXIST) {
0089             ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n",
0090                  pci_domain_nr(parent), parent->number);
0091             goto err_exit;
0092         }
0093     }
0094 
0095     pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON,
0096                   PCI_EXP_SLTCTL_ATTN_IND_OFF);
0097     return 0;
0098 
0099 err_exit:
0100     set_slot_off(ctrl);
0101     return retval;
0102 }
0103 
0104 /**
0105  * remove_board - Turn off slot and Power Indicator
0106  * @ctrl: PCIe hotplug controller where board is being removed
0107  * @safe_removal: whether the board is safely removed (versus surprise removed)
0108  */
0109 static void remove_board(struct controller *ctrl, bool safe_removal)
0110 {
0111     pciehp_unconfigure_device(ctrl, safe_removal);
0112 
0113     if (POWER_CTRL(ctrl)) {
0114         pciehp_power_off_slot(ctrl);
0115 
0116         /*
0117          * After turning power off, we must wait for at least 1 second
0118          * before taking any action that relies on power having been
0119          * removed from the slot/adapter.
0120          */
0121         msleep(1000);
0122 
0123         /* Ignore link or presence changes caused by power off */
0124         atomic_and(~(PCI_EXP_SLTSTA_DLLSC | PCI_EXP_SLTSTA_PDC),
0125                &ctrl->pending_events);
0126     }
0127 
0128     pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
0129                   INDICATOR_NOOP);
0130 }
0131 
0132 static int pciehp_enable_slot(struct controller *ctrl);
0133 static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal);
0134 
0135 void pciehp_request(struct controller *ctrl, int action)
0136 {
0137     atomic_or(action, &ctrl->pending_events);
0138     if (!pciehp_poll_mode)
0139         irq_wake_thread(ctrl->pcie->irq, ctrl);
0140 }
0141 
0142 void pciehp_queue_pushbutton_work(struct work_struct *work)
0143 {
0144     struct controller *ctrl = container_of(work, struct controller,
0145                            button_work.work);
0146 
0147     mutex_lock(&ctrl->state_lock);
0148     switch (ctrl->state) {
0149     case BLINKINGOFF_STATE:
0150         pciehp_request(ctrl, DISABLE_SLOT);
0151         break;
0152     case BLINKINGON_STATE:
0153         pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
0154         break;
0155     default:
0156         break;
0157     }
0158     mutex_unlock(&ctrl->state_lock);
0159 }
0160 
0161 void pciehp_handle_button_press(struct controller *ctrl)
0162 {
0163     mutex_lock(&ctrl->state_lock);
0164     switch (ctrl->state) {
0165     case OFF_STATE:
0166     case ON_STATE:
0167         if (ctrl->state == ON_STATE) {
0168             ctrl->state = BLINKINGOFF_STATE;
0169             ctrl_info(ctrl, "Slot(%s): Powering off due to button press\n",
0170                   slot_name(ctrl));
0171         } else {
0172             ctrl->state = BLINKINGON_STATE;
0173             ctrl_info(ctrl, "Slot(%s) Powering on due to button press\n",
0174                   slot_name(ctrl));
0175         }
0176         /* blink power indicator and turn off attention */
0177         pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK,
0178                       PCI_EXP_SLTCTL_ATTN_IND_OFF);
0179         schedule_delayed_work(&ctrl->button_work, 5 * HZ);
0180         break;
0181     case BLINKINGOFF_STATE:
0182     case BLINKINGON_STATE:
0183         /*
0184          * Cancel if we are still blinking; this means that we
0185          * press the attention again before the 5 sec. limit
0186          * expires to cancel hot-add or hot-remove
0187          */
0188         ctrl_info(ctrl, "Slot(%s): Button cancel\n", slot_name(ctrl));
0189         cancel_delayed_work(&ctrl->button_work);
0190         if (ctrl->state == BLINKINGOFF_STATE) {
0191             ctrl->state = ON_STATE;
0192             pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON,
0193                           PCI_EXP_SLTCTL_ATTN_IND_OFF);
0194         } else {
0195             ctrl->state = OFF_STATE;
0196             pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
0197                           PCI_EXP_SLTCTL_ATTN_IND_OFF);
0198         }
0199         ctrl_info(ctrl, "Slot(%s): Action canceled due to button press\n",
0200               slot_name(ctrl));
0201         break;
0202     default:
0203         ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n",
0204              slot_name(ctrl), ctrl->state);
0205         break;
0206     }
0207     mutex_unlock(&ctrl->state_lock);
0208 }
0209 
0210 void pciehp_handle_disable_request(struct controller *ctrl)
0211 {
0212     mutex_lock(&ctrl->state_lock);
0213     switch (ctrl->state) {
0214     case BLINKINGON_STATE:
0215     case BLINKINGOFF_STATE:
0216         cancel_delayed_work(&ctrl->button_work);
0217         break;
0218     }
0219     ctrl->state = POWEROFF_STATE;
0220     mutex_unlock(&ctrl->state_lock);
0221 
0222     ctrl->request_result = pciehp_disable_slot(ctrl, SAFE_REMOVAL);
0223 }
0224 
0225 void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events)
0226 {
0227     int present, link_active;
0228 
0229     /*
0230      * If the slot is on and presence or link has changed, turn it off.
0231      * Even if it's occupied again, we cannot assume the card is the same.
0232      */
0233     mutex_lock(&ctrl->state_lock);
0234     switch (ctrl->state) {
0235     case BLINKINGOFF_STATE:
0236         cancel_delayed_work(&ctrl->button_work);
0237         fallthrough;
0238     case ON_STATE:
0239         ctrl->state = POWEROFF_STATE;
0240         mutex_unlock(&ctrl->state_lock);
0241         if (events & PCI_EXP_SLTSTA_DLLSC)
0242             ctrl_info(ctrl, "Slot(%s): Link Down\n",
0243                   slot_name(ctrl));
0244         if (events & PCI_EXP_SLTSTA_PDC)
0245             ctrl_info(ctrl, "Slot(%s): Card not present\n",
0246                   slot_name(ctrl));
0247         pciehp_disable_slot(ctrl, SURPRISE_REMOVAL);
0248         break;
0249     default:
0250         mutex_unlock(&ctrl->state_lock);
0251         break;
0252     }
0253 
0254     /* Turn the slot on if it's occupied or link is up */
0255     mutex_lock(&ctrl->state_lock);
0256     present = pciehp_card_present(ctrl);
0257     link_active = pciehp_check_link_active(ctrl);
0258     if (present <= 0 && link_active <= 0) {
0259         mutex_unlock(&ctrl->state_lock);
0260         return;
0261     }
0262 
0263     switch (ctrl->state) {
0264     case BLINKINGON_STATE:
0265         cancel_delayed_work(&ctrl->button_work);
0266         fallthrough;
0267     case OFF_STATE:
0268         ctrl->state = POWERON_STATE;
0269         mutex_unlock(&ctrl->state_lock);
0270         if (present)
0271             ctrl_info(ctrl, "Slot(%s): Card present\n",
0272                   slot_name(ctrl));
0273         if (link_active)
0274             ctrl_info(ctrl, "Slot(%s): Link Up\n",
0275                   slot_name(ctrl));
0276         ctrl->request_result = pciehp_enable_slot(ctrl);
0277         break;
0278     default:
0279         mutex_unlock(&ctrl->state_lock);
0280         break;
0281     }
0282 }
0283 
0284 static int __pciehp_enable_slot(struct controller *ctrl)
0285 {
0286     u8 getstatus = 0;
0287 
0288     if (MRL_SENS(ctrl)) {
0289         pciehp_get_latch_status(ctrl, &getstatus);
0290         if (getstatus) {
0291             ctrl_info(ctrl, "Slot(%s): Latch open\n",
0292                   slot_name(ctrl));
0293             return -ENODEV;
0294         }
0295     }
0296 
0297     if (POWER_CTRL(ctrl)) {
0298         pciehp_get_power_status(ctrl, &getstatus);
0299         if (getstatus) {
0300             ctrl_info(ctrl, "Slot(%s): Already enabled\n",
0301                   slot_name(ctrl));
0302             return 0;
0303         }
0304     }
0305 
0306     return board_added(ctrl);
0307 }
0308 
0309 static int pciehp_enable_slot(struct controller *ctrl)
0310 {
0311     int ret;
0312 
0313     pm_runtime_get_sync(&ctrl->pcie->port->dev);
0314     ret = __pciehp_enable_slot(ctrl);
0315     if (ret && ATTN_BUTTN(ctrl))
0316         /* may be blinking */
0317         pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
0318                       INDICATOR_NOOP);
0319     pm_runtime_put(&ctrl->pcie->port->dev);
0320 
0321     mutex_lock(&ctrl->state_lock);
0322     ctrl->state = ret ? OFF_STATE : ON_STATE;
0323     mutex_unlock(&ctrl->state_lock);
0324 
0325     return ret;
0326 }
0327 
0328 static int __pciehp_disable_slot(struct controller *ctrl, bool safe_removal)
0329 {
0330     u8 getstatus = 0;
0331 
0332     if (POWER_CTRL(ctrl)) {
0333         pciehp_get_power_status(ctrl, &getstatus);
0334         if (!getstatus) {
0335             ctrl_info(ctrl, "Slot(%s): Already disabled\n",
0336                   slot_name(ctrl));
0337             return -EINVAL;
0338         }
0339     }
0340 
0341     remove_board(ctrl, safe_removal);
0342     return 0;
0343 }
0344 
0345 static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal)
0346 {
0347     int ret;
0348 
0349     pm_runtime_get_sync(&ctrl->pcie->port->dev);
0350     ret = __pciehp_disable_slot(ctrl, safe_removal);
0351     pm_runtime_put(&ctrl->pcie->port->dev);
0352 
0353     mutex_lock(&ctrl->state_lock);
0354     ctrl->state = OFF_STATE;
0355     mutex_unlock(&ctrl->state_lock);
0356 
0357     return ret;
0358 }
0359 
0360 int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot)
0361 {
0362     struct controller *ctrl = to_ctrl(hotplug_slot);
0363 
0364     mutex_lock(&ctrl->state_lock);
0365     switch (ctrl->state) {
0366     case BLINKINGON_STATE:
0367     case OFF_STATE:
0368         mutex_unlock(&ctrl->state_lock);
0369         /*
0370          * The IRQ thread becomes a no-op if the user pulls out the
0371          * card before the thread wakes up, so initialize to -ENODEV.
0372          */
0373         ctrl->request_result = -ENODEV;
0374         pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
0375         wait_event(ctrl->requester,
0376                !atomic_read(&ctrl->pending_events) &&
0377                !ctrl->ist_running);
0378         return ctrl->request_result;
0379     case POWERON_STATE:
0380         ctrl_info(ctrl, "Slot(%s): Already in powering on state\n",
0381               slot_name(ctrl));
0382         break;
0383     case BLINKINGOFF_STATE:
0384     case ON_STATE:
0385     case POWEROFF_STATE:
0386         ctrl_info(ctrl, "Slot(%s): Already enabled\n",
0387               slot_name(ctrl));
0388         break;
0389     default:
0390         ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
0391              slot_name(ctrl), ctrl->state);
0392         break;
0393     }
0394     mutex_unlock(&ctrl->state_lock);
0395 
0396     return -ENODEV;
0397 }
0398 
0399 int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot)
0400 {
0401     struct controller *ctrl = to_ctrl(hotplug_slot);
0402 
0403     mutex_lock(&ctrl->state_lock);
0404     switch (ctrl->state) {
0405     case BLINKINGOFF_STATE:
0406     case ON_STATE:
0407         mutex_unlock(&ctrl->state_lock);
0408         pciehp_request(ctrl, DISABLE_SLOT);
0409         wait_event(ctrl->requester,
0410                !atomic_read(&ctrl->pending_events) &&
0411                !ctrl->ist_running);
0412         return ctrl->request_result;
0413     case POWEROFF_STATE:
0414         ctrl_info(ctrl, "Slot(%s): Already in powering off state\n",
0415               slot_name(ctrl));
0416         break;
0417     case BLINKINGON_STATE:
0418     case OFF_STATE:
0419     case POWERON_STATE:
0420         ctrl_info(ctrl, "Slot(%s): Already disabled\n",
0421               slot_name(ctrl));
0422         break;
0423     default:
0424         ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
0425              slot_name(ctrl), ctrl->state);
0426         break;
0427     }
0428     mutex_unlock(&ctrl->state_lock);
0429 
0430     return -ENODEV;
0431 }