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