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