xref: /linux/drivers/pci/hotplug/cpci_hotplug_pci.c (revision c537b994505099b7197e7d3125b942ecbcc51eb6)
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 }
356