GNU Linux-libre 4.19.268-gnu1
[releases.git] / drivers / pci / hotplug / cpci_hotplug_pci.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * CompactPCI Hot Plug Driver PCI functions
4  *
5  * Copyright (C) 2002,2005 by SOMA Networks, Inc.
6  *
7  * All rights reserved.
8  *
9  * Send feedback to <scottm@somanetworks.com>
10  */
11
12 #include <linux/module.h>
13 #include <linux/kernel.h>
14 #include <linux/pci.h>
15 #include <linux/pci_hotplug.h>
16 #include <linux/proc_fs.h>
17 #include "../pci.h"
18 #include "cpci_hotplug.h"
19
20 #define MY_NAME "cpci_hotplug"
21
22 extern int cpci_debug;
23
24 #define dbg(format, arg...)                                     \
25         do {                                                    \
26                 if (cpci_debug)                                 \
27                         printk(KERN_DEBUG "%s: " format "\n",   \
28                                 MY_NAME, ## arg);               \
29         } while (0)
30 #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME, ## arg)
31 #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME, ## arg)
32 #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME, ## arg)
33
34
35 u8 cpci_get_attention_status(struct slot *slot)
36 {
37         int hs_cap;
38         u16 hs_csr;
39
40         hs_cap = pci_bus_find_capability(slot->bus,
41                                          slot->devfn,
42                                          PCI_CAP_ID_CHSWP);
43         if (!hs_cap)
44                 return 0;
45
46         if (pci_bus_read_config_word(slot->bus,
47                                      slot->devfn,
48                                      hs_cap + 2,
49                                      &hs_csr))
50                 return 0;
51
52         return hs_csr & 0x0008 ? 1 : 0;
53 }
54
55 int cpci_set_attention_status(struct slot *slot, int status)
56 {
57         int hs_cap;
58         u16 hs_csr;
59
60         hs_cap = pci_bus_find_capability(slot->bus,
61                                          slot->devfn,
62                                          PCI_CAP_ID_CHSWP);
63         if (!hs_cap)
64                 return 0;
65         if (pci_bus_read_config_word(slot->bus,
66                                      slot->devfn,
67                                      hs_cap + 2,
68                                      &hs_csr))
69                 return 0;
70         if (status)
71                 hs_csr |= HS_CSR_LOO;
72         else
73                 hs_csr &= ~HS_CSR_LOO;
74         if (pci_bus_write_config_word(slot->bus,
75                                       slot->devfn,
76                                       hs_cap + 2,
77                                       hs_csr))
78                 return 0;
79         return 1;
80 }
81
82 u16 cpci_get_hs_csr(struct slot *slot)
83 {
84         int hs_cap;
85         u16 hs_csr;
86
87         hs_cap = pci_bus_find_capability(slot->bus,
88                                          slot->devfn,
89                                          PCI_CAP_ID_CHSWP);
90         if (!hs_cap)
91                 return 0xFFFF;
92         if (pci_bus_read_config_word(slot->bus,
93                                      slot->devfn,
94                                      hs_cap + 2,
95                                      &hs_csr))
96                 return 0xFFFF;
97         return hs_csr;
98 }
99
100 int cpci_check_and_clear_ins(struct slot *slot)
101 {
102         int hs_cap;
103         u16 hs_csr;
104         int ins = 0;
105
106         hs_cap = pci_bus_find_capability(slot->bus,
107                                          slot->devfn,
108                                          PCI_CAP_ID_CHSWP);
109         if (!hs_cap)
110                 return 0;
111         if (pci_bus_read_config_word(slot->bus,
112                                      slot->devfn,
113                                      hs_cap + 2,
114                                      &hs_csr))
115                 return 0;
116         if (hs_csr & HS_CSR_INS) {
117                 /* Clear INS (by setting it) */
118                 if (pci_bus_write_config_word(slot->bus,
119                                               slot->devfn,
120                                               hs_cap + 2,
121                                               hs_csr))
122                         ins = 0;
123                 else
124                         ins = 1;
125         }
126         return ins;
127 }
128
129 int cpci_check_ext(struct slot *slot)
130 {
131         int hs_cap;
132         u16 hs_csr;
133         int ext = 0;
134
135         hs_cap = pci_bus_find_capability(slot->bus,
136                                          slot->devfn,
137                                          PCI_CAP_ID_CHSWP);
138         if (!hs_cap)
139                 return 0;
140         if (pci_bus_read_config_word(slot->bus,
141                                      slot->devfn,
142                                      hs_cap + 2,
143                                      &hs_csr))
144                 return 0;
145         if (hs_csr & HS_CSR_EXT)
146                 ext = 1;
147         return ext;
148 }
149
150 int cpci_clear_ext(struct slot *slot)
151 {
152         int hs_cap;
153         u16 hs_csr;
154
155         hs_cap = pci_bus_find_capability(slot->bus,
156                                          slot->devfn,
157                                          PCI_CAP_ID_CHSWP);
158         if (!hs_cap)
159                 return -ENODEV;
160         if (pci_bus_read_config_word(slot->bus,
161                                      slot->devfn,
162                                      hs_cap + 2,
163                                      &hs_csr))
164                 return -ENODEV;
165         if (hs_csr & HS_CSR_EXT) {
166                 /* Clear EXT (by setting it) */
167                 if (pci_bus_write_config_word(slot->bus,
168                                               slot->devfn,
169                                               hs_cap + 2,
170                                               hs_csr))
171                         return -ENODEV;
172         }
173         return 0;
174 }
175
176 int cpci_led_on(struct slot *slot)
177 {
178         int hs_cap;
179         u16 hs_csr;
180
181         hs_cap = pci_bus_find_capability(slot->bus,
182                                          slot->devfn,
183                                          PCI_CAP_ID_CHSWP);
184         if (!hs_cap)
185                 return -ENODEV;
186         if (pci_bus_read_config_word(slot->bus,
187                                      slot->devfn,
188                                      hs_cap + 2,
189                                      &hs_csr))
190                 return -ENODEV;
191         if ((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) {
192                 hs_csr |= HS_CSR_LOO;
193                 if (pci_bus_write_config_word(slot->bus,
194                                               slot->devfn,
195                                               hs_cap + 2,
196                                               hs_csr)) {
197                         err("Could not set LOO for slot %s",
198                             hotplug_slot_name(slot->hotplug_slot));
199                         return -ENODEV;
200                 }
201         }
202         return 0;
203 }
204
205 int cpci_led_off(struct slot *slot)
206 {
207         int hs_cap;
208         u16 hs_csr;
209
210         hs_cap = pci_bus_find_capability(slot->bus,
211                                          slot->devfn,
212                                          PCI_CAP_ID_CHSWP);
213         if (!hs_cap)
214                 return -ENODEV;
215         if (pci_bus_read_config_word(slot->bus,
216                                      slot->devfn,
217                                      hs_cap + 2,
218                                      &hs_csr))
219                 return -ENODEV;
220         if (hs_csr & HS_CSR_LOO) {
221                 hs_csr &= ~HS_CSR_LOO;
222                 if (pci_bus_write_config_word(slot->bus,
223                                               slot->devfn,
224                                               hs_cap + 2,
225                                               hs_csr)) {
226                         err("Could not clear LOO for slot %s",
227                             hotplug_slot_name(slot->hotplug_slot));
228                         return -ENODEV;
229                 }
230         }
231         return 0;
232 }
233
234
235 /*
236  * Device configuration functions
237  */
238
239 int cpci_configure_slot(struct slot *slot)
240 {
241         struct pci_dev *dev;
242         struct pci_bus *parent;
243         int ret = 0;
244
245         dbg("%s - enter", __func__);
246
247         pci_lock_rescan_remove();
248
249         if (slot->dev == NULL) {
250                 dbg("pci_dev null, finding %02x:%02x:%x",
251                     slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn));
252                 slot->dev = pci_get_slot(slot->bus, slot->devfn);
253         }
254
255         /* Still NULL? Well then scan for it! */
256         if (slot->dev == NULL) {
257                 int n;
258                 dbg("pci_dev still null");
259
260                 /*
261                  * This will generate pci_dev structures for all functions, but
262                  * we will only call this case when lookup fails.
263                  */
264                 n = pci_scan_slot(slot->bus, slot->devfn);
265                 dbg("%s: pci_scan_slot returned %d", __func__, n);
266                 slot->dev = pci_get_slot(slot->bus, slot->devfn);
267                 if (slot->dev == NULL) {
268                         err("Could not find PCI device for slot %02x", slot->number);
269                         ret = -ENODEV;
270                         goto out;
271                 }
272         }
273         parent = slot->dev->bus;
274
275         for_each_pci_bridge(dev, parent) {
276                 if (PCI_SLOT(dev->devfn) == PCI_SLOT(slot->devfn))
277                         pci_hp_add_bridge(dev);
278         }
279
280         pci_assign_unassigned_bridge_resources(parent->self);
281
282         pci_bus_add_devices(parent);
283
284  out:
285         pci_unlock_rescan_remove();
286         dbg("%s - exit", __func__);
287         return ret;
288 }
289
290 int cpci_unconfigure_slot(struct slot *slot)
291 {
292         struct pci_dev *dev, *temp;
293
294         dbg("%s - enter", __func__);
295         if (!slot->dev) {
296                 err("No device for slot %02x\n", slot->number);
297                 return -ENODEV;
298         }
299
300         pci_lock_rescan_remove();
301
302         list_for_each_entry_safe(dev, temp, &slot->bus->devices, bus_list) {
303                 if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn))
304                         continue;
305                 pci_dev_get(dev);
306                 pci_stop_and_remove_bus_device(dev);
307                 pci_dev_put(dev);
308         }
309         pci_dev_put(slot->dev);
310         slot->dev = NULL;
311
312         pci_unlock_rescan_remove();
313
314         dbg("%s - exit", __func__);
315         return 0;
316 }