linux/drivers/pci/hotplug/shpchp_pci.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Standard 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 */
  15
  16#include <linux/module.h>
  17#include <linux/kernel.h>
  18#include <linux/types.h>
  19#include <linux/pci.h>
  20#include "../pci.h"
  21#include "shpchp.h"
  22
  23int shpchp_configure_device(struct slot *p_slot)
  24{
  25        struct pci_dev *dev;
  26        struct controller *ctrl = p_slot->ctrl;
  27        struct pci_dev *bridge = ctrl->pci_dev;
  28        struct pci_bus *parent = bridge->subordinate;
  29        int num, ret = 0;
  30
  31        pci_lock_rescan_remove();
  32
  33        dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0));
  34        if (dev) {
  35                ctrl_err(ctrl, "Device %s already exists at %04x:%02x:%02x, cannot hot-add\n",
  36                         pci_name(dev), pci_domain_nr(parent),
  37                         p_slot->bus, p_slot->device);
  38                pci_dev_put(dev);
  39                ret = -EINVAL;
  40                goto out;
  41        }
  42
  43        num = pci_scan_slot(parent, PCI_DEVFN(p_slot->device, 0));
  44        if (num == 0) {
  45                ctrl_err(ctrl, "No new device found\n");
  46                ret = -ENODEV;
  47                goto out;
  48        }
  49
  50        for_each_pci_bridge(dev, parent) {
  51                if (PCI_SLOT(dev->devfn) == p_slot->device)
  52                        pci_hp_add_bridge(dev);
  53        }
  54
  55        pci_assign_unassigned_bridge_resources(bridge);
  56        pcie_bus_configure_settings(parent);
  57        pci_bus_add_devices(parent);
  58
  59 out:
  60        pci_unlock_rescan_remove();
  61        return ret;
  62}
  63
  64void shpchp_unconfigure_device(struct slot *p_slot)
  65{
  66        struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
  67        struct pci_dev *dev, *temp;
  68        struct controller *ctrl = p_slot->ctrl;
  69
  70        ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:%02x\n",
  71                 __func__, pci_domain_nr(parent), p_slot->bus, p_slot->device);
  72
  73        pci_lock_rescan_remove();
  74
  75        list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) {
  76                if (PCI_SLOT(dev->devfn) != p_slot->device)
  77                        continue;
  78
  79                pci_dev_get(dev);
  80                pci_stop_and_remove_bus_device(dev);
  81                pci_dev_put(dev);
  82        }
  83
  84        pci_unlock_rescan_remove();
  85}
  86