linux/drivers/pci/hotplug/s390_pci_hpc.c
<<
>>
Prefs
   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
  23static int zpci_fn_configured(enum zpci_state state)
  24{
  25        return state == ZPCI_FN_STATE_CONFIGURED ||
  26               state == ZPCI_FN_STATE_ONLINE;
  27}
  28
  29static inline int zdev_configure(struct zpci_dev *zdev)
  30{
  31        int ret = sclp_pci_configure(zdev->fid);
  32
  33        zpci_dbg(3, "conf fid:%x, rc:%d\n", zdev->fid, ret);
  34        if (!ret)
  35                zdev->state = ZPCI_FN_STATE_CONFIGURED;
  36
  37        return ret;
  38}
  39
  40static inline int zdev_deconfigure(struct zpci_dev *zdev)
  41{
  42        int ret = sclp_pci_deconfigure(zdev->fid);
  43
  44        zpci_dbg(3, "deconf fid:%x, rc:%d\n", zdev->fid, ret);
  45        if (!ret)
  46                zdev->state = ZPCI_FN_STATE_STANDBY;
  47
  48        return ret;
  49}
  50
  51static int enable_slot(struct hotplug_slot *hotplug_slot)
  52{
  53        struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev,
  54                                             hotplug_slot);
  55        struct zpci_bus *zbus = zdev->zbus;
  56        int rc;
  57
  58        if (zdev->state != ZPCI_FN_STATE_STANDBY)
  59                return -EIO;
  60
  61        rc = zdev_configure(zdev);
  62        if (rc)
  63                return rc;
  64
  65        rc = zpci_enable_device(zdev);
  66        if (rc)
  67                goto out_deconfigure;
  68
  69        pci_scan_slot(zbus->bus, zdev->devfn);
  70        pci_lock_rescan_remove();
  71        pci_bus_add_devices(zbus->bus);
  72        pci_unlock_rescan_remove();
  73
  74        return rc;
  75
  76out_deconfigure:
  77        zdev_deconfigure(zdev);
  78        return rc;
  79}
  80
  81static int disable_slot(struct hotplug_slot *hotplug_slot)
  82{
  83        struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev,
  84                                             hotplug_slot);
  85        struct pci_dev *pdev;
  86        int rc;
  87
  88        if (!zpci_fn_configured(zdev->state))
  89                return -EIO;
  90
  91        pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn);
  92        if (pdev && pci_num_vf(pdev)) {
  93                pci_dev_put(pdev);
  94                return -EBUSY;
  95        }
  96
  97        zpci_remove_device(zdev);
  98
  99        rc = zpci_disable_device(zdev);
 100        if (rc)
 101                return rc;
 102
 103        return zdev_deconfigure(zdev);
 104}
 105
 106static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
 107{
 108        struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev,
 109                                             hotplug_slot);
 110
 111        switch (zdev->state) {
 112        case ZPCI_FN_STATE_STANDBY:
 113                *value = 0;
 114                break;
 115        default:
 116                *value = 1;
 117                break;
 118        }
 119        return 0;
 120}
 121
 122static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
 123{
 124        /* if the slot exits it always contains a function */
 125        *value = 1;
 126        return 0;
 127}
 128
 129static const struct hotplug_slot_ops s390_hotplug_slot_ops = {
 130        .enable_slot =          enable_slot,
 131        .disable_slot =         disable_slot,
 132        .get_power_status =     get_power_status,
 133        .get_adapter_status =   get_adapter_status,
 134};
 135
 136int zpci_init_slot(struct zpci_dev *zdev)
 137{
 138        char name[SLOT_NAME_SIZE];
 139        struct zpci_bus *zbus = zdev->zbus;
 140
 141        zdev->hotplug_slot.ops = &s390_hotplug_slot_ops;
 142
 143        snprintf(name, SLOT_NAME_SIZE, "%08x", zdev->fid);
 144        return pci_hp_register(&zdev->hotplug_slot, zbus->bus,
 145                               zdev->devfn, name);
 146}
 147
 148void zpci_exit_slot(struct zpci_dev *zdev)
 149{
 150        pci_hp_deregister(&zdev->hotplug_slot);
 151}
 152