Merge branch 'x86-vdso-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6] / 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_bus *parent;
256         int fn;
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         for (fn = 0; fn < 8; fn++) {
286                 struct pci_dev *dev;
287
288                 dev = pci_get_slot(parent, PCI_DEVFN(PCI_SLOT(slot->devfn), fn));
289                 if (!dev)
290                         continue;
291                 if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
292                     (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
293                         /* Find an unused bus number for the new bridge */
294                         struct pci_bus *child;
295                         unsigned char busnr, start = parent->secondary;
296                         unsigned char end = parent->subordinate;
297
298                         for (busnr = start; busnr <= end; busnr++) {
299                                 if (!pci_find_bus(pci_domain_nr(parent),
300                                                   busnr))
301                                         break;
302                         }
303                         if (busnr >= end) {
304                                 err("No free bus for hot-added bridge\n");
305                                 pci_dev_put(dev);
306                                 continue;
307                         }
308                         child = pci_add_new_bus(parent, dev, busnr);
309                         if (!child) {
310                                 err("Cannot add new bus for %s\n",
311                                     pci_name(dev));
312                                 pci_dev_put(dev);
313                                 continue;
314                         }
315                         child->subordinate = pci_do_scan_bus(child);
316                         pci_bus_size_bridges(child);
317                 }
318                 pci_dev_put(dev);
319         }
320
321         pci_bus_assign_resources(parent);
322         pci_bus_add_devices(parent);
323         pci_enable_bridges(parent);
324
325         dbg("%s - exit", __func__);
326         return 0;
327 }
328
329 int cpci_unconfigure_slot(struct slot* slot)
330 {
331         int i;
332         struct pci_dev *dev;
333
334         dbg("%s - enter", __func__);
335         if (!slot->dev) {
336                 err("No device for slot %02x\n", slot->number);
337                 return -ENODEV;
338         }
339
340         for (i = 0; i < 8; i++) {
341                 dev = pci_get_slot(slot->bus,
342                                     PCI_DEVFN(PCI_SLOT(slot->devfn), i));
343                 if (dev) {
344                         pci_remove_bus_device(dev);
345                         pci_dev_put(dev);
346                 }
347         }
348         pci_dev_put(slot->dev);
349         slot->dev = NULL;
350
351         dbg("%s - exit", __func__);
352         return 0;
353 }