root/drivers/pci/hotplug/s390_pci_hpc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zpci_fn_configured
  2. to_slot
  3. slot_configure
  4. slot_deconfigure
  5. enable_slot
  6. disable_slot
  7. get_power_status
  8. get_adapter_status
  9. zpci_init_slot
  10. zpci_exit_slot

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * PCI Hot Plug Controller Driver for System z
   4  *
   5  * Copyright 2012 IBM Corp.
   6  *
   7  * Author(s):
   8  *   Jan Glauber <jang@linux.vnet.ibm.com>
   9  */
  10 
  11 #define KMSG_COMPONENT "zpci"
  12 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  13 
  14 #include <linux/kernel.h>
  15 #include <linux/slab.h>
  16 #include <linux/pci.h>
  17 #include <linux/pci_hotplug.h>
  18 #include <asm/pci_debug.h>
  19 #include <asm/sclp.h>
  20 
  21 #define SLOT_NAME_SIZE  10
  22 static LIST_HEAD(s390_hotplug_slot_list);
  23 
  24 static int zpci_fn_configured(enum zpci_state state)
  25 {
  26         return state == ZPCI_FN_STATE_CONFIGURED ||
  27                state == ZPCI_FN_STATE_ONLINE;
  28 }
  29 
  30 /*
  31  * struct slot - slot information for each *physical* slot
  32  */
  33 struct slot {
  34         struct list_head slot_list;
  35         struct hotplug_slot hotplug_slot;
  36         struct zpci_dev *zdev;
  37 };
  38 
  39 static inline struct slot *to_slot(struct hotplug_slot *hotplug_slot)
  40 {
  41         return container_of(hotplug_slot, struct slot, hotplug_slot);
  42 }
  43 
  44 static inline int slot_configure(struct slot *slot)
  45 {
  46         int ret = sclp_pci_configure(slot->zdev->fid);
  47 
  48         zpci_dbg(3, "conf fid:%x, rc:%d\n", slot->zdev->fid, ret);
  49         if (!ret)
  50                 slot->zdev->state = ZPCI_FN_STATE_CONFIGURED;
  51 
  52         return ret;
  53 }
  54 
  55 static inline int slot_deconfigure(struct slot *slot)
  56 {
  57         int ret = sclp_pci_deconfigure(slot->zdev->fid);
  58 
  59         zpci_dbg(3, "deconf fid:%x, rc:%d\n", slot->zdev->fid, ret);
  60         if (!ret)
  61                 slot->zdev->state = ZPCI_FN_STATE_STANDBY;
  62 
  63         return ret;
  64 }
  65 
  66 static int enable_slot(struct hotplug_slot *hotplug_slot)
  67 {
  68         struct slot *slot = to_slot(hotplug_slot);
  69         int rc;
  70 
  71         if (slot->zdev->state != ZPCI_FN_STATE_STANDBY)
  72                 return -EIO;
  73 
  74         rc = slot_configure(slot);
  75         if (rc)
  76                 return rc;
  77 
  78         rc = zpci_enable_device(slot->zdev);
  79         if (rc)
  80                 goto out_deconfigure;
  81 
  82         pci_scan_slot(slot->zdev->bus, ZPCI_DEVFN);
  83         pci_lock_rescan_remove();
  84         pci_bus_add_devices(slot->zdev->bus);
  85         pci_unlock_rescan_remove();
  86 
  87         return rc;
  88 
  89 out_deconfigure:
  90         slot_deconfigure(slot);
  91         return rc;
  92 }
  93 
  94 static int disable_slot(struct hotplug_slot *hotplug_slot)
  95 {
  96         struct slot *slot = to_slot(hotplug_slot);
  97         struct pci_dev *pdev;
  98         int rc;
  99 
 100         if (!zpci_fn_configured(slot->zdev->state))
 101                 return -EIO;
 102 
 103         pdev = pci_get_slot(slot->zdev->bus, ZPCI_DEVFN);
 104         if (pdev) {
 105                 pci_stop_and_remove_bus_device_locked(pdev);
 106                 pci_dev_put(pdev);
 107         }
 108 
 109         rc = zpci_disable_device(slot->zdev);
 110         if (rc)
 111                 return rc;
 112 
 113         return slot_deconfigure(slot);
 114 }
 115 
 116 static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
 117 {
 118         struct slot *slot = to_slot(hotplug_slot);
 119 
 120         switch (slot->zdev->state) {
 121         case ZPCI_FN_STATE_STANDBY:
 122                 *value = 0;
 123                 break;
 124         default:
 125                 *value = 1;
 126                 break;
 127         }
 128         return 0;
 129 }
 130 
 131 static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
 132 {
 133         /* if the slot exits it always contains a function */
 134         *value = 1;
 135         return 0;
 136 }
 137 
 138 static const struct hotplug_slot_ops s390_hotplug_slot_ops = {
 139         .enable_slot =          enable_slot,
 140         .disable_slot =         disable_slot,
 141         .get_power_status =     get_power_status,
 142         .get_adapter_status =   get_adapter_status,
 143 };
 144 
 145 int zpci_init_slot(struct zpci_dev *zdev)
 146 {
 147         char name[SLOT_NAME_SIZE];
 148         struct slot *slot;
 149         int rc;
 150 
 151         if (!zdev)
 152                 return 0;
 153 
 154         slot = kzalloc(sizeof(*slot), GFP_KERNEL);
 155         if (!slot)
 156                 goto error;
 157 
 158         slot->zdev = zdev;
 159         slot->hotplug_slot.ops = &s390_hotplug_slot_ops;
 160 
 161         snprintf(name, SLOT_NAME_SIZE, "%08x", zdev->fid);
 162         rc = pci_hp_register(&slot->hotplug_slot, zdev->bus,
 163                              ZPCI_DEVFN, name);
 164         if (rc)
 165                 goto error_reg;
 166 
 167         list_add(&slot->slot_list, &s390_hotplug_slot_list);
 168         return 0;
 169 
 170 error_reg:
 171         kfree(slot);
 172 error:
 173         return -ENOMEM;
 174 }
 175 
 176 void zpci_exit_slot(struct zpci_dev *zdev)
 177 {
 178         struct slot *slot, *next;
 179 
 180         list_for_each_entry_safe(slot, next, &s390_hotplug_slot_list,
 181                                  slot_list) {
 182                 if (slot->zdev != zdev)
 183                         continue;
 184                 list_del(&slot->slot_list);
 185                 pci_hp_deregister(&slot->hotplug_slot);
 186                 kfree(slot);
 187         }
 188 }

/* [<][>][^][v][top][bottom][index][help] */