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 | |
23 | static int enable_slot(struct hotplug_slot *hotplug_slot) |
24 | { |
25 | struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev, |
26 | hotplug_slot); |
27 | int rc; |
28 | |
29 | mutex_lock(&zdev->state_lock); |
30 | if (zdev->state != ZPCI_FN_STATE_STANDBY) { |
31 | rc = -EIO; |
32 | goto out; |
33 | } |
34 | |
35 | rc = sclp_pci_configure(zdev->fid); |
36 | zpci_dbg(3, "conf fid:%x, rc:%d\n" , zdev->fid, rc); |
37 | if (rc) |
38 | goto out; |
39 | zdev->state = ZPCI_FN_STATE_CONFIGURED; |
40 | |
41 | rc = zpci_scan_configured_device(zdev, zdev->fh); |
42 | out: |
43 | mutex_unlock(lock: &zdev->state_lock); |
44 | return rc; |
45 | } |
46 | |
47 | static int disable_slot(struct hotplug_slot *hotplug_slot) |
48 | { |
49 | struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev, |
50 | hotplug_slot); |
51 | struct pci_dev *pdev = NULL; |
52 | int rc; |
53 | |
54 | mutex_lock(&zdev->state_lock); |
55 | if (zdev->state != ZPCI_FN_STATE_CONFIGURED) { |
56 | rc = -EIO; |
57 | goto out; |
58 | } |
59 | |
60 | pdev = pci_get_slot(bus: zdev->zbus->bus, devfn: zdev->devfn); |
61 | if (pdev && pci_num_vf(dev: pdev)) { |
62 | pci_dev_put(dev: pdev); |
63 | rc = -EBUSY; |
64 | goto out; |
65 | } |
66 | |
67 | rc = zpci_deconfigure_device(zdev); |
68 | out: |
69 | mutex_unlock(lock: &zdev->state_lock); |
70 | if (pdev) |
71 | pci_dev_put(dev: pdev); |
72 | return rc; |
73 | } |
74 | |
75 | static int reset_slot(struct hotplug_slot *hotplug_slot, bool probe) |
76 | { |
77 | struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev, |
78 | hotplug_slot); |
79 | int rc = -EIO; |
80 | |
81 | /* |
82 | * If we can't get the zdev->state_lock the device state is |
83 | * currently undergoing a transition and we bail out - just |
84 | * the same as if the device's state is not configured at all. |
85 | */ |
86 | if (!mutex_trylock(lock: &zdev->state_lock)) |
87 | return rc; |
88 | |
89 | /* We can reset only if the function is configured */ |
90 | if (zdev->state != ZPCI_FN_STATE_CONFIGURED) |
91 | goto out; |
92 | |
93 | if (probe) { |
94 | rc = 0; |
95 | goto out; |
96 | } |
97 | |
98 | rc = zpci_hot_reset_device(zdev); |
99 | out: |
100 | mutex_unlock(lock: &zdev->state_lock); |
101 | return rc; |
102 | } |
103 | |
104 | static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) |
105 | { |
106 | struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev, |
107 | hotplug_slot); |
108 | |
109 | *value = zpci_is_device_configured(zdev) ? 1 : 0; |
110 | return 0; |
111 | } |
112 | |
113 | static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) |
114 | { |
115 | /* if the slot exits it always contains a function */ |
116 | *value = 1; |
117 | return 0; |
118 | } |
119 | |
120 | static const struct hotplug_slot_ops s390_hotplug_slot_ops = { |
121 | .enable_slot = enable_slot, |
122 | .disable_slot = disable_slot, |
123 | .reset_slot = reset_slot, |
124 | .get_power_status = get_power_status, |
125 | .get_adapter_status = get_adapter_status, |
126 | }; |
127 | |
128 | int zpci_init_slot(struct zpci_dev *zdev) |
129 | { |
130 | char name[SLOT_NAME_SIZE]; |
131 | struct zpci_bus *zbus = zdev->zbus; |
132 | |
133 | zdev->hotplug_slot.ops = &s390_hotplug_slot_ops; |
134 | |
135 | snprintf(buf: name, SLOT_NAME_SIZE, fmt: "%08x" , zdev->fid); |
136 | return pci_hp_register(&zdev->hotplug_slot, zbus->bus, |
137 | zdev->devfn, name); |
138 | } |
139 | |
140 | void zpci_exit_slot(struct zpci_dev *zdev) |
141 | { |
142 | pci_hp_deregister(slot: &zdev->hotplug_slot); |
143 | } |
144 | |