Merge branch 'upstream-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/linvil...
[pandora-kernel.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 #define ROUND_UP(x, a)          (((x) + (a) - 1) & ~((a) - 1))
49
50
51 u8 cpci_get_attention_status(struct slot* slot)
52 {
53         int hs_cap;
54         u16 hs_csr;
55
56         hs_cap = pci_bus_find_capability(slot->bus,
57                                          slot->devfn,
58                                          PCI_CAP_ID_CHSWP);
59         if (!hs_cap)
60                 return 0;
61
62         if (pci_bus_read_config_word(slot->bus,
63                                      slot->devfn,
64                                      hs_cap + 2,
65                                      &hs_csr))
66                 return 0;
67
68         return hs_csr & 0x0008 ? 1 : 0;
69 }
70
71 int cpci_set_attention_status(struct slot* slot, int status)
72 {
73         int hs_cap;
74         u16 hs_csr;
75
76         hs_cap = pci_bus_find_capability(slot->bus,
77                                          slot->devfn,
78                                          PCI_CAP_ID_CHSWP);
79         if (!hs_cap)
80                 return 0;
81         if (pci_bus_read_config_word(slot->bus,
82                                      slot->devfn,
83                                      hs_cap + 2,
84                                      &hs_csr))
85                 return 0;
86         if (status)
87                 hs_csr |= HS_CSR_LOO;
88         else
89                 hs_csr &= ~HS_CSR_LOO;
90         if (pci_bus_write_config_word(slot->bus,
91                                       slot->devfn,
92                                       hs_cap + 2,
93                                       hs_csr))
94                 return 0;
95         return 1;
96 }
97
98 u16 cpci_get_hs_csr(struct slot* slot)
99 {
100         int hs_cap;
101         u16 hs_csr;
102
103         hs_cap = pci_bus_find_capability(slot->bus,
104                                          slot->devfn,
105                                          PCI_CAP_ID_CHSWP);
106         if (!hs_cap)
107                 return 0xFFFF;
108         if (pci_bus_read_config_word(slot->bus,
109                                      slot->devfn,
110                                      hs_cap + 2,
111                                      &hs_csr))
112                 return 0xFFFF;
113         return hs_csr;
114 }
115
116 int cpci_check_and_clear_ins(struct slot* slot)
117 {
118         int hs_cap;
119         u16 hs_csr;
120         int ins = 0;
121
122         hs_cap = pci_bus_find_capability(slot->bus,
123                                          slot->devfn,
124                                          PCI_CAP_ID_CHSWP);
125         if (!hs_cap)
126                 return 0;
127         if (pci_bus_read_config_word(slot->bus,
128                                      slot->devfn,
129                                      hs_cap + 2,
130                                      &hs_csr))
131                 return 0;
132         if (hs_csr & HS_CSR_INS) {
133                 /* Clear INS (by setting it) */
134                 if (pci_bus_write_config_word(slot->bus,
135                                               slot->devfn,
136                                               hs_cap + 2,
137                                               hs_csr))
138                         ins = 0;
139                 else
140                         ins = 1;
141         }
142         return ins;
143 }
144
145 int cpci_check_ext(struct slot* slot)
146 {
147         int hs_cap;
148         u16 hs_csr;
149         int ext = 0;
150
151         hs_cap = pci_bus_find_capability(slot->bus,
152                                          slot->devfn,
153                                          PCI_CAP_ID_CHSWP);
154         if (!hs_cap)
155                 return 0;
156         if (pci_bus_read_config_word(slot->bus,
157                                      slot->devfn,
158                                      hs_cap + 2,
159                                      &hs_csr))
160                 return 0;
161         if (hs_csr & HS_CSR_EXT)
162                 ext = 1;
163         return ext;
164 }
165
166 int cpci_clear_ext(struct slot* slot)
167 {
168         int hs_cap;
169         u16 hs_csr;
170
171         hs_cap = pci_bus_find_capability(slot->bus,
172                                          slot->devfn,
173                                          PCI_CAP_ID_CHSWP);
174         if (!hs_cap)
175                 return -ENODEV;
176         if (pci_bus_read_config_word(slot->bus,
177                                      slot->devfn,
178                                      hs_cap + 2,
179                                      &hs_csr))
180                 return -ENODEV;
181         if (hs_csr & HS_CSR_EXT) {
182                 /* Clear EXT (by setting it) */
183                 if (pci_bus_write_config_word(slot->bus,
184                                               slot->devfn,
185                                               hs_cap + 2,
186                                               hs_csr))
187                         return -ENODEV;
188         }
189         return 0;
190 }
191
192 int cpci_led_on(struct slot* slot)
193 {
194         int hs_cap;
195         u16 hs_csr;
196
197         hs_cap = pci_bus_find_capability(slot->bus,
198                                          slot->devfn,
199                                          PCI_CAP_ID_CHSWP);
200         if (!hs_cap)
201                 return -ENODEV;
202         if (pci_bus_read_config_word(slot->bus,
203                                      slot->devfn,
204                                      hs_cap + 2,
205                                      &hs_csr))
206                 return -ENODEV;
207         if ((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) {
208                 hs_csr |= HS_CSR_LOO;
209                 if (pci_bus_write_config_word(slot->bus,
210                                               slot->devfn,
211                                               hs_cap + 2,
212                                               hs_csr)) {
213                         err("Could not set LOO for slot %s",
214                             slot->hotplug_slot->name);
215                         return -ENODEV;
216                 }
217         }
218         return 0;
219 }
220
221 int cpci_led_off(struct slot* slot)
222 {
223         int hs_cap;
224         u16 hs_csr;
225
226         hs_cap = pci_bus_find_capability(slot->bus,
227                                          slot->devfn,
228                                          PCI_CAP_ID_CHSWP);
229         if (!hs_cap)
230                 return -ENODEV;
231         if (pci_bus_read_config_word(slot->bus,
232                                      slot->devfn,
233                                      hs_cap + 2,
234                                      &hs_csr))
235                 return -ENODEV;
236         if (hs_csr & HS_CSR_LOO) {
237                 hs_csr &= ~HS_CSR_LOO;
238                 if (pci_bus_write_config_word(slot->bus,
239                                               slot->devfn,
240                                               hs_cap + 2,
241                                               hs_csr)) {
242                         err("Could not clear LOO for slot %s",
243                             slot->hotplug_slot->name);
244                         return -ENODEV;
245                 }
246         }
247         return 0;
248 }
249
250
251 /*
252  * Device configuration functions
253  */
254
255 int cpci_configure_slot(struct slot* slot)
256 {
257         struct pci_bus *parent;
258         int fn;
259
260         dbg("%s - enter", __FUNCTION__);
261
262         if (slot->dev == NULL) {
263                 dbg("pci_dev null, finding %02x:%02x:%x",
264                     slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn));
265                 slot->dev = pci_get_slot(slot->bus, slot->devfn);
266         }
267
268         /* Still NULL? Well then scan for it! */
269         if (slot->dev == NULL) {
270                 int n;
271                 dbg("pci_dev still null");
272
273                 /*
274                  * This will generate pci_dev structures for all functions, but
275                  * we will only call this case when lookup fails.
276                  */
277                 n = pci_scan_slot(slot->bus, slot->devfn);
278                 dbg("%s: pci_scan_slot returned %d", __FUNCTION__, n);
279                 slot->dev = pci_get_slot(slot->bus, slot->devfn);
280                 if (slot->dev == NULL) {
281                         err("Could not find PCI device for slot %02x", slot->number);
282                         return -ENODEV;
283                 }
284         }
285         parent = slot->dev->bus;
286
287         for (fn = 0; fn < 8; fn++) {
288                 struct pci_dev *dev;
289
290                 dev = pci_get_slot(parent, PCI_DEVFN(PCI_SLOT(slot->devfn), fn));
291                 if (!dev)
292                         continue;
293                 if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
294                     (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
295                         /* Find an unused bus number for the new bridge */
296                         struct pci_bus *child;
297                         unsigned char busnr, start = parent->secondary;
298                         unsigned char end = parent->subordinate;
299
300                         for (busnr = start; busnr <= end; busnr++) {
301                                 if (!pci_find_bus(pci_domain_nr(parent),
302                                                   busnr))
303                                         break;
304                         }
305                         if (busnr >= end) {
306                                 err("No free bus for hot-added bridge\n");
307                                 pci_dev_put(dev);
308                                 continue;
309                         }
310                         child = pci_add_new_bus(parent, dev, busnr);
311                         if (!child) {
312                                 err("Cannot add new bus for %s\n",
313                                     pci_name(dev));
314                                 pci_dev_put(dev);
315                                 continue;
316                         }
317                         child->subordinate = pci_do_scan_bus(child);
318                         pci_bus_size_bridges(child);
319                 }
320                 pci_dev_put(dev);
321         }
322
323         pci_bus_assign_resources(parent);
324         pci_bus_add_devices(parent);
325         pci_enable_bridges(parent);
326
327         dbg("%s - exit", __FUNCTION__);
328         return 0;
329 }
330
331 int cpci_unconfigure_slot(struct slot* slot)
332 {
333         int i;
334         struct pci_dev *dev;
335
336         dbg("%s - enter", __FUNCTION__);
337         if (!slot->dev) {
338                 err("No device for slot %02x\n", slot->number);
339                 return -ENODEV;
340         }
341
342         for (i = 0; i < 8; i++) {
343                 dev = pci_get_slot(slot->bus,
344                                     PCI_DEVFN(PCI_SLOT(slot->devfn), i));
345                 if (dev) {
346                         pci_remove_bus_device(dev);
347                         pci_dev_put(dev);
348                 }
349         }
350         pci_dev_put(slot->dev);
351         slot->dev = NULL;
352
353         dbg("%s - exit", __FUNCTION__);
354         return 0;
355 }