xref: /openbmc/linux/drivers/rapidio/rio-scan.c (revision f4c9c0e8)
1eb188d0eSMatt Porter /*
2eb188d0eSMatt Porter  * RapidIO enumeration and discovery support
3eb188d0eSMatt Porter  *
4eb188d0eSMatt Porter  * Copyright 2005 MontaVista Software, Inc.
5eb188d0eSMatt Porter  * Matt Porter <mporter@kernel.crashing.org>
6eb188d0eSMatt Porter  *
7e5cabeb3SAlexandre Bounine  * Copyright 2009 Integrated Device Technology, Inc.
8e5cabeb3SAlexandre Bounine  * Alex Bounine <alexandre.bounine@idt.com>
9e5cabeb3SAlexandre Bounine  * - Added Port-Write/Error Management initialization and handling
10e5cabeb3SAlexandre Bounine  *
11933af4a6SThomas Moll  * Copyright 2009 Sysgo AG
12933af4a6SThomas Moll  * Thomas Moll <thomas.moll@sysgo.com>
13933af4a6SThomas Moll  * - Added Input- Output- enable functionality, to allow full communication
14933af4a6SThomas Moll  *
15eb188d0eSMatt Porter  * This program is free software; you can redistribute  it and/or modify it
16eb188d0eSMatt Porter  * under  the terms of  the GNU General  Public License as published by the
17eb188d0eSMatt Porter  * Free Software Foundation;  either version 2 of the  License, or (at your
18eb188d0eSMatt Porter  * option) any later version.
19eb188d0eSMatt Porter  */
20eb188d0eSMatt Porter 
21eb188d0eSMatt Porter #include <linux/types.h>
22eb188d0eSMatt Porter #include <linux/kernel.h>
23eb188d0eSMatt Porter 
24eb188d0eSMatt Porter #include <linux/delay.h>
25fa78cc51SMatt Porter #include <linux/dma-mapping.h>
26eb188d0eSMatt Porter #include <linux/init.h>
27eb188d0eSMatt Porter #include <linux/rio.h>
28eb188d0eSMatt Porter #include <linux/rio_drv.h>
29eb188d0eSMatt Porter #include <linux/rio_ids.h>
30eb188d0eSMatt Porter #include <linux/rio_regs.h>
31eb188d0eSMatt Porter #include <linux/module.h>
32eb188d0eSMatt Porter #include <linux/spinlock.h>
33eb188d0eSMatt Porter #include <linux/timer.h>
34fa3dbaa0SAlexandre Bounine #include <linux/sched.h>
35de25968cSTim Schmielau #include <linux/jiffies.h>
36de25968cSTim Schmielau #include <linux/slab.h>
37eb188d0eSMatt Porter 
38eb188d0eSMatt Porter #include "rio.h"
39eb188d0eSMatt Porter 
40eb188d0eSMatt Porter LIST_HEAD(rio_devices);
41eb188d0eSMatt Porter 
42e5cabeb3SAlexandre Bounine static void rio_init_em(struct rio_dev *rdev);
43e5cabeb3SAlexandre Bounine 
44fa78cc51SMatt Porter DEFINE_SPINLOCK(rio_global_list_lock);
45fa78cc51SMatt Porter 
46eb188d0eSMatt Porter static int next_destid = 0;
47af84ca38SAlexandre Bounine static int next_comptag = 1;
48eb188d0eSMatt Porter 
49eb188d0eSMatt Porter static int rio_mport_phys_table[] = {
50eb188d0eSMatt Porter 	RIO_EFB_PAR_EP_ID,
51eb188d0eSMatt Porter 	RIO_EFB_PAR_EP_REC_ID,
52eb188d0eSMatt Porter 	RIO_EFB_SER_EP_ID,
53eb188d0eSMatt Porter 	RIO_EFB_SER_EP_REC_ID,
54eb188d0eSMatt Porter 	-1,
55eb188d0eSMatt Porter };
56eb188d0eSMatt Porter 
57de74e00aSAlexandre Bounine 
58de74e00aSAlexandre Bounine /*
59de74e00aSAlexandre Bounine  * rio_destid_alloc - Allocate next available destID for given network
60de74e00aSAlexandre Bounine  * net: RIO network
61de74e00aSAlexandre Bounine  *
62de74e00aSAlexandre Bounine  * Returns next available device destination ID for the specified RIO network.
63de74e00aSAlexandre Bounine  * Marks allocated ID as one in use.
64de74e00aSAlexandre Bounine  * Returns RIO_INVALID_DESTID if new destID is not available.
65de74e00aSAlexandre Bounine  */
66de74e00aSAlexandre Bounine static u16 rio_destid_alloc(struct rio_net *net)
67de74e00aSAlexandre Bounine {
68de74e00aSAlexandre Bounine 	int destid;
69de74e00aSAlexandre Bounine 	struct rio_id_table *idtab = &net->destid_table;
70de74e00aSAlexandre Bounine 
71de74e00aSAlexandre Bounine 	spin_lock(&idtab->lock);
72de74e00aSAlexandre Bounine 	destid = find_next_zero_bit(idtab->table, idtab->max, idtab->next);
73de74e00aSAlexandre Bounine 	if (destid >= idtab->max)
74de74e00aSAlexandre Bounine 		destid = find_first_zero_bit(idtab->table, idtab->max);
75de74e00aSAlexandre Bounine 
76de74e00aSAlexandre Bounine 	if (destid < idtab->max) {
77de74e00aSAlexandre Bounine 		idtab->next = destid + 1;
78de74e00aSAlexandre Bounine 		if (idtab->next >= idtab->max)
79de74e00aSAlexandre Bounine 			idtab->next = 0;
80de74e00aSAlexandre Bounine 		set_bit(destid, idtab->table);
81de74e00aSAlexandre Bounine 		destid += idtab->start;
82de74e00aSAlexandre Bounine 	} else
83de74e00aSAlexandre Bounine 		destid = RIO_INVALID_DESTID;
84de74e00aSAlexandre Bounine 
85de74e00aSAlexandre Bounine 	spin_unlock(&idtab->lock);
86de74e00aSAlexandre Bounine 	return (u16)destid;
87de74e00aSAlexandre Bounine }
88de74e00aSAlexandre Bounine 
89de74e00aSAlexandre Bounine /*
90de74e00aSAlexandre Bounine  * rio_destid_reserve - Reserve the specivied destID
91de74e00aSAlexandre Bounine  * net: RIO network
92de74e00aSAlexandre Bounine  * destid: destID to reserve
93de74e00aSAlexandre Bounine  *
94de74e00aSAlexandre Bounine  * Tries to reserve the specified destID.
95de74e00aSAlexandre Bounine  * Returns 0 if successfull.
96de74e00aSAlexandre Bounine  */
97de74e00aSAlexandre Bounine static int rio_destid_reserve(struct rio_net *net, u16 destid)
98de74e00aSAlexandre Bounine {
99de74e00aSAlexandre Bounine 	int oldbit;
100de74e00aSAlexandre Bounine 	struct rio_id_table *idtab = &net->destid_table;
101de74e00aSAlexandre Bounine 
102de74e00aSAlexandre Bounine 	destid -= idtab->start;
103de74e00aSAlexandre Bounine 	spin_lock(&idtab->lock);
104de74e00aSAlexandre Bounine 	oldbit = test_and_set_bit(destid, idtab->table);
105de74e00aSAlexandre Bounine 	spin_unlock(&idtab->lock);
106de74e00aSAlexandre Bounine 	return oldbit;
107de74e00aSAlexandre Bounine }
108de74e00aSAlexandre Bounine 
109de74e00aSAlexandre Bounine /*
110de74e00aSAlexandre Bounine  * rio_destid_free - free a previously allocated destID
111de74e00aSAlexandre Bounine  * net: RIO network
112de74e00aSAlexandre Bounine  * destid: destID to free
113de74e00aSAlexandre Bounine  *
114de74e00aSAlexandre Bounine  * Makes the specified destID available for use.
115de74e00aSAlexandre Bounine  */
116de74e00aSAlexandre Bounine static void rio_destid_free(struct rio_net *net, u16 destid)
117de74e00aSAlexandre Bounine {
118de74e00aSAlexandre Bounine 	struct rio_id_table *idtab = &net->destid_table;
119de74e00aSAlexandre Bounine 
120de74e00aSAlexandre Bounine 	destid -= idtab->start;
121de74e00aSAlexandre Bounine 	spin_lock(&idtab->lock);
122de74e00aSAlexandre Bounine 	clear_bit(destid, idtab->table);
123de74e00aSAlexandre Bounine 	spin_unlock(&idtab->lock);
124de74e00aSAlexandre Bounine }
125de74e00aSAlexandre Bounine 
126de74e00aSAlexandre Bounine /*
127de74e00aSAlexandre Bounine  * rio_destid_first - return first destID in use
128de74e00aSAlexandre Bounine  * net: RIO network
129de74e00aSAlexandre Bounine  */
130de74e00aSAlexandre Bounine static u16 rio_destid_first(struct rio_net *net)
131de74e00aSAlexandre Bounine {
132de74e00aSAlexandre Bounine 	int destid;
133de74e00aSAlexandre Bounine 	struct rio_id_table *idtab = &net->destid_table;
134de74e00aSAlexandre Bounine 
135de74e00aSAlexandre Bounine 	spin_lock(&idtab->lock);
136de74e00aSAlexandre Bounine 	destid = find_first_bit(idtab->table, idtab->max);
137de74e00aSAlexandre Bounine 	if (destid >= idtab->max)
138de74e00aSAlexandre Bounine 		destid = RIO_INVALID_DESTID;
139de74e00aSAlexandre Bounine 	else
140de74e00aSAlexandre Bounine 		destid += idtab->start;
141de74e00aSAlexandre Bounine 	spin_unlock(&idtab->lock);
142de74e00aSAlexandre Bounine 	return (u16)destid;
143de74e00aSAlexandre Bounine }
144de74e00aSAlexandre Bounine 
145de74e00aSAlexandre Bounine /*
146de74e00aSAlexandre Bounine  * rio_destid_next - return next destID in use
147de74e00aSAlexandre Bounine  * net: RIO network
148de74e00aSAlexandre Bounine  * from: destination ID from which search shall continue
149de74e00aSAlexandre Bounine  */
150de74e00aSAlexandre Bounine static u16 rio_destid_next(struct rio_net *net, u16 from)
151de74e00aSAlexandre Bounine {
152de74e00aSAlexandre Bounine 	int destid;
153de74e00aSAlexandre Bounine 	struct rio_id_table *idtab = &net->destid_table;
154de74e00aSAlexandre Bounine 
155de74e00aSAlexandre Bounine 	spin_lock(&idtab->lock);
156de74e00aSAlexandre Bounine 	destid = find_next_bit(idtab->table, idtab->max, from);
157de74e00aSAlexandre Bounine 	if (destid >= idtab->max)
158de74e00aSAlexandre Bounine 		destid = RIO_INVALID_DESTID;
159de74e00aSAlexandre Bounine 	else
160de74e00aSAlexandre Bounine 		destid += idtab->start;
161de74e00aSAlexandre Bounine 	spin_unlock(&idtab->lock);
162de74e00aSAlexandre Bounine 	return (u16)destid;
163de74e00aSAlexandre Bounine }
164de74e00aSAlexandre Bounine 
165eb188d0eSMatt Porter /**
166eb188d0eSMatt Porter  * rio_get_device_id - Get the base/extended device id for a device
167eb188d0eSMatt Porter  * @port: RIO master port
168eb188d0eSMatt Porter  * @destid: Destination ID of device
169eb188d0eSMatt Porter  * @hopcount: Hopcount to device
170eb188d0eSMatt Porter  *
171eb188d0eSMatt Porter  * Reads the base/extended device id from a device. Returns the
172eb188d0eSMatt Porter  * 8/16-bit device ID.
173eb188d0eSMatt Porter  */
174eb188d0eSMatt Porter static u16 rio_get_device_id(struct rio_mport *port, u16 destid, u8 hopcount)
175eb188d0eSMatt Porter {
176eb188d0eSMatt Porter 	u32 result;
177eb188d0eSMatt Porter 
178eb188d0eSMatt Porter 	rio_mport_read_config_32(port, destid, hopcount, RIO_DID_CSR, &result);
179eb188d0eSMatt Porter 
180e0423236SZhang Wei 	return RIO_GET_DID(port->sys_size, result);
181eb188d0eSMatt Porter }
182eb188d0eSMatt Porter 
183eb188d0eSMatt Porter /**
184eb188d0eSMatt Porter  * rio_set_device_id - Set the base/extended device id for a device
185eb188d0eSMatt Porter  * @port: RIO master port
186eb188d0eSMatt Porter  * @destid: Destination ID of device
187eb188d0eSMatt Porter  * @hopcount: Hopcount to device
188eb188d0eSMatt Porter  * @did: Device ID value to be written
189eb188d0eSMatt Porter  *
190eb188d0eSMatt Porter  * Writes the base/extended device id from a device.
191eb188d0eSMatt Porter  */
192fa78cc51SMatt Porter static void rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u16 did)
193eb188d0eSMatt Porter {
194eb188d0eSMatt Porter 	rio_mport_write_config_32(port, destid, hopcount, RIO_DID_CSR,
195e0423236SZhang Wei 				  RIO_SET_DID(port->sys_size, did));
196eb188d0eSMatt Porter }
197eb188d0eSMatt Porter 
198eb188d0eSMatt Porter /**
199eb188d0eSMatt Porter  * rio_local_set_device_id - Set the base/extended device id for a port
200eb188d0eSMatt Porter  * @port: RIO master port
201eb188d0eSMatt Porter  * @did: Device ID value to be written
202eb188d0eSMatt Porter  *
203eb188d0eSMatt Porter  * Writes the base/extended device id from a device.
204eb188d0eSMatt Porter  */
205eb188d0eSMatt Porter static void rio_local_set_device_id(struct rio_mport *port, u16 did)
206eb188d0eSMatt Porter {
207e0423236SZhang Wei 	rio_local_write_config_32(port, RIO_DID_CSR, RIO_SET_DID(port->sys_size,
208e0423236SZhang Wei 				did));
209eb188d0eSMatt Porter }
210eb188d0eSMatt Porter 
211eb188d0eSMatt Porter /**
212eb188d0eSMatt Porter  * rio_clear_locks- Release all host locks and signal enumeration complete
213a7071efcSAlexandre Bounine  * @net: RIO network to run on
214eb188d0eSMatt Porter  *
215eb188d0eSMatt Porter  * Marks the component tag CSR on each device with the enumeration
216eb188d0eSMatt Porter  * complete flag. When complete, it then release the host locks on
217eb188d0eSMatt Porter  * each device. Returns 0 on success or %-EINVAL on failure.
218eb188d0eSMatt Porter  */
219a7071efcSAlexandre Bounine static int rio_clear_locks(struct rio_net *net)
220eb188d0eSMatt Porter {
221a7071efcSAlexandre Bounine 	struct rio_mport *port = net->hport;
222eb188d0eSMatt Porter 	struct rio_dev *rdev;
223eb188d0eSMatt Porter 	u32 result;
224eb188d0eSMatt Porter 	int ret = 0;
225eb188d0eSMatt Porter 
226eb188d0eSMatt Porter 	/* Release host device id locks */
227eb188d0eSMatt Porter 	rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR,
228eb188d0eSMatt Porter 				  port->host_deviceid);
229eb188d0eSMatt Porter 	rio_local_read_config_32(port, RIO_HOST_DID_LOCK_CSR, &result);
230eb188d0eSMatt Porter 	if ((result & 0xffff) != 0xffff) {
231eb188d0eSMatt Porter 		printk(KERN_INFO
232eb188d0eSMatt Porter 		       "RIO: badness when releasing host lock on master port, result %8.8x\n",
233eb188d0eSMatt Porter 		       result);
234eb188d0eSMatt Porter 		ret = -EINVAL;
235eb188d0eSMatt Porter 	}
236a7071efcSAlexandre Bounine 	list_for_each_entry(rdev, &net->devices, net_list) {
237eb188d0eSMatt Porter 		rio_write_config_32(rdev, RIO_HOST_DID_LOCK_CSR,
238eb188d0eSMatt Porter 				    port->host_deviceid);
239eb188d0eSMatt Porter 		rio_read_config_32(rdev, RIO_HOST_DID_LOCK_CSR, &result);
240eb188d0eSMatt Porter 		if ((result & 0xffff) != 0xffff) {
241eb188d0eSMatt Porter 			printk(KERN_INFO
242eb188d0eSMatt Porter 			       "RIO: badness when releasing host lock on vid %4.4x did %4.4x\n",
243eb188d0eSMatt Porter 			       rdev->vid, rdev->did);
244eb188d0eSMatt Porter 			ret = -EINVAL;
245eb188d0eSMatt Porter 		}
246af84ca38SAlexandre Bounine 
247af84ca38SAlexandre Bounine 		/* Mark device as discovered and enable master */
248af84ca38SAlexandre Bounine 		rio_read_config_32(rdev,
249af84ca38SAlexandre Bounine 				   rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR,
250af84ca38SAlexandre Bounine 				   &result);
251af84ca38SAlexandre Bounine 		result |= RIO_PORT_GEN_DISCOVERED | RIO_PORT_GEN_MASTER;
252af84ca38SAlexandre Bounine 		rio_write_config_32(rdev,
253af84ca38SAlexandre Bounine 				    rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR,
254af84ca38SAlexandre Bounine 				    result);
255eb188d0eSMatt Porter 	}
256eb188d0eSMatt Porter 
257eb188d0eSMatt Porter 	return ret;
258eb188d0eSMatt Porter }
259eb188d0eSMatt Porter 
260eb188d0eSMatt Porter /**
261eb188d0eSMatt Porter  * rio_enum_host- Set host lock and initialize host destination ID
262eb188d0eSMatt Porter  * @port: Master port to issue transaction
263eb188d0eSMatt Porter  *
264eb188d0eSMatt Porter  * Sets the local host master port lock and destination ID register
265eb188d0eSMatt Porter  * with the host device ID value. The host device ID value is provided
266eb188d0eSMatt Porter  * by the platform. Returns %0 on success or %-1 on failure.
267eb188d0eSMatt Porter  */
268eb188d0eSMatt Porter static int rio_enum_host(struct rio_mport *port)
269eb188d0eSMatt Porter {
270eb188d0eSMatt Porter 	u32 result;
271eb188d0eSMatt Porter 
272eb188d0eSMatt Porter 	/* Set master port host device id lock */
273eb188d0eSMatt Porter 	rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR,
274eb188d0eSMatt Porter 				  port->host_deviceid);
275eb188d0eSMatt Porter 
276eb188d0eSMatt Porter 	rio_local_read_config_32(port, RIO_HOST_DID_LOCK_CSR, &result);
277eb188d0eSMatt Porter 	if ((result & 0xffff) != port->host_deviceid)
278eb188d0eSMatt Porter 		return -1;
279eb188d0eSMatt Porter 
280eb188d0eSMatt Porter 	/* Set master port destid and init destid ctr */
281eb188d0eSMatt Porter 	rio_local_set_device_id(port, port->host_deviceid);
282eb188d0eSMatt Porter 	return 0;
283eb188d0eSMatt Porter }
284eb188d0eSMatt Porter 
285eb188d0eSMatt Porter /**
286eb188d0eSMatt Porter  * rio_device_has_destid- Test if a device contains a destination ID register
287eb188d0eSMatt Porter  * @port: Master port to issue transaction
288eb188d0eSMatt Porter  * @src_ops: RIO device source operations
289eb188d0eSMatt Porter  * @dst_ops: RIO device destination operations
290eb188d0eSMatt Porter  *
291eb188d0eSMatt Porter  * Checks the provided @src_ops and @dst_ops for the necessary transaction
292eb188d0eSMatt Porter  * capabilities that indicate whether or not a device will implement a
293eb188d0eSMatt Porter  * destination ID register. Returns 1 if true or 0 if false.
294eb188d0eSMatt Porter  */
295eb188d0eSMatt Porter static int rio_device_has_destid(struct rio_mport *port, int src_ops,
296eb188d0eSMatt Porter 				 int dst_ops)
297eb188d0eSMatt Porter {
298fa78cc51SMatt Porter 	u32 mask = RIO_OPS_READ | RIO_OPS_WRITE | RIO_OPS_ATOMIC_TST_SWP | RIO_OPS_ATOMIC_INC | RIO_OPS_ATOMIC_DEC | RIO_OPS_ATOMIC_SET | RIO_OPS_ATOMIC_CLR;
299fa78cc51SMatt Porter 
300fa78cc51SMatt Porter 	return !!((src_ops | dst_ops) & mask);
301eb188d0eSMatt Porter }
302eb188d0eSMatt Porter 
303eb188d0eSMatt Porter /**
304eb188d0eSMatt Porter  * rio_release_dev- Frees a RIO device struct
305eb188d0eSMatt Porter  * @dev: LDM device associated with a RIO device struct
306eb188d0eSMatt Porter  *
307eb188d0eSMatt Porter  * Gets the RIO device struct associated a RIO device struct.
308eb188d0eSMatt Porter  * The RIO device struct is freed.
309eb188d0eSMatt Porter  */
310eb188d0eSMatt Porter static void rio_release_dev(struct device *dev)
311eb188d0eSMatt Porter {
312eb188d0eSMatt Porter 	struct rio_dev *rdev;
313eb188d0eSMatt Porter 
314eb188d0eSMatt Porter 	rdev = to_rio_dev(dev);
315eb188d0eSMatt Porter 	kfree(rdev);
316eb188d0eSMatt Porter }
317eb188d0eSMatt Porter 
318eb188d0eSMatt Porter /**
319eb188d0eSMatt Porter  * rio_is_switch- Tests if a RIO device has switch capabilities
320eb188d0eSMatt Porter  * @rdev: RIO device
321eb188d0eSMatt Porter  *
322eb188d0eSMatt Porter  * Gets the RIO device Processing Element Features register
323eb188d0eSMatt Porter  * contents and tests for switch capabilities. Returns 1 if
324eb188d0eSMatt Porter  * the device is a switch or 0 if it is not a switch.
325eb188d0eSMatt Porter  * The RIO device struct is freed.
326eb188d0eSMatt Porter  */
327eb188d0eSMatt Porter static int rio_is_switch(struct rio_dev *rdev)
328eb188d0eSMatt Porter {
329eb188d0eSMatt Porter 	if (rdev->pef & RIO_PEF_SWITCH)
330eb188d0eSMatt Porter 		return 1;
331eb188d0eSMatt Porter 	return 0;
332eb188d0eSMatt Porter }
333eb188d0eSMatt Porter 
334eb188d0eSMatt Porter /**
335058f88d6SAlexandre Bounine  * rio_switch_init - Sets switch operations for a particular vendor switch
336eb188d0eSMatt Porter  * @rdev: RIO device
337058f88d6SAlexandre Bounine  * @do_enum: Enumeration/Discovery mode flag
338eb188d0eSMatt Porter  *
339058f88d6SAlexandre Bounine  * Searches the RIO switch ops table for known switch types. If the vid
340058f88d6SAlexandre Bounine  * and did match a switch table entry, then call switch initialization
341058f88d6SAlexandre Bounine  * routine to setup switch-specific routines.
342eb188d0eSMatt Porter  */
343058f88d6SAlexandre Bounine static void rio_switch_init(struct rio_dev *rdev, int do_enum)
344eb188d0eSMatt Porter {
345058f88d6SAlexandre Bounine 	struct rio_switch_ops *cur = __start_rio_switch_ops;
346058f88d6SAlexandre Bounine 	struct rio_switch_ops *end = __end_rio_switch_ops;
347eb188d0eSMatt Porter 
348eb188d0eSMatt Porter 	while (cur < end) {
349eb188d0eSMatt Porter 		if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) {
350058f88d6SAlexandre Bounine 			pr_debug("RIO: calling init routine for %s\n",
351058f88d6SAlexandre Bounine 				 rio_name(rdev));
352058f88d6SAlexandre Bounine 			cur->init_hook(rdev, do_enum);
35307590ff0SAlexandre Bounine 			break;
354eb188d0eSMatt Porter 		}
355eb188d0eSMatt Porter 		cur++;
356eb188d0eSMatt Porter 	}
357eb188d0eSMatt Porter 
35807590ff0SAlexandre Bounine 	if ((cur >= end) && (rdev->pef & RIO_PEF_STD_RT)) {
35907590ff0SAlexandre Bounine 		pr_debug("RIO: adding STD routing ops for %s\n",
36007590ff0SAlexandre Bounine 			rio_name(rdev));
36107590ff0SAlexandre Bounine 		rdev->rswitch->add_entry = rio_std_route_add_entry;
36207590ff0SAlexandre Bounine 		rdev->rswitch->get_entry = rio_std_route_get_entry;
36307590ff0SAlexandre Bounine 		rdev->rswitch->clr_table = rio_std_route_clr_table;
36407590ff0SAlexandre Bounine 	}
36507590ff0SAlexandre Bounine 
366eb188d0eSMatt Porter 	if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry)
367eb188d0eSMatt Porter 		printk(KERN_ERR "RIO: missing routing ops for %s\n",
368eb188d0eSMatt Porter 		       rio_name(rdev));
369eb188d0eSMatt Porter }
370eb188d0eSMatt Porter 
371eb188d0eSMatt Porter /**
372eb188d0eSMatt Porter  * rio_add_device- Adds a RIO device to the device model
373eb188d0eSMatt Porter  * @rdev: RIO device
374eb188d0eSMatt Porter  *
375eb188d0eSMatt Porter  * Adds the RIO device to the global device list and adds the RIO
376eb188d0eSMatt Porter  * device to the RIO device list.  Creates the generic sysfs nodes
377eb188d0eSMatt Porter  * for an RIO device.
378eb188d0eSMatt Porter  */
3795f28c520SYang Li static int __devinit rio_add_device(struct rio_dev *rdev)
380eb188d0eSMatt Porter {
3815f28c520SYang Li 	int err;
3825f28c520SYang Li 
3835f28c520SYang Li 	err = device_add(&rdev->dev);
3845f28c520SYang Li 	if (err)
3855f28c520SYang Li 		return err;
386eb188d0eSMatt Porter 
387eb188d0eSMatt Porter 	spin_lock(&rio_global_list_lock);
388eb188d0eSMatt Porter 	list_add_tail(&rdev->global_list, &rio_devices);
389eb188d0eSMatt Porter 	spin_unlock(&rio_global_list_lock);
390eb188d0eSMatt Porter 
391eb188d0eSMatt Porter 	rio_create_sysfs_dev_files(rdev);
3925f28c520SYang Li 
3935f28c520SYang Li 	return 0;
394eb188d0eSMatt Porter }
395eb188d0eSMatt Porter 
396eb188d0eSMatt Porter /**
39725985edcSLucas De Marchi  * rio_enable_rx_tx_port - enable input receiver and output transmitter of
398933af4a6SThomas Moll  * given port
399933af4a6SThomas Moll  * @port: Master port associated with the RIO network
400933af4a6SThomas Moll  * @local: local=1 select local port otherwise a far device is reached
401933af4a6SThomas Moll  * @destid: Destination ID of the device to check host bit
402933af4a6SThomas Moll  * @hopcount: Number of hops to reach the target
403933af4a6SThomas Moll  * @port_num: Port (-number on switch) to enable on a far end device
404933af4a6SThomas Moll  *
405933af4a6SThomas Moll  * Returns 0 or 1 from on General Control Command and Status Register
406933af4a6SThomas Moll  * (EXT_PTR+0x3C)
407933af4a6SThomas Moll  */
408933af4a6SThomas Moll inline int rio_enable_rx_tx_port(struct rio_mport *port,
409933af4a6SThomas Moll 				 int local, u16 destid,
410933af4a6SThomas Moll 				 u8 hopcount, u8 port_num) {
411933af4a6SThomas Moll #ifdef CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS
412933af4a6SThomas Moll 	u32 regval;
413933af4a6SThomas Moll 	u32 ext_ftr_ptr;
414933af4a6SThomas Moll 
415933af4a6SThomas Moll 	/*
416933af4a6SThomas Moll 	* enable rx input tx output port
417933af4a6SThomas Moll 	*/
418933af4a6SThomas Moll 	pr_debug("rio_enable_rx_tx_port(local = %d, destid = %d, hopcount = "
419933af4a6SThomas Moll 		 "%d, port_num = %d)\n", local, destid, hopcount, port_num);
420933af4a6SThomas Moll 
421933af4a6SThomas Moll 	ext_ftr_ptr = rio_mport_get_physefb(port, local, destid, hopcount);
422933af4a6SThomas Moll 
423933af4a6SThomas Moll 	if (local) {
424933af4a6SThomas Moll 		rio_local_read_config_32(port, ext_ftr_ptr +
425933af4a6SThomas Moll 				RIO_PORT_N_CTL_CSR(0),
426933af4a6SThomas Moll 				&regval);
427933af4a6SThomas Moll 	} else {
428933af4a6SThomas Moll 		if (rio_mport_read_config_32(port, destid, hopcount,
429933af4a6SThomas Moll 		ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), &regval) < 0)
430933af4a6SThomas Moll 			return -EIO;
431933af4a6SThomas Moll 	}
432933af4a6SThomas Moll 
433933af4a6SThomas Moll 	if (regval & RIO_PORT_N_CTL_P_TYP_SER) {
434933af4a6SThomas Moll 		/* serial */
435933af4a6SThomas Moll 		regval = regval | RIO_PORT_N_CTL_EN_RX_SER
436933af4a6SThomas Moll 				| RIO_PORT_N_CTL_EN_TX_SER;
437933af4a6SThomas Moll 	} else {
438933af4a6SThomas Moll 		/* parallel */
439933af4a6SThomas Moll 		regval = regval | RIO_PORT_N_CTL_EN_RX_PAR
440933af4a6SThomas Moll 				| RIO_PORT_N_CTL_EN_TX_PAR;
441933af4a6SThomas Moll 	}
442933af4a6SThomas Moll 
443933af4a6SThomas Moll 	if (local) {
444933af4a6SThomas Moll 		rio_local_write_config_32(port, ext_ftr_ptr +
445933af4a6SThomas Moll 					  RIO_PORT_N_CTL_CSR(0), regval);
446933af4a6SThomas Moll 	} else {
447933af4a6SThomas Moll 		if (rio_mport_write_config_32(port, destid, hopcount,
448933af4a6SThomas Moll 		    ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), regval) < 0)
449933af4a6SThomas Moll 			return -EIO;
450933af4a6SThomas Moll 	}
451933af4a6SThomas Moll #endif
452933af4a6SThomas Moll 	return 0;
453933af4a6SThomas Moll }
454933af4a6SThomas Moll 
455933af4a6SThomas Moll /**
456eb188d0eSMatt Porter  * rio_setup_device- Allocates and sets up a RIO device
457eb188d0eSMatt Porter  * @net: RIO network
458eb188d0eSMatt Porter  * @port: Master port to send transactions
459eb188d0eSMatt Porter  * @destid: Current destination ID
460eb188d0eSMatt Porter  * @hopcount: Current hopcount
461eb188d0eSMatt Porter  * @do_enum: Enumeration/Discovery mode flag
462eb188d0eSMatt Porter  *
463eb188d0eSMatt Porter  * Allocates a RIO device and configures fields based on configuration
464eb188d0eSMatt Porter  * space contents. If device has a destination ID register, a destination
465eb188d0eSMatt Porter  * ID is either assigned in enumeration mode or read from configuration
466eb188d0eSMatt Porter  * space in discovery mode.  If the device has switch capabilities, then
467eb188d0eSMatt Porter  * a switch is allocated and configured appropriately. Returns a pointer
468eb188d0eSMatt Porter  * to a RIO device on success or NULL on failure.
469eb188d0eSMatt Porter  *
470eb188d0eSMatt Porter  */
471181a6ff0SLi Yang static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
472eb188d0eSMatt Porter 					struct rio_mport *port, u16 destid,
473eb188d0eSMatt Porter 					u8 hopcount, int do_enum)
474eb188d0eSMatt Porter {
4755f28c520SYang Li 	int ret = 0;
476eb188d0eSMatt Porter 	struct rio_dev *rdev;
4775f28c520SYang Li 	struct rio_switch *rswitch = NULL;
478eb188d0eSMatt Porter 	int result, rdid;
479ded05782SAlexandre Bounine 	size_t size;
480ded05782SAlexandre Bounine 	u32 swpinfo = 0;
481eb188d0eSMatt Porter 
482ded05782SAlexandre Bounine 	size = sizeof(struct rio_dev);
483ded05782SAlexandre Bounine 	if (rio_mport_read_config_32(port, destid, hopcount,
484ded05782SAlexandre Bounine 				     RIO_PEF_CAR, &result))
485ded05782SAlexandre Bounine 		return NULL;
486ded05782SAlexandre Bounine 
487ded05782SAlexandre Bounine 	if (result & (RIO_PEF_SWITCH | RIO_PEF_MULTIPORT)) {
488ded05782SAlexandre Bounine 		rio_mport_read_config_32(port, destid, hopcount,
489ded05782SAlexandre Bounine 					 RIO_SWP_INFO_CAR, &swpinfo);
490ded05782SAlexandre Bounine 		if (result & RIO_PEF_SWITCH) {
491ded05782SAlexandre Bounine 			size += (RIO_GET_TOTAL_PORTS(swpinfo) *
492ded05782SAlexandre Bounine 				sizeof(rswitch->nextdev[0])) + sizeof(*rswitch);
493ded05782SAlexandre Bounine 		}
494ded05782SAlexandre Bounine 	}
495ded05782SAlexandre Bounine 
496ded05782SAlexandre Bounine 	rdev = kzalloc(size, GFP_KERNEL);
497eb188d0eSMatt Porter 	if (!rdev)
4985f28c520SYang Li 		return NULL;
499eb188d0eSMatt Porter 
500eb188d0eSMatt Porter 	rdev->net = net;
501ded05782SAlexandre Bounine 	rdev->pef = result;
502ded05782SAlexandre Bounine 	rdev->swpinfo = swpinfo;
503eb188d0eSMatt Porter 	rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_ID_CAR,
504eb188d0eSMatt Porter 				 &result);
505eb188d0eSMatt Porter 	rdev->did = result >> 16;
506eb188d0eSMatt Porter 	rdev->vid = result & 0xffff;
507eb188d0eSMatt Porter 	rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_INFO_CAR,
508eb188d0eSMatt Porter 				 &rdev->device_rev);
509eb188d0eSMatt Porter 	rio_mport_read_config_32(port, destid, hopcount, RIO_ASM_ID_CAR,
510eb188d0eSMatt Porter 				 &result);
511eb188d0eSMatt Porter 	rdev->asm_did = result >> 16;
512eb188d0eSMatt Porter 	rdev->asm_vid = result & 0xffff;
513eb188d0eSMatt Porter 	rio_mport_read_config_32(port, destid, hopcount, RIO_ASM_INFO_CAR,
514eb188d0eSMatt Porter 				 &result);
515eb188d0eSMatt Porter 	rdev->asm_rev = result >> 16;
516e5cabeb3SAlexandre Bounine 	if (rdev->pef & RIO_PEF_EXT_FEATURES) {
517eb188d0eSMatt Porter 		rdev->efptr = result & 0xffff;
518e5cabeb3SAlexandre Bounine 		rdev->phys_efptr = rio_mport_get_physefb(port, 0, destid,
519e5cabeb3SAlexandre Bounine 							 hopcount);
520e5cabeb3SAlexandre Bounine 
521e5cabeb3SAlexandre Bounine 		rdev->em_efptr = rio_mport_get_feature(port, 0, destid,
522e5cabeb3SAlexandre Bounine 						hopcount, RIO_EFB_ERR_MGMNT);
523e5cabeb3SAlexandre Bounine 	}
524eb188d0eSMatt Porter 
525eb188d0eSMatt Porter 	rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR,
526eb188d0eSMatt Porter 				 &rdev->src_ops);
527eb188d0eSMatt Porter 	rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR,
528eb188d0eSMatt Porter 				 &rdev->dst_ops);
529eb188d0eSMatt Porter 
530af84ca38SAlexandre Bounine 	if (do_enum) {
531af84ca38SAlexandre Bounine 		/* Assign component tag to device */
532af84ca38SAlexandre Bounine 		if (next_comptag >= 0x10000) {
533af84ca38SAlexandre Bounine 			pr_err("RIO: Component Tag Counter Overflow\n");
534af84ca38SAlexandre Bounine 			goto cleanup;
535af84ca38SAlexandre Bounine 		}
536af84ca38SAlexandre Bounine 		rio_mport_write_config_32(port, destid, hopcount,
537af84ca38SAlexandre Bounine 					  RIO_COMPONENT_TAG_CSR, next_comptag);
538af84ca38SAlexandre Bounine 		rdev->comp_tag = next_comptag++;
539558bda65SAlexandre Bounine 	}  else {
540558bda65SAlexandre Bounine 		rio_mport_read_config_32(port, destid, hopcount,
541558bda65SAlexandre Bounine 					 RIO_COMPONENT_TAG_CSR,
542558bda65SAlexandre Bounine 					 &rdev->comp_tag);
543af84ca38SAlexandre Bounine 	}
544af84ca38SAlexandre Bounine 
545c70555b0SAlexandre Bounine 	if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) {
546c70555b0SAlexandre Bounine 		if (do_enum) {
547eb188d0eSMatt Porter 			rio_set_device_id(port, destid, hopcount, next_destid);
548de74e00aSAlexandre Bounine 			rdev->destid = next_destid;
549de74e00aSAlexandre Bounine 			next_destid = rio_destid_alloc(net);
550eb188d0eSMatt Porter 		} else
551eb188d0eSMatt Porter 			rdev->destid = rio_get_device_id(port, destid, hopcount);
552a93192a5SAlexandre Bounine 
553a93192a5SAlexandre Bounine 		rdev->hopcount = 0xff;
554a93192a5SAlexandre Bounine 	} else {
555a93192a5SAlexandre Bounine 		/* Switch device has an associated destID which
556a93192a5SAlexandre Bounine 		 * will be adjusted later
557a93192a5SAlexandre Bounine 		 */
558a93192a5SAlexandre Bounine 		rdev->destid = destid;
559a93192a5SAlexandre Bounine 		rdev->hopcount = hopcount;
560a93192a5SAlexandre Bounine 	}
561eb188d0eSMatt Porter 
562eb188d0eSMatt Porter 	/* If a PE has both switch and other functions, show it as a switch */
563eb188d0eSMatt Porter 	if (rio_is_switch(rdev)) {
564ded05782SAlexandre Bounine 		rswitch = rdev->rswitch;
565558bda65SAlexandre Bounine 		rswitch->switchid = rdev->comp_tag & RIO_CTAG_UDEVID;
566e5cabeb3SAlexandre Bounine 		rswitch->port_ok = 0;
567e0423236SZhang Wei 		rswitch->route_table = kzalloc(sizeof(u8)*
568e0423236SZhang Wei 					RIO_MAX_ROUTE_ENTRIES(port->sys_size),
569e0423236SZhang Wei 					GFP_KERNEL);
5705f28c520SYang Li 		if (!rswitch->route_table)
5715f28c520SYang Li 			goto cleanup;
572eb188d0eSMatt Porter 		/* Initialize switch route table */
573e0423236SZhang Wei 		for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES(port->sys_size);
574e0423236SZhang Wei 				rdid++)
575eb188d0eSMatt Porter 			rswitch->route_table[rdid] = RIO_INVALID_ROUTE;
576b53c7583SKay Sievers 		dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id,
577ded05782SAlexandre Bounine 			     rswitch->switchid);
578058f88d6SAlexandre Bounine 		rio_switch_init(rdev, do_enum);
579eb188d0eSMatt Porter 
580ded05782SAlexandre Bounine 		if (do_enum && rswitch->clr_table)
581ded05782SAlexandre Bounine 			rswitch->clr_table(port, destid, hopcount,
58207590ff0SAlexandre Bounine 					   RIO_GLOBAL_TABLE);
58307590ff0SAlexandre Bounine 
584a7071efcSAlexandre Bounine 		list_add_tail(&rswitch->node, &net->switches);
585eb188d0eSMatt Porter 
586933af4a6SThomas Moll 	} else {
587933af4a6SThomas Moll 		if (do_enum)
588933af4a6SThomas Moll 			/*Enable Input Output Port (transmitter reviever)*/
589933af4a6SThomas Moll 			rio_enable_rx_tx_port(port, 0, destid, hopcount, 0);
590933af4a6SThomas Moll 
591b53c7583SKay Sievers 		dev_set_name(&rdev->dev, "%02x:e:%04x", rdev->net->id,
592eb188d0eSMatt Porter 			     rdev->destid);
593933af4a6SThomas Moll 	}
594eb188d0eSMatt Porter 
595eb188d0eSMatt Porter 	rdev->dev.bus = &rio_bus_type;
5962c70f022SAlexandre Bounine 	rdev->dev.parent = &rio_bus;
597eb188d0eSMatt Porter 
598eb188d0eSMatt Porter 	device_initialize(&rdev->dev);
599eb188d0eSMatt Porter 	rdev->dev.release = rio_release_dev;
600eb188d0eSMatt Porter 	rio_dev_get(rdev);
601eb188d0eSMatt Porter 
602284901a9SYang Hongyang 	rdev->dma_mask = DMA_BIT_MASK(32);
603fa78cc51SMatt Porter 	rdev->dev.dma_mask = &rdev->dma_mask;
604284901a9SYang Hongyang 	rdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
605eb188d0eSMatt Porter 
606284fb68dSAlexandre Bounine 	if (rdev->dst_ops & RIO_DST_OPS_DOORBELL)
607eb188d0eSMatt Porter 		rio_init_dbell_res(&rdev->riores[RIO_DOORBELL_RESOURCE],
608eb188d0eSMatt Porter 				   0, 0xffff);
609eb188d0eSMatt Porter 
6105f28c520SYang Li 	ret = rio_add_device(rdev);
6115f28c520SYang Li 	if (ret)
6125f28c520SYang Li 		goto cleanup;
613eb188d0eSMatt Porter 
614eb188d0eSMatt Porter 	return rdev;
6155f28c520SYang Li 
6165f28c520SYang Li cleanup:
617166c050bSAlexandre Bounine 	if (rswitch)
6185f28c520SYang Li 		kfree(rswitch->route_table);
619ded05782SAlexandre Bounine 
6205f28c520SYang Li 	kfree(rdev);
6215f28c520SYang Li 	return NULL;
622eb188d0eSMatt Porter }
623eb188d0eSMatt Porter 
624eb188d0eSMatt Porter /**
625eb188d0eSMatt Porter  * rio_sport_is_active- Tests if a switch port has an active connection.
626eb188d0eSMatt Porter  * @port: Master port to send transaction
627eb188d0eSMatt Porter  * @destid: Associated destination ID for switch
628eb188d0eSMatt Porter  * @hopcount: Hopcount to reach switch
629eb188d0eSMatt Porter  * @sport: Switch port number
630eb188d0eSMatt Porter  *
631eb188d0eSMatt Porter  * Reads the port error status CSR for a particular switch port to
632eb188d0eSMatt Porter  * determine if the port has an active link.  Returns
633e5cabeb3SAlexandre Bounine  * %RIO_PORT_N_ERR_STS_PORT_OK if the port is active or %0 if it is
634eb188d0eSMatt Porter  * inactive.
635eb188d0eSMatt Porter  */
636eb188d0eSMatt Porter static int
637eb188d0eSMatt Porter rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
638eb188d0eSMatt Porter {
639e5cabeb3SAlexandre Bounine 	u32 result = 0;
640eb188d0eSMatt Porter 	u32 ext_ftr_ptr;
641eb188d0eSMatt Porter 
642e5cabeb3SAlexandre Bounine 	ext_ftr_ptr = rio_mport_get_efb(port, 0, destid, hopcount, 0);
643eb188d0eSMatt Porter 
644e5cabeb3SAlexandre Bounine 	while (ext_ftr_ptr) {
645e5cabeb3SAlexandre Bounine 		rio_mport_read_config_32(port, destid, hopcount,
646e5cabeb3SAlexandre Bounine 					 ext_ftr_ptr, &result);
647e5cabeb3SAlexandre Bounine 		result = RIO_GET_BLOCK_ID(result);
648e5cabeb3SAlexandre Bounine 		if ((result == RIO_EFB_SER_EP_FREE_ID) ||
649e5cabeb3SAlexandre Bounine 		    (result == RIO_EFB_SER_EP_FREE_ID_V13P) ||
650e5cabeb3SAlexandre Bounine 		    (result == RIO_EFB_SER_EP_FREC_ID))
651eb188d0eSMatt Porter 			break;
652e5cabeb3SAlexandre Bounine 
653e5cabeb3SAlexandre Bounine 		ext_ftr_ptr = rio_mport_get_efb(port, 0, destid, hopcount,
654e5cabeb3SAlexandre Bounine 						ext_ftr_ptr);
655e5cabeb3SAlexandre Bounine 	}
656eb188d0eSMatt Porter 
657eb188d0eSMatt Porter 	if (ext_ftr_ptr)
658eb188d0eSMatt Porter 		rio_mport_read_config_32(port, destid, hopcount,
659eb188d0eSMatt Porter 					 ext_ftr_ptr +
660eb188d0eSMatt Porter 					 RIO_PORT_N_ERR_STS_CSR(sport),
661eb188d0eSMatt Porter 					 &result);
662eb188d0eSMatt Porter 
663e5cabeb3SAlexandre Bounine 	return result & RIO_PORT_N_ERR_STS_PORT_OK;
664eb188d0eSMatt Porter }
665eb188d0eSMatt Porter 
666eb188d0eSMatt Porter /**
667818a04a0SAlexandre Bounine  * rio_lock_device - Acquires host device lock for specified device
668818a04a0SAlexandre Bounine  * @port: Master port to send transaction
669818a04a0SAlexandre Bounine  * @destid: Destination ID for device/switch
670818a04a0SAlexandre Bounine  * @hopcount: Hopcount to reach switch
671818a04a0SAlexandre Bounine  * @wait_ms: Max wait time in msec (0 = no timeout)
672818a04a0SAlexandre Bounine  *
673818a04a0SAlexandre Bounine  * Attepts to acquire host device lock for specified device
674818a04a0SAlexandre Bounine  * Returns 0 if device lock acquired or EINVAL if timeout expires.
675818a04a0SAlexandre Bounine  */
676818a04a0SAlexandre Bounine static int
677818a04a0SAlexandre Bounine rio_lock_device(struct rio_mport *port, u16 destid, u8 hopcount, int wait_ms)
678818a04a0SAlexandre Bounine {
679818a04a0SAlexandre Bounine 	u32 result;
680818a04a0SAlexandre Bounine 	int tcnt = 0;
681818a04a0SAlexandre Bounine 
682818a04a0SAlexandre Bounine 	/* Attempt to acquire device lock */
683818a04a0SAlexandre Bounine 	rio_mport_write_config_32(port, destid, hopcount,
684818a04a0SAlexandre Bounine 				  RIO_HOST_DID_LOCK_CSR, port->host_deviceid);
685818a04a0SAlexandre Bounine 	rio_mport_read_config_32(port, destid, hopcount,
686818a04a0SAlexandre Bounine 				 RIO_HOST_DID_LOCK_CSR, &result);
687818a04a0SAlexandre Bounine 
688818a04a0SAlexandre Bounine 	while (result != port->host_deviceid) {
689818a04a0SAlexandre Bounine 		if (wait_ms != 0 && tcnt == wait_ms) {
690818a04a0SAlexandre Bounine 			pr_debug("RIO: timeout when locking device %x:%x\n",
691818a04a0SAlexandre Bounine 				destid, hopcount);
692818a04a0SAlexandre Bounine 			return -EINVAL;
693818a04a0SAlexandre Bounine 		}
694818a04a0SAlexandre Bounine 
695818a04a0SAlexandre Bounine 		/* Delay a bit */
696818a04a0SAlexandre Bounine 		mdelay(1);
697818a04a0SAlexandre Bounine 		tcnt++;
698818a04a0SAlexandre Bounine 		/* Try to acquire device lock again */
699818a04a0SAlexandre Bounine 		rio_mport_write_config_32(port, destid,
700818a04a0SAlexandre Bounine 			hopcount,
701818a04a0SAlexandre Bounine 			RIO_HOST_DID_LOCK_CSR,
702818a04a0SAlexandre Bounine 			port->host_deviceid);
703818a04a0SAlexandre Bounine 		rio_mport_read_config_32(port, destid,
704818a04a0SAlexandre Bounine 			hopcount,
705818a04a0SAlexandre Bounine 			RIO_HOST_DID_LOCK_CSR, &result);
706818a04a0SAlexandre Bounine 	}
707818a04a0SAlexandre Bounine 
708818a04a0SAlexandre Bounine 	return 0;
709818a04a0SAlexandre Bounine }
710818a04a0SAlexandre Bounine 
711818a04a0SAlexandre Bounine /**
712818a04a0SAlexandre Bounine  * rio_unlock_device - Releases host device lock for specified device
713818a04a0SAlexandre Bounine  * @port: Master port to send transaction
714818a04a0SAlexandre Bounine  * @destid: Destination ID for device/switch
715818a04a0SAlexandre Bounine  * @hopcount: Hopcount to reach switch
716818a04a0SAlexandre Bounine  *
717818a04a0SAlexandre Bounine  * Returns 0 if device lock released or EINVAL if fails.
718818a04a0SAlexandre Bounine  */
719818a04a0SAlexandre Bounine static int
720818a04a0SAlexandre Bounine rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount)
721818a04a0SAlexandre Bounine {
722818a04a0SAlexandre Bounine 	u32 result;
723818a04a0SAlexandre Bounine 
724818a04a0SAlexandre Bounine 	/* Release device lock */
725818a04a0SAlexandre Bounine 	rio_mport_write_config_32(port, destid,
726818a04a0SAlexandre Bounine 				  hopcount,
727818a04a0SAlexandre Bounine 				  RIO_HOST_DID_LOCK_CSR,
728818a04a0SAlexandre Bounine 				  port->host_deviceid);
729818a04a0SAlexandre Bounine 	rio_mport_read_config_32(port, destid, hopcount,
730818a04a0SAlexandre Bounine 		RIO_HOST_DID_LOCK_CSR, &result);
731818a04a0SAlexandre Bounine 	if ((result & 0xffff) != 0xffff) {
732818a04a0SAlexandre Bounine 		pr_debug("RIO: badness when releasing device lock %x:%x\n",
733818a04a0SAlexandre Bounine 			 destid, hopcount);
734818a04a0SAlexandre Bounine 		return -EINVAL;
735818a04a0SAlexandre Bounine 	}
736818a04a0SAlexandre Bounine 
737818a04a0SAlexandre Bounine 	return 0;
738818a04a0SAlexandre Bounine }
739818a04a0SAlexandre Bounine 
740818a04a0SAlexandre Bounine /**
741eb188d0eSMatt Porter  * rio_route_add_entry- Add a route entry to a switch routing table
742a93192a5SAlexandre Bounine  * @rdev: RIO device
743eb188d0eSMatt Porter  * @table: Routing table ID
744eb188d0eSMatt Porter  * @route_destid: Destination ID to be routed
745eb188d0eSMatt Porter  * @route_port: Port number to be routed
746818a04a0SAlexandre Bounine  * @lock: lock switch device flag
747eb188d0eSMatt Porter  *
748eb188d0eSMatt Porter  * Calls the switch specific add_entry() method to add a route entry
749eb188d0eSMatt Porter  * on a switch. The route table can be specified using the @table
750eb188d0eSMatt Porter  * argument if a switch has per port routing tables or the normal
751eb188d0eSMatt Porter  * use is to specific all tables (or the global table) by passing
752eb188d0eSMatt Porter  * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL
753eb188d0eSMatt Porter  * on failure.
754eb188d0eSMatt Porter  */
755818a04a0SAlexandre Bounine static int
756a93192a5SAlexandre Bounine rio_route_add_entry(struct rio_dev *rdev,
757818a04a0SAlexandre Bounine 		    u16 table, u16 route_destid, u8 route_port, int lock)
758eb188d0eSMatt Porter {
759818a04a0SAlexandre Bounine 	int rc;
760818a04a0SAlexandre Bounine 
761818a04a0SAlexandre Bounine 	if (lock) {
762a93192a5SAlexandre Bounine 		rc = rio_lock_device(rdev->net->hport, rdev->destid,
763a93192a5SAlexandre Bounine 				     rdev->hopcount, 1000);
764818a04a0SAlexandre Bounine 		if (rc)
765818a04a0SAlexandre Bounine 			return rc;
766818a04a0SAlexandre Bounine 	}
767818a04a0SAlexandre Bounine 
768a93192a5SAlexandre Bounine 	rc = rdev->rswitch->add_entry(rdev->net->hport, rdev->destid,
769a93192a5SAlexandre Bounine 				      rdev->hopcount, table,
770eb188d0eSMatt Porter 				      route_destid, route_port);
771818a04a0SAlexandre Bounine 	if (lock)
772a93192a5SAlexandre Bounine 		rio_unlock_device(rdev->net->hport, rdev->destid,
773a93192a5SAlexandre Bounine 				  rdev->hopcount);
774818a04a0SAlexandre Bounine 
775818a04a0SAlexandre Bounine 	return rc;
776eb188d0eSMatt Porter }
777eb188d0eSMatt Porter 
778eb188d0eSMatt Porter /**
779eb188d0eSMatt Porter  * rio_route_get_entry- Read a route entry in a switch routing table
780a93192a5SAlexandre Bounine  * @rdev: RIO device
781eb188d0eSMatt Porter  * @table: Routing table ID
782eb188d0eSMatt Porter  * @route_destid: Destination ID to be routed
783eb188d0eSMatt Porter  * @route_port: Pointer to read port number into
784818a04a0SAlexandre Bounine  * @lock: lock switch device flag
785eb188d0eSMatt Porter  *
786eb188d0eSMatt Porter  * Calls the switch specific get_entry() method to read a route entry
787eb188d0eSMatt Porter  * in a switch. The route table can be specified using the @table
788eb188d0eSMatt Porter  * argument if a switch has per port routing tables or the normal
789eb188d0eSMatt Porter  * use is to specific all tables (or the global table) by passing
790eb188d0eSMatt Porter  * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL
791eb188d0eSMatt Porter  * on failure.
792eb188d0eSMatt Porter  */
793eb188d0eSMatt Porter static int
794a93192a5SAlexandre Bounine rio_route_get_entry(struct rio_dev *rdev, u16 table,
795818a04a0SAlexandre Bounine 		    u16 route_destid, u8 *route_port, int lock)
796eb188d0eSMatt Porter {
797818a04a0SAlexandre Bounine 	int rc;
798818a04a0SAlexandre Bounine 
799818a04a0SAlexandre Bounine 	if (lock) {
800a93192a5SAlexandre Bounine 		rc = rio_lock_device(rdev->net->hport, rdev->destid,
801a93192a5SAlexandre Bounine 				     rdev->hopcount, 1000);
802818a04a0SAlexandre Bounine 		if (rc)
803818a04a0SAlexandre Bounine 			return rc;
804818a04a0SAlexandre Bounine 	}
805818a04a0SAlexandre Bounine 
806a93192a5SAlexandre Bounine 	rc = rdev->rswitch->get_entry(rdev->net->hport, rdev->destid,
807a93192a5SAlexandre Bounine 				      rdev->hopcount, table,
808eb188d0eSMatt Porter 				      route_destid, route_port);
809818a04a0SAlexandre Bounine 	if (lock)
810a93192a5SAlexandre Bounine 		rio_unlock_device(rdev->net->hport, rdev->destid,
811a93192a5SAlexandre Bounine 				  rdev->hopcount);
812818a04a0SAlexandre Bounine 
813818a04a0SAlexandre Bounine 	return rc;
814eb188d0eSMatt Porter }
815eb188d0eSMatt Porter 
816eb188d0eSMatt Porter /**
817eb188d0eSMatt Porter  * rio_get_host_deviceid_lock- Reads the Host Device ID Lock CSR on a device
818eb188d0eSMatt Porter  * @port: Master port to send transaction
819eb188d0eSMatt Porter  * @hopcount: Number of hops to the device
820eb188d0eSMatt Porter  *
821eb188d0eSMatt Porter  * Used during enumeration to read the Host Device ID Lock CSR on a
822eb188d0eSMatt Porter  * RIO device. Returns the value of the lock register.
823eb188d0eSMatt Porter  */
824eb188d0eSMatt Porter static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount)
825eb188d0eSMatt Porter {
826eb188d0eSMatt Porter 	u32 result;
827eb188d0eSMatt Porter 
828e0423236SZhang Wei 	rio_mport_read_config_32(port, RIO_ANY_DESTID(port->sys_size), hopcount,
829eb188d0eSMatt Porter 				 RIO_HOST_DID_LOCK_CSR, &result);
830eb188d0eSMatt Porter 
831eb188d0eSMatt Porter 	return (u16) (result & 0xffff);
832eb188d0eSMatt Porter }
833eb188d0eSMatt Porter 
834eb188d0eSMatt Porter /**
835eb188d0eSMatt Porter  * rio_enum_peer- Recursively enumerate a RIO network through a master port
836eb188d0eSMatt Porter  * @net: RIO network being enumerated
837eb188d0eSMatt Porter  * @port: Master port to send transactions
838eb188d0eSMatt Porter  * @hopcount: Number of hops into the network
83968fe4df5SAlexandre Bounine  * @prev: Previous RIO device connected to the enumerated one
84068fe4df5SAlexandre Bounine  * @prev_port: Port on previous RIO device
841eb188d0eSMatt Porter  *
842eb188d0eSMatt Porter  * Recursively enumerates a RIO network.  Transactions are sent via the
843eb188d0eSMatt Porter  * master port passed in @port.
844eb188d0eSMatt Porter  */
845181a6ff0SLi Yang static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
84668fe4df5SAlexandre Bounine 			 u8 hopcount, struct rio_dev *prev, int prev_port)
847eb188d0eSMatt Porter {
848eb188d0eSMatt Porter 	struct rio_dev *rdev;
849af84ca38SAlexandre Bounine 	u32 regval;
850eb188d0eSMatt Porter 	int tmp;
851eb188d0eSMatt Porter 
852e274e0edSAlexandre Bounine 	if (rio_mport_chk_dev_access(port,
853e274e0edSAlexandre Bounine 			RIO_ANY_DESTID(port->sys_size), hopcount)) {
854e274e0edSAlexandre Bounine 		pr_debug("RIO: device access check failed\n");
855e274e0edSAlexandre Bounine 		return -1;
856e274e0edSAlexandre Bounine 	}
857e274e0edSAlexandre Bounine 
858eb188d0eSMatt Porter 	if (rio_get_host_deviceid_lock(port, hopcount) == port->host_deviceid) {
859eb188d0eSMatt Porter 		pr_debug("RIO: PE already discovered by this host\n");
860eb188d0eSMatt Porter 		/*
861eb188d0eSMatt Porter 		 * Already discovered by this host. Add it as another
862af84ca38SAlexandre Bounine 		 * link to the existing device.
863eb188d0eSMatt Porter 		 */
864af84ca38SAlexandre Bounine 		rio_mport_read_config_32(port, RIO_ANY_DESTID(port->sys_size),
865af84ca38SAlexandre Bounine 				hopcount, RIO_COMPONENT_TAG_CSR, &regval);
866af84ca38SAlexandre Bounine 
867af84ca38SAlexandre Bounine 		if (regval) {
868af84ca38SAlexandre Bounine 			rdev = rio_get_comptag((regval & 0xffff), NULL);
869af84ca38SAlexandre Bounine 
870af84ca38SAlexandre Bounine 			if (rdev && prev && rio_is_switch(prev)) {
871af84ca38SAlexandre Bounine 				pr_debug("RIO: redundant path to %s\n",
872af84ca38SAlexandre Bounine 					 rio_name(rdev));
873af84ca38SAlexandre Bounine 				prev->rswitch->nextdev[prev_port] = rdev;
874af84ca38SAlexandre Bounine 			}
875af84ca38SAlexandre Bounine 		}
876af84ca38SAlexandre Bounine 
877eb188d0eSMatt Porter 		return 0;
878eb188d0eSMatt Porter 	}
879eb188d0eSMatt Porter 
880eb188d0eSMatt Porter 	/* Attempt to acquire device lock */
881e0423236SZhang Wei 	rio_mport_write_config_32(port, RIO_ANY_DESTID(port->sys_size),
882e0423236SZhang Wei 				  hopcount,
883eb188d0eSMatt Porter 				  RIO_HOST_DID_LOCK_CSR, port->host_deviceid);
884eb188d0eSMatt Porter 	while ((tmp = rio_get_host_deviceid_lock(port, hopcount))
885eb188d0eSMatt Porter 	       < port->host_deviceid) {
886eb188d0eSMatt Porter 		/* Delay a bit */
887eb188d0eSMatt Porter 		mdelay(1);
888eb188d0eSMatt Porter 		/* Attempt to acquire device lock again */
889e0423236SZhang Wei 		rio_mport_write_config_32(port, RIO_ANY_DESTID(port->sys_size),
890e0423236SZhang Wei 					  hopcount,
891eb188d0eSMatt Porter 					  RIO_HOST_DID_LOCK_CSR,
892eb188d0eSMatt Porter 					  port->host_deviceid);
893eb188d0eSMatt Porter 	}
894eb188d0eSMatt Porter 
895eb188d0eSMatt Porter 	if (rio_get_host_deviceid_lock(port, hopcount) > port->host_deviceid) {
896eb188d0eSMatt Porter 		pr_debug(
897eb188d0eSMatt Porter 		    "RIO: PE locked by a higher priority host...retreating\n");
898eb188d0eSMatt Porter 		return -1;
899eb188d0eSMatt Porter 	}
900eb188d0eSMatt Porter 
901eb188d0eSMatt Porter 	/* Setup new RIO device */
902e0423236SZhang Wei 	rdev = rio_setup_device(net, port, RIO_ANY_DESTID(port->sys_size),
903e0423236SZhang Wei 					hopcount, 1);
904e0423236SZhang Wei 	if (rdev) {
905eb188d0eSMatt Porter 		/* Add device to the global and bus/net specific list. */
906eb188d0eSMatt Porter 		list_add_tail(&rdev->net_list, &net->devices);
90768fe4df5SAlexandre Bounine 		rdev->prev = prev;
90868fe4df5SAlexandre Bounine 		if (prev && rio_is_switch(prev))
90968fe4df5SAlexandre Bounine 			prev->rswitch->nextdev[prev_port] = rdev;
910eb188d0eSMatt Porter 	} else
911eb188d0eSMatt Porter 		return -1;
912eb188d0eSMatt Porter 
913eb188d0eSMatt Porter 	if (rio_is_switch(rdev)) {
914de74e00aSAlexandre Bounine 		int sw_destid;
915de74e00aSAlexandre Bounine 		int cur_destid;
916de74e00aSAlexandre Bounine 		int sw_inport;
917de74e00aSAlexandre Bounine 		u16 destid;
918de74e00aSAlexandre Bounine 		int port_num;
919de74e00aSAlexandre Bounine 
920ae05cbd5SAlexandre Bounine 		sw_inport = RIO_GET_PORT_NUM(rdev->swpinfo);
921a93192a5SAlexandre Bounine 		rio_route_add_entry(rdev, RIO_GLOBAL_TABLE,
922818a04a0SAlexandre Bounine 				    port->host_deviceid, sw_inport, 0);
923c70555b0SAlexandre Bounine 		rdev->rswitch->route_table[port->host_deviceid] = sw_inport;
924eb188d0eSMatt Porter 
925de74e00aSAlexandre Bounine 		destid = rio_destid_first(net);
926de74e00aSAlexandre Bounine 		while (destid != RIO_INVALID_DESTID && destid < next_destid) {
927de74e00aSAlexandre Bounine 			if (destid != port->host_deviceid) {
928a93192a5SAlexandre Bounine 				rio_route_add_entry(rdev, RIO_GLOBAL_TABLE,
929818a04a0SAlexandre Bounine 						    destid, sw_inport, 0);
930c70555b0SAlexandre Bounine 				rdev->rswitch->route_table[destid] = sw_inport;
931eb188d0eSMatt Porter 			}
932de74e00aSAlexandre Bounine 			destid = rio_destid_next(net, destid + 1);
933de74e00aSAlexandre Bounine 		}
934eb188d0eSMatt Porter 		pr_debug(
935eb188d0eSMatt Porter 		    "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n",
93668fe4df5SAlexandre Bounine 		    rio_name(rdev), rdev->vid, rdev->did,
93768fe4df5SAlexandre Bounine 		    RIO_GET_TOTAL_PORTS(rdev->swpinfo));
938c70555b0SAlexandre Bounine 		sw_destid = next_destid;
93968fe4df5SAlexandre Bounine 		for (port_num = 0;
94068fe4df5SAlexandre Bounine 		     port_num < RIO_GET_TOTAL_PORTS(rdev->swpinfo);
94168fe4df5SAlexandre Bounine 		     port_num++) {
9428d4630dcSAlexandre Bounine 			if (sw_inport == port_num) {
943933af4a6SThomas Moll 				rio_enable_rx_tx_port(port, 0,
944933af4a6SThomas Moll 					      RIO_ANY_DESTID(port->sys_size),
945933af4a6SThomas Moll 					      hopcount, port_num);
946e5cabeb3SAlexandre Bounine 				rdev->rswitch->port_ok |= (1 << port_num);
947eb188d0eSMatt Porter 				continue;
948e5cabeb3SAlexandre Bounine 			}
949eb188d0eSMatt Porter 
950eb188d0eSMatt Porter 			cur_destid = next_destid;
951eb188d0eSMatt Porter 
952eb188d0eSMatt Porter 			if (rio_sport_is_active
953e0423236SZhang Wei 			    (port, RIO_ANY_DESTID(port->sys_size), hopcount,
954e0423236SZhang Wei 			     port_num)) {
955eb188d0eSMatt Porter 				pr_debug(
956eb188d0eSMatt Porter 				    "RIO: scanning device on port %d\n",
957eb188d0eSMatt Porter 				    port_num);
9588d4630dcSAlexandre Bounine 				rio_enable_rx_tx_port(port, 0,
9598d4630dcSAlexandre Bounine 					      RIO_ANY_DESTID(port->sys_size),
9608d4630dcSAlexandre Bounine 					      hopcount, port_num);
961e5cabeb3SAlexandre Bounine 				rdev->rswitch->port_ok |= (1 << port_num);
962a93192a5SAlexandre Bounine 				rio_route_add_entry(rdev, RIO_GLOBAL_TABLE,
963e0423236SZhang Wei 						RIO_ANY_DESTID(port->sys_size),
964818a04a0SAlexandre Bounine 						port_num, 0);
965eb188d0eSMatt Porter 
96668fe4df5SAlexandre Bounine 				if (rio_enum_peer(net, port, hopcount + 1,
96768fe4df5SAlexandre Bounine 						  rdev, port_num) < 0)
968eb188d0eSMatt Porter 					return -1;
969eb188d0eSMatt Porter 
970eb188d0eSMatt Porter 				/* Update routing tables */
971de74e00aSAlexandre Bounine 				destid = rio_destid_next(net, cur_destid + 1);
972de74e00aSAlexandre Bounine 				if (destid != RIO_INVALID_DESTID) {
973eb188d0eSMatt Porter 					for (destid = cur_destid;
974de74e00aSAlexandre Bounine 					     destid < next_destid;) {
975de74e00aSAlexandre Bounine 						if (destid != port->host_deviceid) {
976a93192a5SAlexandre Bounine 							rio_route_add_entry(rdev,
977eb188d0eSMatt Porter 								    RIO_GLOBAL_TABLE,
978eb188d0eSMatt Porter 								    destid,
979818a04a0SAlexandre Bounine 								    port_num,
980818a04a0SAlexandre Bounine 								    0);
981eb188d0eSMatt Porter 							rdev->rswitch->
982eb188d0eSMatt Porter 								route_table[destid] =
983eb188d0eSMatt Porter 								port_num;
984eb188d0eSMatt Porter 						}
985de74e00aSAlexandre Bounine 						destid = rio_destid_next(net,
986de74e00aSAlexandre Bounine 								destid + 1);
987de74e00aSAlexandre Bounine 					}
988eb188d0eSMatt Porter 				}
989e5cabeb3SAlexandre Bounine 			} else {
990e5cabeb3SAlexandre Bounine 				/* If switch supports Error Management,
991e5cabeb3SAlexandre Bounine 				 * set PORT_LOCKOUT bit for unused port
992e5cabeb3SAlexandre Bounine 				 */
993e5cabeb3SAlexandre Bounine 				if (rdev->em_efptr)
994e5cabeb3SAlexandre Bounine 					rio_set_port_lockout(rdev, port_num, 1);
995e5cabeb3SAlexandre Bounine 
996e5cabeb3SAlexandre Bounine 				rdev->rswitch->port_ok &= ~(1 << port_num);
997eb188d0eSMatt Porter 			}
998eb188d0eSMatt Porter 		}
999c70555b0SAlexandre Bounine 
1000e5cabeb3SAlexandre Bounine 		/* Direct Port-write messages to the enumeratiing host */
1001e5cabeb3SAlexandre Bounine 		if ((rdev->src_ops & RIO_SRC_OPS_PORT_WRITE) &&
1002e5cabeb3SAlexandre Bounine 		    (rdev->em_efptr)) {
1003e5cabeb3SAlexandre Bounine 			rio_write_config_32(rdev,
1004e5cabeb3SAlexandre Bounine 					rdev->em_efptr + RIO_EM_PW_TGT_DEVID,
1005e5cabeb3SAlexandre Bounine 					(port->host_deviceid << 16) |
1006e5cabeb3SAlexandre Bounine 					(port->sys_size << 15));
1007e5cabeb3SAlexandre Bounine 		}
1008e5cabeb3SAlexandre Bounine 
1009e5cabeb3SAlexandre Bounine 		rio_init_em(rdev);
1010e5cabeb3SAlexandre Bounine 
1011c70555b0SAlexandre Bounine 		/* Check for empty switch */
1012de74e00aSAlexandre Bounine 		if (next_destid == sw_destid)
1013de74e00aSAlexandre Bounine 			next_destid = rio_destid_alloc(net);
1014c70555b0SAlexandre Bounine 
1015a93192a5SAlexandre Bounine 		rdev->destid = sw_destid;
1016eb188d0eSMatt Porter 	} else
1017eb188d0eSMatt Porter 		pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n",
1018eb188d0eSMatt Porter 		    rio_name(rdev), rdev->vid, rdev->did);
1019eb188d0eSMatt Porter 
1020eb188d0eSMatt Porter 	return 0;
1021eb188d0eSMatt Porter }
1022eb188d0eSMatt Porter 
1023eb188d0eSMatt Porter /**
1024eb188d0eSMatt Porter  * rio_enum_complete- Tests if enumeration of a network is complete
1025eb188d0eSMatt Porter  * @port: Master port to send transaction
1026eb188d0eSMatt Porter  *
1027a571259fSLiu Gang  * Tests the PGCCSR discovered bit for non-zero value (enumeration
1028e5cabeb3SAlexandre Bounine  * complete flag). Return %1 if enumeration is complete or %0 if
1029eb188d0eSMatt Porter  * enumeration is incomplete.
1030eb188d0eSMatt Porter  */
1031eb188d0eSMatt Porter static int rio_enum_complete(struct rio_mport *port)
1032eb188d0eSMatt Porter {
1033af84ca38SAlexandre Bounine 	u32 regval;
1034eb188d0eSMatt Porter 
1035af84ca38SAlexandre Bounine 	rio_local_read_config_32(port, port->phys_efptr + RIO_PORT_GEN_CTL_CSR,
1036af84ca38SAlexandre Bounine 				 &regval);
1037a571259fSLiu Gang 	return (regval & RIO_PORT_GEN_DISCOVERED) ? 1 : 0;
1038eb188d0eSMatt Porter }
1039eb188d0eSMatt Porter 
1040eb188d0eSMatt Porter /**
1041eb188d0eSMatt Porter  * rio_disc_peer- Recursively discovers a RIO network through a master port
1042eb188d0eSMatt Porter  * @net: RIO network being discovered
1043eb188d0eSMatt Porter  * @port: Master port to send transactions
1044eb188d0eSMatt Porter  * @destid: Current destination ID in network
1045eb188d0eSMatt Porter  * @hopcount: Number of hops into the network
10469b310accSRandy Dunlap  * @prev: previous rio_dev
10479b310accSRandy Dunlap  * @prev_port: previous port number
1048eb188d0eSMatt Porter  *
1049eb188d0eSMatt Porter  * Recursively discovers a RIO network.  Transactions are sent via the
1050eb188d0eSMatt Porter  * master port passed in @port.
1051eb188d0eSMatt Porter  */
1052181a6ff0SLi Yang static int __devinit
1053eb188d0eSMatt Porter rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
105417e96205SAlexandre Bounine 	      u8 hopcount, struct rio_dev *prev, int prev_port)
1055eb188d0eSMatt Porter {
1056eb188d0eSMatt Porter 	u8 port_num, route_port;
1057eb188d0eSMatt Porter 	struct rio_dev *rdev;
1058eb188d0eSMatt Porter 	u16 ndestid;
1059eb188d0eSMatt Porter 
1060eb188d0eSMatt Porter 	/* Setup new RIO device */
1061eb188d0eSMatt Porter 	if ((rdev = rio_setup_device(net, port, destid, hopcount, 0))) {
1062eb188d0eSMatt Porter 		/* Add device to the global and bus/net specific list. */
1063eb188d0eSMatt Porter 		list_add_tail(&rdev->net_list, &net->devices);
106417e96205SAlexandre Bounine 		rdev->prev = prev;
106517e96205SAlexandre Bounine 		if (prev && rio_is_switch(prev))
106617e96205SAlexandre Bounine 			prev->rswitch->nextdev[prev_port] = rdev;
1067eb188d0eSMatt Porter 	} else
1068eb188d0eSMatt Porter 		return -1;
1069eb188d0eSMatt Porter 
1070eb188d0eSMatt Porter 	if (rio_is_switch(rdev)) {
1071eb188d0eSMatt Porter 		/* Associated destid is how we accessed this switch */
1072a93192a5SAlexandre Bounine 		rdev->destid = destid;
1073eb188d0eSMatt Porter 
1074eb188d0eSMatt Porter 		pr_debug(
1075eb188d0eSMatt Porter 		    "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n",
107668fe4df5SAlexandre Bounine 		    rio_name(rdev), rdev->vid, rdev->did,
107768fe4df5SAlexandre Bounine 		    RIO_GET_TOTAL_PORTS(rdev->swpinfo));
107868fe4df5SAlexandre Bounine 		for (port_num = 0;
107968fe4df5SAlexandre Bounine 		     port_num < RIO_GET_TOTAL_PORTS(rdev->swpinfo);
108068fe4df5SAlexandre Bounine 		     port_num++) {
1081ae05cbd5SAlexandre Bounine 			if (RIO_GET_PORT_NUM(rdev->swpinfo) == port_num)
1082eb188d0eSMatt Porter 				continue;
1083eb188d0eSMatt Porter 
1084eb188d0eSMatt Porter 			if (rio_sport_is_active
1085eb188d0eSMatt Porter 			    (port, destid, hopcount, port_num)) {
1086eb188d0eSMatt Porter 				pr_debug(
1087eb188d0eSMatt Porter 				    "RIO: scanning device on port %d\n",
1088eb188d0eSMatt Porter 				    port_num);
1089818a04a0SAlexandre Bounine 
1090818a04a0SAlexandre Bounine 				rio_lock_device(port, destid, hopcount, 1000);
1091818a04a0SAlexandre Bounine 
1092e0423236SZhang Wei 				for (ndestid = 0;
1093e0423236SZhang Wei 				     ndestid < RIO_ANY_DESTID(port->sys_size);
1094eb188d0eSMatt Porter 				     ndestid++) {
1095a93192a5SAlexandre Bounine 					rio_route_get_entry(rdev,
1096eb188d0eSMatt Porter 							    RIO_GLOBAL_TABLE,
1097eb188d0eSMatt Porter 							    ndestid,
1098818a04a0SAlexandre Bounine 							    &route_port, 0);
1099eb188d0eSMatt Porter 					if (route_port == port_num)
1100eb188d0eSMatt Porter 						break;
1101eb188d0eSMatt Porter 				}
1102eb188d0eSMatt Porter 
1103af84ca38SAlexandre Bounine 				if (ndestid == RIO_ANY_DESTID(port->sys_size))
1104af84ca38SAlexandre Bounine 					continue;
1105818a04a0SAlexandre Bounine 				rio_unlock_device(port, destid, hopcount);
110617e96205SAlexandre Bounine 				if (rio_disc_peer(net, port, ndestid,
110717e96205SAlexandre Bounine 					hopcount + 1, rdev, port_num) < 0)
1108eb188d0eSMatt Porter 					return -1;
1109eb188d0eSMatt Porter 			}
1110eb188d0eSMatt Porter 		}
1111eb188d0eSMatt Porter 	} else
1112eb188d0eSMatt Porter 		pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n",
1113eb188d0eSMatt Porter 		    rio_name(rdev), rdev->vid, rdev->did);
1114eb188d0eSMatt Porter 
1115eb188d0eSMatt Porter 	return 0;
1116eb188d0eSMatt Porter }
1117eb188d0eSMatt Porter 
1118eb188d0eSMatt Porter /**
1119eb188d0eSMatt Porter  * rio_mport_is_active- Tests if master port link is active
1120eb188d0eSMatt Porter  * @port: Master port to test
1121eb188d0eSMatt Porter  *
1122eb188d0eSMatt Porter  * Reads the port error status CSR for the master port to
1123eb188d0eSMatt Porter  * determine if the port has an active link.  Returns
1124e5cabeb3SAlexandre Bounine  * %RIO_PORT_N_ERR_STS_PORT_OK if the  master port is active
1125eb188d0eSMatt Porter  * or %0 if it is inactive.
1126eb188d0eSMatt Porter  */
1127eb188d0eSMatt Porter static int rio_mport_is_active(struct rio_mport *port)
1128eb188d0eSMatt Porter {
1129eb188d0eSMatt Porter 	u32 result = 0;
1130eb188d0eSMatt Porter 	u32 ext_ftr_ptr;
1131eb188d0eSMatt Porter 	int *entry = rio_mport_phys_table;
1132eb188d0eSMatt Porter 
1133eb188d0eSMatt Porter 	do {
1134eb188d0eSMatt Porter 		if ((ext_ftr_ptr =
1135eb188d0eSMatt Porter 		     rio_mport_get_feature(port, 1, 0, 0, *entry)))
1136eb188d0eSMatt Porter 			break;
1137eb188d0eSMatt Porter 	} while (*++entry >= 0);
1138eb188d0eSMatt Porter 
1139eb188d0eSMatt Porter 	if (ext_ftr_ptr)
1140eb188d0eSMatt Porter 		rio_local_read_config_32(port,
1141eb188d0eSMatt Porter 					 ext_ftr_ptr +
1142eb188d0eSMatt Porter 					 RIO_PORT_N_ERR_STS_CSR(port->index),
1143eb188d0eSMatt Porter 					 &result);
1144eb188d0eSMatt Porter 
1145e5cabeb3SAlexandre Bounine 	return result & RIO_PORT_N_ERR_STS_PORT_OK;
1146eb188d0eSMatt Porter }
1147eb188d0eSMatt Porter 
1148eb188d0eSMatt Porter /**
1149eb188d0eSMatt Porter  * rio_alloc_net- Allocate and configure a new RIO network
1150eb188d0eSMatt Porter  * @port: Master port associated with the RIO network
1151de74e00aSAlexandre Bounine  * @do_enum: Enumeration/Discovery mode flag
1152de74e00aSAlexandre Bounine  * @start: logical minimal start id for new net
1153eb188d0eSMatt Porter  *
1154eb188d0eSMatt Porter  * Allocates a RIO network structure, initializes per-network
1155eb188d0eSMatt Porter  * list heads, and adds the associated master port to the
1156eb188d0eSMatt Porter  * network list of associated master ports. Returns a
1157eb188d0eSMatt Porter  * RIO network pointer on success or %NULL on failure.
1158eb188d0eSMatt Porter  */
1159de74e00aSAlexandre Bounine static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port,
1160de74e00aSAlexandre Bounine 					       int do_enum, u16 start)
1161eb188d0eSMatt Porter {
1162eb188d0eSMatt Porter 	struct rio_net *net;
1163eb188d0eSMatt Porter 
1164dd00cc48SYoann Padioleau 	net = kzalloc(sizeof(struct rio_net), GFP_KERNEL);
1165de74e00aSAlexandre Bounine 	if (net && do_enum) {
1166de74e00aSAlexandre Bounine 		net->destid_table.table = kzalloc(
1167de74e00aSAlexandre Bounine 			BITS_TO_LONGS(RIO_MAX_ROUTE_ENTRIES(port->sys_size)) *
1168de74e00aSAlexandre Bounine 			sizeof(long),
1169de74e00aSAlexandre Bounine 			GFP_KERNEL);
1170de74e00aSAlexandre Bounine 
1171de74e00aSAlexandre Bounine 		if (net->destid_table.table == NULL) {
1172de74e00aSAlexandre Bounine 			pr_err("RIO: failed to allocate destID table\n");
1173de74e00aSAlexandre Bounine 			kfree(net);
1174de74e00aSAlexandre Bounine 			net = NULL;
1175de74e00aSAlexandre Bounine 		} else {
1176de74e00aSAlexandre Bounine 			net->destid_table.start = start;
1177de74e00aSAlexandre Bounine 			net->destid_table.next = 0;
1178de74e00aSAlexandre Bounine 			net->destid_table.max =
1179de74e00aSAlexandre Bounine 					RIO_MAX_ROUTE_ENTRIES(port->sys_size);
1180de74e00aSAlexandre Bounine 			spin_lock_init(&net->destid_table.lock);
1181de74e00aSAlexandre Bounine 		}
1182de74e00aSAlexandre Bounine 	}
1183de74e00aSAlexandre Bounine 
1184eb188d0eSMatt Porter 	if (net) {
1185eb188d0eSMatt Porter 		INIT_LIST_HEAD(&net->node);
1186eb188d0eSMatt Porter 		INIT_LIST_HEAD(&net->devices);
1187a7071efcSAlexandre Bounine 		INIT_LIST_HEAD(&net->switches);
1188eb188d0eSMatt Porter 		INIT_LIST_HEAD(&net->mports);
1189eb188d0eSMatt Porter 		list_add_tail(&port->nnode, &net->mports);
1190eb188d0eSMatt Porter 		net->hport = port;
1191005842efSAlexandre Bounine 		net->id = port->id;
1192eb188d0eSMatt Porter 	}
1193eb188d0eSMatt Porter 	return net;
1194eb188d0eSMatt Porter }
1195eb188d0eSMatt Porter 
1196eb188d0eSMatt Porter /**
1197c70555b0SAlexandre Bounine  * rio_update_route_tables- Updates route tables in switches
1198a7071efcSAlexandre Bounine  * @net: RIO network to run update on
1199c70555b0SAlexandre Bounine  *
1200c70555b0SAlexandre Bounine  * For each enumerated device, ensure that each switch in a system
1201c70555b0SAlexandre Bounine  * has correct routing entries. Add routes for devices that where
1202c70555b0SAlexandre Bounine  * unknown dirung the first enumeration pass through the switch.
1203c70555b0SAlexandre Bounine  */
1204a7071efcSAlexandre Bounine static void rio_update_route_tables(struct rio_net *net)
1205c70555b0SAlexandre Bounine {
1206ded05782SAlexandre Bounine 	struct rio_dev *rdev, *swrdev;
1207c70555b0SAlexandre Bounine 	struct rio_switch *rswitch;
1208c70555b0SAlexandre Bounine 	u8 sport;
1209c70555b0SAlexandre Bounine 	u16 destid;
1210c70555b0SAlexandre Bounine 
1211a7071efcSAlexandre Bounine 	list_for_each_entry(rdev, &net->devices, net_list) {
1212c70555b0SAlexandre Bounine 
1213a93192a5SAlexandre Bounine 		destid = rdev->destid;
1214c70555b0SAlexandre Bounine 
1215a7071efcSAlexandre Bounine 		list_for_each_entry(rswitch, &net->switches, node) {
1216c70555b0SAlexandre Bounine 
1217c70555b0SAlexandre Bounine 			if (rio_is_switch(rdev)	&& (rdev->rswitch == rswitch))
1218c70555b0SAlexandre Bounine 				continue;
1219c70555b0SAlexandre Bounine 
1220c70555b0SAlexandre Bounine 			if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) {
1221ded05782SAlexandre Bounine 				swrdev = sw_to_rio_dev(rswitch);
1222ded05782SAlexandre Bounine 
122307590ff0SAlexandre Bounine 				/* Skip if destid ends in empty switch*/
1224ded05782SAlexandre Bounine 				if (swrdev->destid == destid)
122507590ff0SAlexandre Bounine 					continue;
1226c70555b0SAlexandre Bounine 
1227ded05782SAlexandre Bounine 				sport = RIO_GET_PORT_NUM(swrdev->swpinfo);
1228c70555b0SAlexandre Bounine 
1229c70555b0SAlexandre Bounine 				if (rswitch->add_entry)	{
1230ded05782SAlexandre Bounine 					rio_route_add_entry(swrdev,
1231818a04a0SAlexandre Bounine 						RIO_GLOBAL_TABLE, destid,
1232818a04a0SAlexandre Bounine 						sport, 0);
1233c70555b0SAlexandre Bounine 					rswitch->route_table[destid] = sport;
1234c70555b0SAlexandre Bounine 				}
1235c70555b0SAlexandre Bounine 			}
1236c70555b0SAlexandre Bounine 		}
1237c70555b0SAlexandre Bounine 	}
1238c70555b0SAlexandre Bounine }
1239c70555b0SAlexandre Bounine 
1240c70555b0SAlexandre Bounine /**
1241e5cabeb3SAlexandre Bounine  * rio_init_em - Initializes RIO Error Management (for switches)
124297ef6f74SRandy Dunlap  * @rdev: RIO device
1243e5cabeb3SAlexandre Bounine  *
1244e5cabeb3SAlexandre Bounine  * For each enumerated switch, call device-specific error management
1245e5cabeb3SAlexandre Bounine  * initialization routine (if supplied by the switch driver).
1246e5cabeb3SAlexandre Bounine  */
1247e5cabeb3SAlexandre Bounine static void rio_init_em(struct rio_dev *rdev)
1248e5cabeb3SAlexandre Bounine {
1249e5cabeb3SAlexandre Bounine 	if (rio_is_switch(rdev) && (rdev->em_efptr) &&
1250e5cabeb3SAlexandre Bounine 	    (rdev->rswitch->em_init)) {
1251e5cabeb3SAlexandre Bounine 		rdev->rswitch->em_init(rdev);
1252e5cabeb3SAlexandre Bounine 	}
1253e5cabeb3SAlexandre Bounine }
1254e5cabeb3SAlexandre Bounine 
1255e5cabeb3SAlexandre Bounine /**
1256e5cabeb3SAlexandre Bounine  * rio_pw_enable - Enables/disables port-write handling by a master port
1257e5cabeb3SAlexandre Bounine  * @port: Master port associated with port-write handling
1258e5cabeb3SAlexandre Bounine  * @enable:  1=enable,  0=disable
1259e5cabeb3SAlexandre Bounine  */
1260e5cabeb3SAlexandre Bounine static void rio_pw_enable(struct rio_mport *port, int enable)
1261e5cabeb3SAlexandre Bounine {
1262e5cabeb3SAlexandre Bounine 	if (port->ops->pwenable)
1263e5cabeb3SAlexandre Bounine 		port->ops->pwenable(port, enable);
1264e5cabeb3SAlexandre Bounine }
1265e5cabeb3SAlexandre Bounine 
1266e5cabeb3SAlexandre Bounine /**
1267eb188d0eSMatt Porter  * rio_enum_mport- Start enumeration through a master port
1268eb188d0eSMatt Porter  * @mport: Master port to send transactions
1269eb188d0eSMatt Porter  *
1270eb188d0eSMatt Porter  * Starts the enumeration process. If somebody has enumerated our
1271eb188d0eSMatt Porter  * master port device, then give up. If not and we have an active
1272eb188d0eSMatt Porter  * link, then start recursive peer enumeration. Returns %0 if
1273eb188d0eSMatt Porter  * enumeration succeeds or %-EBUSY if enumeration fails.
1274eb188d0eSMatt Porter  */
127537d33d15SAl Viro int __devinit rio_enum_mport(struct rio_mport *mport)
1276eb188d0eSMatt Porter {
1277eb188d0eSMatt Porter 	struct rio_net *net = NULL;
1278eb188d0eSMatt Porter 	int rc = 0;
1279eb188d0eSMatt Porter 
1280eb188d0eSMatt Porter 	printk(KERN_INFO "RIO: enumerate master port %d, %s\n", mport->id,
1281eb188d0eSMatt Porter 	       mport->name);
1282eb188d0eSMatt Porter 	/* If somebody else enumerated our master port device, bail. */
1283eb188d0eSMatt Porter 	if (rio_enum_host(mport) < 0) {
1284eb188d0eSMatt Porter 		printk(KERN_INFO
1285eb188d0eSMatt Porter 		       "RIO: master port %d device has been enumerated by a remote host\n",
1286eb188d0eSMatt Porter 		       mport->id);
1287eb188d0eSMatt Porter 		rc = -EBUSY;
1288eb188d0eSMatt Porter 		goto out;
1289eb188d0eSMatt Porter 	}
1290eb188d0eSMatt Porter 
1291eb188d0eSMatt Porter 	/* If master port has an active link, allocate net and enum peers */
1292eb188d0eSMatt Porter 	if (rio_mport_is_active(mport)) {
1293de74e00aSAlexandre Bounine 		net = rio_alloc_net(mport, 1, 0);
1294de74e00aSAlexandre Bounine 		if (!net) {
1295eb188d0eSMatt Porter 			printk(KERN_ERR "RIO: failed to allocate new net\n");
1296eb188d0eSMatt Porter 			rc = -ENOMEM;
1297eb188d0eSMatt Porter 			goto out;
1298eb188d0eSMatt Porter 		}
1299933af4a6SThomas Moll 
1300de74e00aSAlexandre Bounine 		/* reserve mport destID in new net */
1301de74e00aSAlexandre Bounine 		rio_destid_reserve(net, mport->host_deviceid);
1302de74e00aSAlexandre Bounine 
1303933af4a6SThomas Moll 		/* Enable Input Output Port (transmitter reviever) */
1304933af4a6SThomas Moll 		rio_enable_rx_tx_port(mport, 1, 0, 0, 0);
1305933af4a6SThomas Moll 
1306af84ca38SAlexandre Bounine 		/* Set component tag for host */
1307af84ca38SAlexandre Bounine 		rio_local_write_config_32(mport, RIO_COMPONENT_TAG_CSR,
1308af84ca38SAlexandre Bounine 					  next_comptag++);
1309af84ca38SAlexandre Bounine 
1310de74e00aSAlexandre Bounine 		next_destid = rio_destid_alloc(net);
1311de74e00aSAlexandre Bounine 
131268fe4df5SAlexandre Bounine 		if (rio_enum_peer(net, mport, 0, NULL, 0) < 0) {
1313eb188d0eSMatt Porter 			/* A higher priority host won enumeration, bail. */
1314eb188d0eSMatt Porter 			printk(KERN_INFO
1315eb188d0eSMatt Porter 			       "RIO: master port %d device has lost enumeration to a remote host\n",
1316eb188d0eSMatt Porter 			       mport->id);
1317a7071efcSAlexandre Bounine 			rio_clear_locks(net);
1318eb188d0eSMatt Porter 			rc = -EBUSY;
1319eb188d0eSMatt Porter 			goto out;
1320eb188d0eSMatt Porter 		}
1321de74e00aSAlexandre Bounine 		/* free the last allocated destID (unused) */
1322de74e00aSAlexandre Bounine 		rio_destid_free(net, next_destid);
1323a7071efcSAlexandre Bounine 		rio_update_route_tables(net);
1324a7071efcSAlexandre Bounine 		rio_clear_locks(net);
1325e5cabeb3SAlexandre Bounine 		rio_pw_enable(mport, 1);
1326eb188d0eSMatt Porter 	} else {
1327eb188d0eSMatt Porter 		printk(KERN_INFO "RIO: master port %d link inactive\n",
1328eb188d0eSMatt Porter 		       mport->id);
1329eb188d0eSMatt Porter 		rc = -EINVAL;
1330eb188d0eSMatt Porter 	}
1331eb188d0eSMatt Porter 
1332eb188d0eSMatt Porter       out:
1333eb188d0eSMatt Porter 	return rc;
1334eb188d0eSMatt Porter }
1335eb188d0eSMatt Porter 
1336eb188d0eSMatt Porter /**
1337eb188d0eSMatt Porter  * rio_build_route_tables- Generate route tables from switch route entries
1338a7071efcSAlexandre Bounine  * @net: RIO network to run route tables scan on
1339eb188d0eSMatt Porter  *
1340eb188d0eSMatt Porter  * For each switch device, generate a route table by copying existing
1341eb188d0eSMatt Porter  * route entries from the switch.
1342eb188d0eSMatt Porter  */
1343a7071efcSAlexandre Bounine static void rio_build_route_tables(struct rio_net *net)
1344eb188d0eSMatt Porter {
1345a7071efcSAlexandre Bounine 	struct rio_switch *rswitch;
1346eb188d0eSMatt Porter 	struct rio_dev *rdev;
1347eb188d0eSMatt Porter 	int i;
1348eb188d0eSMatt Porter 	u8 sport;
1349eb188d0eSMatt Porter 
1350a7071efcSAlexandre Bounine 	list_for_each_entry(rswitch, &net->switches, node) {
1351a7071efcSAlexandre Bounine 		rdev = sw_to_rio_dev(rswitch);
1352a7071efcSAlexandre Bounine 
1353a7071efcSAlexandre Bounine 		rio_lock_device(net->hport, rdev->destid,
1354a93192a5SAlexandre Bounine 				rdev->hopcount, 1000);
1355e0423236SZhang Wei 		for (i = 0;
1356a7071efcSAlexandre Bounine 		     i < RIO_MAX_ROUTE_ENTRIES(net->hport->sys_size);
1357e0423236SZhang Wei 		     i++) {
1358a7071efcSAlexandre Bounine 			if (rio_route_get_entry(rdev, RIO_GLOBAL_TABLE,
1359a7071efcSAlexandre Bounine 						i, &sport, 0) < 0)
1360eb188d0eSMatt Porter 				continue;
1361a7071efcSAlexandre Bounine 			rswitch->route_table[i] = sport;
1362eb188d0eSMatt Porter 		}
1363818a04a0SAlexandre Bounine 
1364a7071efcSAlexandre Bounine 		rio_unlock_device(net->hport, rdev->destid, rdev->hopcount);
1365818a04a0SAlexandre Bounine 	}
1366eb188d0eSMatt Porter }
1367eb188d0eSMatt Porter 
1368eb188d0eSMatt Porter /**
1369eb188d0eSMatt Porter  * rio_disc_mport- Start discovery through a master port
1370eb188d0eSMatt Porter  * @mport: Master port to send transactions
1371eb188d0eSMatt Porter  *
1372eb188d0eSMatt Porter  * Starts the discovery process. If we have an active link,
1373eb188d0eSMatt Porter  * then wait for the signal that enumeration is complete.
1374eb188d0eSMatt Porter  * When enumeration completion is signaled, start recursive
1375eb188d0eSMatt Porter  * peer discovery. Returns %0 if discovery succeeds or %-EBUSY
1376eb188d0eSMatt Porter  * on failure.
1377eb188d0eSMatt Porter  */
137837d33d15SAl Viro int __devinit rio_disc_mport(struct rio_mport *mport)
1379eb188d0eSMatt Porter {
1380eb188d0eSMatt Porter 	struct rio_net *net = NULL;
1381fa3dbaa0SAlexandre Bounine 	unsigned long to_end;
1382eb188d0eSMatt Porter 
1383eb188d0eSMatt Porter 	printk(KERN_INFO "RIO: discover master port %d, %s\n", mport->id,
1384eb188d0eSMatt Porter 	       mport->name);
1385eb188d0eSMatt Porter 
1386eb188d0eSMatt Porter 	/* If master port has an active link, allocate net and discover peers */
1387eb188d0eSMatt Porter 	if (rio_mport_is_active(mport)) {
1388fa3dbaa0SAlexandre Bounine 		pr_debug("RIO: wait for enumeration to complete...\n");
1389fa3dbaa0SAlexandre Bounine 
1390fa3dbaa0SAlexandre Bounine 		to_end = jiffies + CONFIG_RAPIDIO_DISC_TIMEOUT * HZ;
1391fa3dbaa0SAlexandre Bounine 		while (time_before(jiffies, to_end)) {
1392fa3dbaa0SAlexandre Bounine 			if (rio_enum_complete(mport))
1393fa3dbaa0SAlexandre Bounine 				goto enum_done;
1394f4c9c0e8SAlexandre Bounine 			msleep(10);
1395fa3dbaa0SAlexandre Bounine 		}
1396fa3dbaa0SAlexandre Bounine 
1397fa3dbaa0SAlexandre Bounine 		pr_debug("RIO: discovery timeout on mport %d %s\n",
1398fa3dbaa0SAlexandre Bounine 			 mport->id, mport->name);
1399fa3dbaa0SAlexandre Bounine 		goto bail;
1400fa3dbaa0SAlexandre Bounine enum_done:
1401fa3dbaa0SAlexandre Bounine 		pr_debug("RIO: ... enumeration done\n");
1402fa3dbaa0SAlexandre Bounine 
1403de74e00aSAlexandre Bounine 		net = rio_alloc_net(mport, 0, 0);
1404fa3dbaa0SAlexandre Bounine 		if (!net) {
1405eb188d0eSMatt Porter 			printk(KERN_ERR "RIO: Failed to allocate new net\n");
1406eb188d0eSMatt Porter 			goto bail;
1407eb188d0eSMatt Porter 		}
1408eb188d0eSMatt Porter 
1409818a04a0SAlexandre Bounine 		/* Read DestID assigned by enumerator */
1410818a04a0SAlexandre Bounine 		rio_local_read_config_32(mport, RIO_DID_CSR,
1411818a04a0SAlexandre Bounine 					 &mport->host_deviceid);
1412818a04a0SAlexandre Bounine 		mport->host_deviceid = RIO_GET_DID(mport->sys_size,
1413818a04a0SAlexandre Bounine 						   mport->host_deviceid);
1414818a04a0SAlexandre Bounine 
1415e0423236SZhang Wei 		if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size),
141617e96205SAlexandre Bounine 					0, NULL, 0) < 0) {
1417eb188d0eSMatt Porter 			printk(KERN_INFO
1418eb188d0eSMatt Porter 			       "RIO: master port %d device has failed discovery\n",
1419eb188d0eSMatt Porter 			       mport->id);
1420eb188d0eSMatt Porter 			goto bail;
1421eb188d0eSMatt Porter 		}
1422eb188d0eSMatt Porter 
1423a7071efcSAlexandre Bounine 		rio_build_route_tables(net);
1424eb188d0eSMatt Porter 	}
1425eb188d0eSMatt Porter 
1426eb188d0eSMatt Porter 	return 0;
1427eb188d0eSMatt Porter bail:
1428eb188d0eSMatt Porter 	return -EBUSY;
1429eb188d0eSMatt Porter }
1430