Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Standard 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 #include <linux/module.h>
0017 #include <linux/kernel.h>
0018 #include <linux/types.h>
0019 #include <linux/pci.h>
0020 #include "../pci.h"
0021 #include "shpchp.h"
0022 
0023 int shpchp_configure_device(struct slot *p_slot)
0024 {
0025     struct pci_dev *dev;
0026     struct controller *ctrl = p_slot->ctrl;
0027     struct pci_dev *bridge = ctrl->pci_dev;
0028     struct pci_bus *parent = bridge->subordinate;
0029     int num, ret = 0;
0030 
0031     pci_lock_rescan_remove();
0032 
0033     dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0));
0034     if (dev) {
0035         ctrl_err(ctrl, "Device %s already exists at %04x:%02x:%02x, cannot hot-add\n",
0036              pci_name(dev), pci_domain_nr(parent),
0037              p_slot->bus, p_slot->device);
0038         pci_dev_put(dev);
0039         ret = -EINVAL;
0040         goto out;
0041     }
0042 
0043     num = pci_scan_slot(parent, PCI_DEVFN(p_slot->device, 0));
0044     if (num == 0) {
0045         ctrl_err(ctrl, "No new device found\n");
0046         ret = -ENODEV;
0047         goto out;
0048     }
0049 
0050     for_each_pci_bridge(dev, parent) {
0051         if (PCI_SLOT(dev->devfn) == p_slot->device)
0052             pci_hp_add_bridge(dev);
0053     }
0054 
0055     pci_assign_unassigned_bridge_resources(bridge);
0056     pcie_bus_configure_settings(parent);
0057     pci_bus_add_devices(parent);
0058 
0059  out:
0060     pci_unlock_rescan_remove();
0061     return ret;
0062 }
0063 
0064 void shpchp_unconfigure_device(struct slot *p_slot)
0065 {
0066     struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
0067     struct pci_dev *dev, *temp;
0068     struct controller *ctrl = p_slot->ctrl;
0069 
0070     ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:%02x\n",
0071          __func__, pci_domain_nr(parent), p_slot->bus, p_slot->device);
0072 
0073     pci_lock_rescan_remove();
0074 
0075     list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) {
0076         if (PCI_SLOT(dev->devfn) != p_slot->device)
0077             continue;
0078 
0079         pci_dev_get(dev);
0080         pci_stop_and_remove_bus_device(dev);
0081         pci_dev_put(dev);
0082     }
0083 
0084     pci_unlock_rescan_remove();
0085 }