xref: /openbmc/linux/drivers/rapidio/rio.c (revision 37d33d15)
1394b701cSMatt Porter /*
2394b701cSMatt Porter  * RapidIO interconnect services
3394b701cSMatt Porter  * (RapidIO Interconnect Specification, http://www.rapidio.org)
4394b701cSMatt Porter  *
5394b701cSMatt Porter  * Copyright 2005 MontaVista Software, Inc.
6394b701cSMatt Porter  * Matt Porter <mporter@kernel.crashing.org>
7394b701cSMatt Porter  *
8394b701cSMatt Porter  * This program is free software; you can redistribute  it and/or modify it
9394b701cSMatt Porter  * under  the terms of  the GNU General  Public License as published by the
10394b701cSMatt Porter  * Free Software Foundation;  either version 2 of the  License, or (at your
11394b701cSMatt Porter  * option) any later version.
12394b701cSMatt Porter  */
13394b701cSMatt Porter 
14394b701cSMatt Porter #include <linux/types.h>
15394b701cSMatt Porter #include <linux/kernel.h>
16394b701cSMatt Porter 
17394b701cSMatt Porter #include <linux/delay.h>
18394b701cSMatt Porter #include <linux/init.h>
19394b701cSMatt Porter #include <linux/rio.h>
20394b701cSMatt Porter #include <linux/rio_drv.h>
21394b701cSMatt Porter #include <linux/rio_ids.h>
22394b701cSMatt Porter #include <linux/rio_regs.h>
23394b701cSMatt Porter #include <linux/module.h>
24394b701cSMatt Porter #include <linux/spinlock.h>
25de25968cSTim Schmielau #include <linux/slab.h>
265febf1cdSKumar Gala #include <linux/interrupt.h>
27394b701cSMatt Porter 
28394b701cSMatt Porter #include "rio.h"
29394b701cSMatt Porter 
30394b701cSMatt Porter static LIST_HEAD(rio_mports);
31394b701cSMatt Porter 
32394b701cSMatt Porter /**
33394b701cSMatt Porter  * rio_local_get_device_id - Get the base/extended device id for a port
34394b701cSMatt Porter  * @port: RIO master port from which to get the deviceid
35394b701cSMatt Porter  *
36394b701cSMatt Porter  * Reads the base/extended device id from the local device
37394b701cSMatt Porter  * implementing the master port. Returns the 8/16-bit device
38394b701cSMatt Porter  * id.
39394b701cSMatt Porter  */
40394b701cSMatt Porter u16 rio_local_get_device_id(struct rio_mport *port)
41394b701cSMatt Porter {
42394b701cSMatt Porter 	u32 result;
43394b701cSMatt Porter 
44394b701cSMatt Porter 	rio_local_read_config_32(port, RIO_DID_CSR, &result);
45394b701cSMatt Porter 
46e0423236SZhang Wei 	return (RIO_GET_DID(port->sys_size, result));
47394b701cSMatt Porter }
48394b701cSMatt Porter 
49394b701cSMatt Porter /**
50394b701cSMatt Porter  * rio_request_inb_mbox - request inbound mailbox service
51394b701cSMatt Porter  * @mport: RIO master port from which to allocate the mailbox resource
526978bbc0SMatt Porter  * @dev_id: Device specific pointer to pass on event
53394b701cSMatt Porter  * @mbox: Mailbox number to claim
54394b701cSMatt Porter  * @entries: Number of entries in inbound mailbox queue
55394b701cSMatt Porter  * @minb: Callback to execute when inbound message is received
56394b701cSMatt Porter  *
57394b701cSMatt Porter  * Requests ownership of an inbound mailbox resource and binds
58394b701cSMatt Porter  * a callback function to the resource. Returns %0 on success.
59394b701cSMatt Porter  */
60394b701cSMatt Porter int rio_request_inb_mbox(struct rio_mport *mport,
616978bbc0SMatt Porter 			 void *dev_id,
62394b701cSMatt Porter 			 int mbox,
63394b701cSMatt Porter 			 int entries,
646978bbc0SMatt Porter 			 void (*minb) (struct rio_mport * mport, void *dev_id, int mbox,
65394b701cSMatt Porter 				       int slot))
66394b701cSMatt Porter {
67394b701cSMatt Porter 	int rc = 0;
68394b701cSMatt Porter 
69394b701cSMatt Porter 	struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL);
70394b701cSMatt Porter 
71394b701cSMatt Porter 	if (res) {
72394b701cSMatt Porter 		rio_init_mbox_res(res, mbox, mbox);
73394b701cSMatt Porter 
74394b701cSMatt Porter 		/* Make sure this mailbox isn't in use */
75394b701cSMatt Porter 		if ((rc =
76394b701cSMatt Porter 		     request_resource(&mport->riores[RIO_INB_MBOX_RESOURCE],
77394b701cSMatt Porter 				      res)) < 0) {
78394b701cSMatt Porter 			kfree(res);
79394b701cSMatt Porter 			goto out;
80394b701cSMatt Porter 		}
81394b701cSMatt Porter 
82394b701cSMatt Porter 		mport->inb_msg[mbox].res = res;
83394b701cSMatt Porter 
84394b701cSMatt Porter 		/* Hook the inbound message callback */
85394b701cSMatt Porter 		mport->inb_msg[mbox].mcback = minb;
86394b701cSMatt Porter 
876978bbc0SMatt Porter 		rc = rio_open_inb_mbox(mport, dev_id, mbox, entries);
88394b701cSMatt Porter 	} else
89394b701cSMatt Porter 		rc = -ENOMEM;
90394b701cSMatt Porter 
91394b701cSMatt Porter       out:
92394b701cSMatt Porter 	return rc;
93394b701cSMatt Porter }
94394b701cSMatt Porter 
95394b701cSMatt Porter /**
96394b701cSMatt Porter  * rio_release_inb_mbox - release inbound mailbox message service
97394b701cSMatt Porter  * @mport: RIO master port from which to release the mailbox resource
98394b701cSMatt Porter  * @mbox: Mailbox number to release
99394b701cSMatt Porter  *
100394b701cSMatt Porter  * Releases ownership of an inbound mailbox resource. Returns 0
101394b701cSMatt Porter  * if the request has been satisfied.
102394b701cSMatt Porter  */
103394b701cSMatt Porter int rio_release_inb_mbox(struct rio_mport *mport, int mbox)
104394b701cSMatt Porter {
105394b701cSMatt Porter 	rio_close_inb_mbox(mport, mbox);
106394b701cSMatt Porter 
107394b701cSMatt Porter 	/* Release the mailbox resource */
108394b701cSMatt Porter 	return release_resource(mport->inb_msg[mbox].res);
109394b701cSMatt Porter }
110394b701cSMatt Porter 
111394b701cSMatt Porter /**
112394b701cSMatt Porter  * rio_request_outb_mbox - request outbound mailbox service
113394b701cSMatt Porter  * @mport: RIO master port from which to allocate the mailbox resource
1146978bbc0SMatt Porter  * @dev_id: Device specific pointer to pass on event
115394b701cSMatt Porter  * @mbox: Mailbox number to claim
116394b701cSMatt Porter  * @entries: Number of entries in outbound mailbox queue
117394b701cSMatt Porter  * @moutb: Callback to execute when outbound message is sent
118394b701cSMatt Porter  *
119394b701cSMatt Porter  * Requests ownership of an outbound mailbox resource and binds
120394b701cSMatt Porter  * a callback function to the resource. Returns 0 on success.
121394b701cSMatt Porter  */
122394b701cSMatt Porter int rio_request_outb_mbox(struct rio_mport *mport,
1236978bbc0SMatt Porter 			  void *dev_id,
124394b701cSMatt Porter 			  int mbox,
125394b701cSMatt Porter 			  int entries,
1266978bbc0SMatt Porter 			  void (*moutb) (struct rio_mport * mport, void *dev_id, int mbox, int slot))
127394b701cSMatt Porter {
128394b701cSMatt Porter 	int rc = 0;
129394b701cSMatt Porter 
130394b701cSMatt Porter 	struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL);
131394b701cSMatt Porter 
132394b701cSMatt Porter 	if (res) {
133394b701cSMatt Porter 		rio_init_mbox_res(res, mbox, mbox);
134394b701cSMatt Porter 
135394b701cSMatt Porter 		/* Make sure this outbound mailbox isn't in use */
136394b701cSMatt Porter 		if ((rc =
137394b701cSMatt Porter 		     request_resource(&mport->riores[RIO_OUTB_MBOX_RESOURCE],
138394b701cSMatt Porter 				      res)) < 0) {
139394b701cSMatt Porter 			kfree(res);
140394b701cSMatt Porter 			goto out;
141394b701cSMatt Porter 		}
142394b701cSMatt Porter 
143394b701cSMatt Porter 		mport->outb_msg[mbox].res = res;
144394b701cSMatt Porter 
145394b701cSMatt Porter 		/* Hook the inbound message callback */
146394b701cSMatt Porter 		mport->outb_msg[mbox].mcback = moutb;
147394b701cSMatt Porter 
1486978bbc0SMatt Porter 		rc = rio_open_outb_mbox(mport, dev_id, mbox, entries);
149394b701cSMatt Porter 	} else
150394b701cSMatt Porter 		rc = -ENOMEM;
151394b701cSMatt Porter 
152394b701cSMatt Porter       out:
153394b701cSMatt Porter 	return rc;
154394b701cSMatt Porter }
155394b701cSMatt Porter 
156394b701cSMatt Porter /**
157394b701cSMatt Porter  * rio_release_outb_mbox - release outbound mailbox message service
158394b701cSMatt Porter  * @mport: RIO master port from which to release the mailbox resource
159394b701cSMatt Porter  * @mbox: Mailbox number to release
160394b701cSMatt Porter  *
161394b701cSMatt Porter  * Releases ownership of an inbound mailbox resource. Returns 0
162394b701cSMatt Porter  * if the request has been satisfied.
163394b701cSMatt Porter  */
164394b701cSMatt Porter int rio_release_outb_mbox(struct rio_mport *mport, int mbox)
165394b701cSMatt Porter {
166394b701cSMatt Porter 	rio_close_outb_mbox(mport, mbox);
167394b701cSMatt Porter 
168394b701cSMatt Porter 	/* Release the mailbox resource */
169394b701cSMatt Porter 	return release_resource(mport->outb_msg[mbox].res);
170394b701cSMatt Porter }
171394b701cSMatt Porter 
172394b701cSMatt Porter /**
173394b701cSMatt Porter  * rio_setup_inb_dbell - bind inbound doorbell callback
174394b701cSMatt Porter  * @mport: RIO master port to bind the doorbell callback
1756978bbc0SMatt Porter  * @dev_id: Device specific pointer to pass on event
176394b701cSMatt Porter  * @res: Doorbell message resource
177394b701cSMatt Porter  * @dinb: Callback to execute when doorbell is received
178394b701cSMatt Porter  *
179394b701cSMatt Porter  * Adds a doorbell resource/callback pair into a port's
180394b701cSMatt Porter  * doorbell event list. Returns 0 if the request has been
181394b701cSMatt Porter  * satisfied.
182394b701cSMatt Porter  */
183394b701cSMatt Porter static int
1846978bbc0SMatt Porter rio_setup_inb_dbell(struct rio_mport *mport, void *dev_id, struct resource *res,
1856978bbc0SMatt Porter 		    void (*dinb) (struct rio_mport * mport, void *dev_id, u16 src, u16 dst,
186394b701cSMatt Porter 				  u16 info))
187394b701cSMatt Porter {
188394b701cSMatt Porter 	int rc = 0;
189394b701cSMatt Porter 	struct rio_dbell *dbell;
190394b701cSMatt Porter 
191394b701cSMatt Porter 	if (!(dbell = kmalloc(sizeof(struct rio_dbell), GFP_KERNEL))) {
192394b701cSMatt Porter 		rc = -ENOMEM;
193394b701cSMatt Porter 		goto out;
194394b701cSMatt Porter 	}
195394b701cSMatt Porter 
196394b701cSMatt Porter 	dbell->res = res;
197394b701cSMatt Porter 	dbell->dinb = dinb;
1986978bbc0SMatt Porter 	dbell->dev_id = dev_id;
199394b701cSMatt Porter 
200394b701cSMatt Porter 	list_add_tail(&dbell->node, &mport->dbells);
201394b701cSMatt Porter 
202394b701cSMatt Porter       out:
203394b701cSMatt Porter 	return rc;
204394b701cSMatt Porter }
205394b701cSMatt Porter 
206394b701cSMatt Porter /**
207394b701cSMatt Porter  * rio_request_inb_dbell - request inbound doorbell message service
208394b701cSMatt Porter  * @mport: RIO master port from which to allocate the doorbell resource
2096978bbc0SMatt Porter  * @dev_id: Device specific pointer to pass on event
210394b701cSMatt Porter  * @start: Doorbell info range start
211394b701cSMatt Porter  * @end: Doorbell info range end
212394b701cSMatt Porter  * @dinb: Callback to execute when doorbell is received
213394b701cSMatt Porter  *
214394b701cSMatt Porter  * Requests ownership of an inbound doorbell resource and binds
215394b701cSMatt Porter  * a callback function to the resource. Returns 0 if the request
216394b701cSMatt Porter  * has been satisfied.
217394b701cSMatt Porter  */
218394b701cSMatt Porter int rio_request_inb_dbell(struct rio_mport *mport,
2196978bbc0SMatt Porter 			  void *dev_id,
220394b701cSMatt Porter 			  u16 start,
221394b701cSMatt Porter 			  u16 end,
2226978bbc0SMatt Porter 			  void (*dinb) (struct rio_mport * mport, void *dev_id, u16 src,
223394b701cSMatt Porter 					u16 dst, u16 info))
224394b701cSMatt Porter {
225394b701cSMatt Porter 	int rc = 0;
226394b701cSMatt Porter 
227394b701cSMatt Porter 	struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL);
228394b701cSMatt Porter 
229394b701cSMatt Porter 	if (res) {
230394b701cSMatt Porter 		rio_init_dbell_res(res, start, end);
231394b701cSMatt Porter 
232394b701cSMatt Porter 		/* Make sure these doorbells aren't in use */
233394b701cSMatt Porter 		if ((rc =
234394b701cSMatt Porter 		     request_resource(&mport->riores[RIO_DOORBELL_RESOURCE],
235394b701cSMatt Porter 				      res)) < 0) {
236394b701cSMatt Porter 			kfree(res);
237394b701cSMatt Porter 			goto out;
238394b701cSMatt Porter 		}
239394b701cSMatt Porter 
240394b701cSMatt Porter 		/* Hook the doorbell callback */
2416978bbc0SMatt Porter 		rc = rio_setup_inb_dbell(mport, dev_id, res, dinb);
242394b701cSMatt Porter 	} else
243394b701cSMatt Porter 		rc = -ENOMEM;
244394b701cSMatt Porter 
245394b701cSMatt Porter       out:
246394b701cSMatt Porter 	return rc;
247394b701cSMatt Porter }
248394b701cSMatt Porter 
249394b701cSMatt Porter /**
250394b701cSMatt Porter  * rio_release_inb_dbell - release inbound doorbell message service
251394b701cSMatt Porter  * @mport: RIO master port from which to release the doorbell resource
252394b701cSMatt Porter  * @start: Doorbell info range start
253394b701cSMatt Porter  * @end: Doorbell info range end
254394b701cSMatt Porter  *
255394b701cSMatt Porter  * Releases ownership of an inbound doorbell resource and removes
256394b701cSMatt Porter  * callback from the doorbell event list. Returns 0 if the request
257394b701cSMatt Porter  * has been satisfied.
258394b701cSMatt Porter  */
259394b701cSMatt Porter int rio_release_inb_dbell(struct rio_mport *mport, u16 start, u16 end)
260394b701cSMatt Porter {
261394b701cSMatt Porter 	int rc = 0, found = 0;
262394b701cSMatt Porter 	struct rio_dbell *dbell;
263394b701cSMatt Porter 
264394b701cSMatt Porter 	list_for_each_entry(dbell, &mport->dbells, node) {
265394b701cSMatt Porter 		if ((dbell->res->start == start) && (dbell->res->end == end)) {
266394b701cSMatt Porter 			found = 1;
267394b701cSMatt Porter 			break;
268394b701cSMatt Porter 		}
269394b701cSMatt Porter 	}
270394b701cSMatt Porter 
271394b701cSMatt Porter 	/* If we can't find an exact match, fail */
272394b701cSMatt Porter 	if (!found) {
273394b701cSMatt Porter 		rc = -EINVAL;
274394b701cSMatt Porter 		goto out;
275394b701cSMatt Porter 	}
276394b701cSMatt Porter 
277394b701cSMatt Porter 	/* Delete from list */
278394b701cSMatt Porter 	list_del(&dbell->node);
279394b701cSMatt Porter 
280394b701cSMatt Porter 	/* Release the doorbell resource */
281394b701cSMatt Porter 	rc = release_resource(dbell->res);
282394b701cSMatt Porter 
283394b701cSMatt Porter 	/* Free the doorbell event */
284394b701cSMatt Porter 	kfree(dbell);
285394b701cSMatt Porter 
286394b701cSMatt Porter       out:
287394b701cSMatt Porter 	return rc;
288394b701cSMatt Porter }
289394b701cSMatt Porter 
290394b701cSMatt Porter /**
291394b701cSMatt Porter  * rio_request_outb_dbell - request outbound doorbell message range
292394b701cSMatt Porter  * @rdev: RIO device from which to allocate the doorbell resource
293394b701cSMatt Porter  * @start: Doorbell message range start
294394b701cSMatt Porter  * @end: Doorbell message range end
295394b701cSMatt Porter  *
296394b701cSMatt Porter  * Requests ownership of a doorbell message range. Returns a resource
297394b701cSMatt Porter  * if the request has been satisfied or %NULL on failure.
298394b701cSMatt Porter  */
299394b701cSMatt Porter struct resource *rio_request_outb_dbell(struct rio_dev *rdev, u16 start,
300394b701cSMatt Porter 					u16 end)
301394b701cSMatt Porter {
302394b701cSMatt Porter 	struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL);
303394b701cSMatt Porter 
304394b701cSMatt Porter 	if (res) {
305394b701cSMatt Porter 		rio_init_dbell_res(res, start, end);
306394b701cSMatt Porter 
307394b701cSMatt Porter 		/* Make sure these doorbells aren't in use */
308394b701cSMatt Porter 		if (request_resource(&rdev->riores[RIO_DOORBELL_RESOURCE], res)
309394b701cSMatt Porter 		    < 0) {
310394b701cSMatt Porter 			kfree(res);
311394b701cSMatt Porter 			res = NULL;
312394b701cSMatt Porter 		}
313394b701cSMatt Porter 	}
314394b701cSMatt Porter 
315394b701cSMatt Porter 	return res;
316394b701cSMatt Porter }
317394b701cSMatt Porter 
318394b701cSMatt Porter /**
319394b701cSMatt Porter  * rio_release_outb_dbell - release outbound doorbell message range
320394b701cSMatt Porter  * @rdev: RIO device from which to release the doorbell resource
321394b701cSMatt Porter  * @res: Doorbell resource to be freed
322394b701cSMatt Porter  *
323394b701cSMatt Porter  * Releases ownership of a doorbell message range. Returns 0 if the
324394b701cSMatt Porter  * request has been satisfied.
325394b701cSMatt Porter  */
326394b701cSMatt Porter int rio_release_outb_dbell(struct rio_dev *rdev, struct resource *res)
327394b701cSMatt Porter {
328394b701cSMatt Porter 	int rc = release_resource(res);
329394b701cSMatt Porter 
330394b701cSMatt Porter 	kfree(res);
331394b701cSMatt Porter 
332394b701cSMatt Porter 	return rc;
333394b701cSMatt Porter }
334394b701cSMatt Porter 
335394b701cSMatt Porter /**
336394b701cSMatt Porter  * rio_mport_get_feature - query for devices' extended features
337394b701cSMatt Porter  * @port: Master port to issue transaction
338394b701cSMatt Porter  * @local: Indicate a local master port or remote device access
339394b701cSMatt Porter  * @destid: Destination ID of the device
340394b701cSMatt Porter  * @hopcount: Number of switch hops to the device
341394b701cSMatt Porter  * @ftr: Extended feature code
342394b701cSMatt Porter  *
343394b701cSMatt Porter  * Tell if a device supports a given RapidIO capability.
344394b701cSMatt Porter  * Returns the offset of the requested extended feature
345394b701cSMatt Porter  * block within the device's RIO configuration space or
346394b701cSMatt Porter  * 0 in case the device does not support it.  Possible
347394b701cSMatt Porter  * values for @ftr:
348394b701cSMatt Porter  *
349394b701cSMatt Porter  * %RIO_EFB_PAR_EP_ID		LP/LVDS EP Devices
350394b701cSMatt Porter  *
351394b701cSMatt Porter  * %RIO_EFB_PAR_EP_REC_ID	LP/LVDS EP Recovery Devices
352394b701cSMatt Porter  *
353394b701cSMatt Porter  * %RIO_EFB_PAR_EP_FREE_ID	LP/LVDS EP Free Devices
354394b701cSMatt Porter  *
355394b701cSMatt Porter  * %RIO_EFB_SER_EP_ID		LP/Serial EP Devices
356394b701cSMatt Porter  *
357394b701cSMatt Porter  * %RIO_EFB_SER_EP_REC_ID	LP/Serial EP Recovery Devices
358394b701cSMatt Porter  *
359394b701cSMatt Porter  * %RIO_EFB_SER_EP_FREE_ID	LP/Serial EP Free Devices
360394b701cSMatt Porter  */
361394b701cSMatt Porter u32
362394b701cSMatt Porter rio_mport_get_feature(struct rio_mport * port, int local, u16 destid,
363394b701cSMatt Porter 		      u8 hopcount, int ftr)
364394b701cSMatt Porter {
365394b701cSMatt Porter 	u32 asm_info, ext_ftr_ptr, ftr_header;
366394b701cSMatt Porter 
367394b701cSMatt Porter 	if (local)
368394b701cSMatt Porter 		rio_local_read_config_32(port, RIO_ASM_INFO_CAR, &asm_info);
369394b701cSMatt Porter 	else
370394b701cSMatt Porter 		rio_mport_read_config_32(port, destid, hopcount,
371394b701cSMatt Porter 					 RIO_ASM_INFO_CAR, &asm_info);
372394b701cSMatt Porter 
373394b701cSMatt Porter 	ext_ftr_ptr = asm_info & RIO_EXT_FTR_PTR_MASK;
374394b701cSMatt Porter 
375394b701cSMatt Porter 	while (ext_ftr_ptr) {
376394b701cSMatt Porter 		if (local)
377394b701cSMatt Porter 			rio_local_read_config_32(port, ext_ftr_ptr,
378394b701cSMatt Porter 						 &ftr_header);
379394b701cSMatt Porter 		else
380394b701cSMatt Porter 			rio_mport_read_config_32(port, destid, hopcount,
381394b701cSMatt Porter 						 ext_ftr_ptr, &ftr_header);
382394b701cSMatt Porter 		if (RIO_GET_BLOCK_ID(ftr_header) == ftr)
383394b701cSMatt Porter 			return ext_ftr_ptr;
384394b701cSMatt Porter 		if (!(ext_ftr_ptr = RIO_GET_BLOCK_PTR(ftr_header)))
385394b701cSMatt Porter 			break;
386394b701cSMatt Porter 	}
387394b701cSMatt Porter 
388394b701cSMatt Porter 	return 0;
389394b701cSMatt Porter }
390394b701cSMatt Porter 
391394b701cSMatt Porter /**
392394b701cSMatt Porter  * rio_get_asm - Begin or continue searching for a RIO device by vid/did/asm_vid/asm_did
393394b701cSMatt Porter  * @vid: RIO vid to match or %RIO_ANY_ID to match all vids
394394b701cSMatt Porter  * @did: RIO did to match or %RIO_ANY_ID to match all dids
395394b701cSMatt Porter  * @asm_vid: RIO asm_vid to match or %RIO_ANY_ID to match all asm_vids
396394b701cSMatt Porter  * @asm_did: RIO asm_did to match or %RIO_ANY_ID to match all asm_dids
397394b701cSMatt Porter  * @from: Previous RIO device found in search, or %NULL for new search
398394b701cSMatt Porter  *
399394b701cSMatt Porter  * Iterates through the list of known RIO devices. If a RIO device is
400394b701cSMatt Porter  * found with a matching @vid, @did, @asm_vid, @asm_did, the reference
401394b701cSMatt Porter  * count to the device is incrememted and a pointer to its device
402394b701cSMatt Porter  * structure is returned. Otherwise, %NULL is returned. A new search
403394b701cSMatt Porter  * is initiated by passing %NULL to the @from argument. Otherwise, if
404394b701cSMatt Porter  * @from is not %NULL, searches continue from next device on the global
405394b701cSMatt Porter  * list. The reference count for @from is always decremented if it is
406394b701cSMatt Porter  * not %NULL.
407394b701cSMatt Porter  */
408394b701cSMatt Porter struct rio_dev *rio_get_asm(u16 vid, u16 did,
409394b701cSMatt Porter 			    u16 asm_vid, u16 asm_did, struct rio_dev *from)
410394b701cSMatt Porter {
411394b701cSMatt Porter 	struct list_head *n;
412394b701cSMatt Porter 	struct rio_dev *rdev;
413394b701cSMatt Porter 
414394b701cSMatt Porter 	WARN_ON(in_interrupt());
415394b701cSMatt Porter 	spin_lock(&rio_global_list_lock);
416394b701cSMatt Porter 	n = from ? from->global_list.next : rio_devices.next;
417394b701cSMatt Porter 
418394b701cSMatt Porter 	while (n && (n != &rio_devices)) {
419394b701cSMatt Porter 		rdev = rio_dev_g(n);
420394b701cSMatt Porter 		if ((vid == RIO_ANY_ID || rdev->vid == vid) &&
421394b701cSMatt Porter 		    (did == RIO_ANY_ID || rdev->did == did) &&
422394b701cSMatt Porter 		    (asm_vid == RIO_ANY_ID || rdev->asm_vid == asm_vid) &&
423394b701cSMatt Porter 		    (asm_did == RIO_ANY_ID || rdev->asm_did == asm_did))
424394b701cSMatt Porter 			goto exit;
425394b701cSMatt Porter 		n = n->next;
426394b701cSMatt Porter 	}
427394b701cSMatt Porter 	rdev = NULL;
428394b701cSMatt Porter       exit:
429394b701cSMatt Porter 	rio_dev_put(from);
430394b701cSMatt Porter 	rdev = rio_dev_get(rdev);
431394b701cSMatt Porter 	spin_unlock(&rio_global_list_lock);
432394b701cSMatt Porter 	return rdev;
433394b701cSMatt Porter }
434394b701cSMatt Porter 
435394b701cSMatt Porter /**
436394b701cSMatt Porter  * rio_get_device - Begin or continue searching for a RIO device by vid/did
437394b701cSMatt Porter  * @vid: RIO vid to match or %RIO_ANY_ID to match all vids
438394b701cSMatt Porter  * @did: RIO did to match or %RIO_ANY_ID to match all dids
439394b701cSMatt Porter  * @from: Previous RIO device found in search, or %NULL for new search
440394b701cSMatt Porter  *
441394b701cSMatt Porter  * Iterates through the list of known RIO devices. If a RIO device is
442394b701cSMatt Porter  * found with a matching @vid and @did, the reference count to the
443394b701cSMatt Porter  * device is incrememted and a pointer to its device structure is returned.
444394b701cSMatt Porter  * Otherwise, %NULL is returned. A new search is initiated by passing %NULL
445394b701cSMatt Porter  * to the @from argument. Otherwise, if @from is not %NULL, searches
446394b701cSMatt Porter  * continue from next device on the global list. The reference count for
447394b701cSMatt Porter  * @from is always decremented if it is not %NULL.
448394b701cSMatt Porter  */
449394b701cSMatt Porter struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from)
450394b701cSMatt Porter {
451394b701cSMatt Porter 	return rio_get_asm(vid, did, RIO_ANY_ID, RIO_ANY_ID, from);
452394b701cSMatt Porter }
453394b701cSMatt Porter 
454394b701cSMatt Porter static void rio_fixup_device(struct rio_dev *dev)
455394b701cSMatt Porter {
456394b701cSMatt Porter }
457394b701cSMatt Porter 
458394b701cSMatt Porter static int __devinit rio_init(void)
459394b701cSMatt Porter {
460394b701cSMatt Porter 	struct rio_dev *dev = NULL;
461394b701cSMatt Porter 
462394b701cSMatt Porter 	while ((dev = rio_get_device(RIO_ANY_ID, RIO_ANY_ID, dev)) != NULL) {
463394b701cSMatt Porter 		rio_fixup_device(dev);
464394b701cSMatt Porter 	}
465394b701cSMatt Porter 	return 0;
466394b701cSMatt Porter }
467394b701cSMatt Porter 
468394b701cSMatt Porter device_initcall(rio_init);
469394b701cSMatt Porter 
47037d33d15SAl Viro int __devinit rio_init_mports(void)
471394b701cSMatt Porter {
472394b701cSMatt Porter 	int rc = 0;
473394b701cSMatt Porter 	struct rio_mport *port;
474394b701cSMatt Porter 
475394b701cSMatt Porter 	list_for_each_entry(port, &rio_mports, node) {
476394b701cSMatt Porter 		if (!request_mem_region(port->iores.start,
477394b701cSMatt Porter 					port->iores.end - port->iores.start,
478394b701cSMatt Porter 					port->name)) {
479394b701cSMatt Porter 			printk(KERN_ERR
4805febf1cdSKumar Gala 			       "RIO: Error requesting master port region 0x%016llx-0x%016llx\n",
4815febf1cdSKumar Gala 			       (u64)port->iores.start, (u64)port->iores.end - 1);
482394b701cSMatt Porter 			rc = -ENOMEM;
483394b701cSMatt Porter 			goto out;
484394b701cSMatt Porter 		}
485394b701cSMatt Porter 
486394b701cSMatt Porter 		if (port->host_deviceid >= 0)
487394b701cSMatt Porter 			rio_enum_mport(port);
488394b701cSMatt Porter 		else
489394b701cSMatt Porter 			rio_disc_mport(port);
490394b701cSMatt Porter 	}
491394b701cSMatt Porter 
492394b701cSMatt Porter       out:
493394b701cSMatt Porter 	return rc;
494394b701cSMatt Porter }
495394b701cSMatt Porter 
496394b701cSMatt Porter void rio_register_mport(struct rio_mport *port)
497394b701cSMatt Porter {
498394b701cSMatt Porter 	list_add_tail(&port->node, &rio_mports);
499394b701cSMatt Porter }
500394b701cSMatt Porter 
501394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_local_get_device_id);
502394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_get_device);
503394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_get_asm);
504394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_inb_dbell);
505394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_inb_dbell);
506394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_outb_dbell);
507394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_outb_dbell);
508394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_inb_mbox);
509394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_inb_mbox);
510394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_outb_mbox);
511394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_outb_mbox);
512