diff options
Diffstat (limited to 'drivers/rapidio/rio-scan.c')
| -rw-r--r-- | drivers/rapidio/rio-scan.c | 808 | 
1 files changed, 353 insertions, 455 deletions
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 1eb82c4c712..47a1b2ea76c 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -31,28 +31,17 @@  #include <linux/module.h>  #include <linux/spinlock.h>  #include <linux/timer.h> +#include <linux/sched.h>  #include <linux/jiffies.h>  #include <linux/slab.h>  #include "rio.h" -LIST_HEAD(rio_devices); -static LIST_HEAD(rio_switches); - -static void rio_enum_timeout(unsigned long); -  static void rio_init_em(struct rio_dev *rdev); -DEFINE_SPINLOCK(rio_global_list_lock); -  static int next_destid = 0; -static int next_switchid = 0; -static int next_net = 0;  static int next_comptag = 1; -static struct timer_list rio_enum_timer = -TIMER_INITIALIZER(rio_enum_timeout, 0, 0); -  static int rio_mport_phys_table[] = {  	RIO_EFB_PAR_EP_ID,  	RIO_EFB_PAR_EP_REC_ID, @@ -61,6 +50,109 @@ static int rio_mport_phys_table[] = {  	-1,  }; + +/** + * rio_destid_alloc - Allocate next available destID for given network + * @net: RIO network + * + * Returns next available device destination ID for the specified RIO network. + * Marks allocated ID as one in use. + * Returns RIO_INVALID_DESTID if new destID is not available. + */ +static u16 rio_destid_alloc(struct rio_net *net) +{ +	int destid; +	struct rio_id_table *idtab = &net->destid_table; + +	spin_lock(&idtab->lock); +	destid = find_first_zero_bit(idtab->table, idtab->max); + +	if (destid < idtab->max) { +		set_bit(destid, idtab->table); +		destid += idtab->start; +	} else +		destid = RIO_INVALID_DESTID; + +	spin_unlock(&idtab->lock); +	return (u16)destid; +} + +/** + * rio_destid_reserve - Reserve the specivied destID + * @net: RIO network + * @destid: destID to reserve + * + * Tries to reserve the specified destID. + * Returns 0 if successfull. + */ +static int rio_destid_reserve(struct rio_net *net, u16 destid) +{ +	int oldbit; +	struct rio_id_table *idtab = &net->destid_table; + +	destid -= idtab->start; +	spin_lock(&idtab->lock); +	oldbit = test_and_set_bit(destid, idtab->table); +	spin_unlock(&idtab->lock); +	return oldbit; +} + +/** + * rio_destid_free - free a previously allocated destID + * @net: RIO network + * @destid: destID to free + * + * Makes the specified destID available for use. + */ +static void rio_destid_free(struct rio_net *net, u16 destid) +{ +	struct rio_id_table *idtab = &net->destid_table; + +	destid -= idtab->start; +	spin_lock(&idtab->lock); +	clear_bit(destid, idtab->table); +	spin_unlock(&idtab->lock); +} + +/** + * rio_destid_first - return first destID in use + * @net: RIO network + */ +static u16 rio_destid_first(struct rio_net *net) +{ +	int destid; +	struct rio_id_table *idtab = &net->destid_table; + +	spin_lock(&idtab->lock); +	destid = find_first_bit(idtab->table, idtab->max); +	if (destid >= idtab->max) +		destid = RIO_INVALID_DESTID; +	else +		destid += idtab->start; +	spin_unlock(&idtab->lock); +	return (u16)destid; +} + +/** + * rio_destid_next - return next destID in use + * @net: RIO network + * @from: destination ID from which search shall continue + */ +static u16 rio_destid_next(struct rio_net *net, u16 from) +{ +	int destid; +	struct rio_id_table *idtab = &net->destid_table; + +	spin_lock(&idtab->lock); +	destid = find_next_bit(idtab->table, idtab->max, from); +	if (destid >= idtab->max) +		destid = RIO_INVALID_DESTID; +	else +		destid += idtab->start; +	spin_unlock(&idtab->lock); +	return (u16)destid; +} +  /**   * rio_get_device_id - Get the base/extended device id for a device   * @port: RIO master port @@ -109,14 +201,15 @@ static void rio_local_set_device_id(struct rio_mport *port, u16 did)  /**   * rio_clear_locks- Release all host locks and signal enumeration complete - * @port: Master port to issue transaction + * @net: RIO network to run on   *   * Marks the component tag CSR on each device with the enumeration   * complete flag. When complete, it then release the host locks on   * each device. Returns 0 on success or %-EINVAL on failure.   */ -static int rio_clear_locks(struct rio_mport *port) +static int rio_clear_locks(struct rio_net *net)  { +	struct rio_mport *port = net->hport;  	struct rio_dev *rdev;  	u32 result;  	int ret = 0; @@ -131,7 +224,7 @@ static int rio_clear_locks(struct rio_mport *port)  		       result);  		ret = -EINVAL;  	} -	list_for_each_entry(rdev, &rio_devices, global_list) { +	list_for_each_entry(rdev, &net->devices, net_list) {  		rio_write_config_32(rdev, RIO_HOST_DID_LOCK_CSR,  				    port->host_deviceid);  		rio_read_config_32(rdev, RIO_HOST_DID_LOCK_CSR, &result); @@ -177,10 +270,6 @@ static int rio_enum_host(struct rio_mport *port)  	/* Set master port destid and init destid ctr */  	rio_local_set_device_id(port, port->host_deviceid); - -	if (next_destid == port->host_deviceid) -		next_destid++; -  	return 0;  } @@ -234,127 +323,6 @@ static int rio_is_switch(struct rio_dev *rdev)  }  /** - * rio_switch_init - Sets switch operations for a particular vendor switch - * @rdev: RIO device - * @do_enum: Enumeration/Discovery mode flag - * - * Searches the RIO switch ops table for known switch types. If the vid - * and did match a switch table entry, then call switch initialization - * routine to setup switch-specific routines. - */ -static void rio_switch_init(struct rio_dev *rdev, int do_enum) -{ -	struct rio_switch_ops *cur = __start_rio_switch_ops; -	struct rio_switch_ops *end = __end_rio_switch_ops; - -	while (cur < end) { -		if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) { -			pr_debug("RIO: calling init routine for %s\n", -				 rio_name(rdev)); -			cur->init_hook(rdev, do_enum); -			break; -		} -		cur++; -	} - -	if ((cur >= end) && (rdev->pef & RIO_PEF_STD_RT)) { -		pr_debug("RIO: adding STD routing ops for %s\n", -			rio_name(rdev)); -		rdev->rswitch->add_entry = rio_std_route_add_entry; -		rdev->rswitch->get_entry = rio_std_route_get_entry; -		rdev->rswitch->clr_table = rio_std_route_clr_table; -	} - -	if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry) -		printk(KERN_ERR "RIO: missing routing ops for %s\n", -		       rio_name(rdev)); -} - -/** - * rio_add_device- Adds a RIO device to the device model - * @rdev: RIO device - * - * Adds the RIO device to the global device list and adds the RIO - * device to the RIO device list.  Creates the generic sysfs nodes - * for an RIO device. - */ -static int __devinit rio_add_device(struct rio_dev *rdev) -{ -	int err; - -	err = device_add(&rdev->dev); -	if (err) -		return err; - -	spin_lock(&rio_global_list_lock); -	list_add_tail(&rdev->global_list, &rio_devices); -	spin_unlock(&rio_global_list_lock); - -	rio_create_sysfs_dev_files(rdev); - -	return 0; -} - -/** - * rio_enable_rx_tx_port - enable input reciever and output transmitter of - * given port - * @port: Master port associated with the RIO network - * @local: local=1 select local port otherwise a far device is reached - * @destid: Destination ID of the device to check host bit - * @hopcount: Number of hops to reach the target - * @port_num: Port (-number on switch) to enable on a far end device - * - * Returns 0 or 1 from on General Control Command and Status Register - * (EXT_PTR+0x3C) - */ -inline int rio_enable_rx_tx_port(struct rio_mport *port, -				 int local, u16 destid, -				 u8 hopcount, u8 port_num) { -#ifdef CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS -	u32 regval; -	u32 ext_ftr_ptr; - -	/* -	* enable rx input tx output port -	*/ -	pr_debug("rio_enable_rx_tx_port(local = %d, destid = %d, hopcount = " -		 "%d, port_num = %d)\n", local, destid, hopcount, port_num); - -	ext_ftr_ptr = rio_mport_get_physefb(port, local, destid, hopcount); - -	if (local) { -		rio_local_read_config_32(port, ext_ftr_ptr + -				RIO_PORT_N_CTL_CSR(0), -				®val); -	} else { -		if (rio_mport_read_config_32(port, destid, hopcount, -		ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), ®val) < 0) -			return -EIO; -	} - -	if (regval & RIO_PORT_N_CTL_P_TYP_SER) { -		/* serial */ -		regval = regval | RIO_PORT_N_CTL_EN_RX_SER -				| RIO_PORT_N_CTL_EN_TX_SER; -	} else { -		/* parallel */ -		regval = regval | RIO_PORT_N_CTL_EN_RX_PAR -				| RIO_PORT_N_CTL_EN_TX_PAR; -	} - -	if (local) { -		rio_local_write_config_32(port, ext_ftr_ptr + -					  RIO_PORT_N_CTL_CSR(0), regval); -	} else { -		if (rio_mport_write_config_32(port, destid, hopcount, -		    ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), regval) < 0) -			return -EIO; -	} -#endif -	return 0; -} - -/**   * rio_setup_device- Allocates and sets up a RIO device   * @net: RIO network   * @port: Master port to send transactions @@ -370,7 +338,7 @@ inline int rio_enable_rx_tx_port(struct rio_mport *port,   * to a RIO device on success or NULL on failure.   *   */ -static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, +static struct rio_dev *rio_setup_device(struct rio_net *net,  					struct rio_mport *port, u16 destid,  					u8 hopcount, int do_enum)  { @@ -378,12 +346,30 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,  	struct rio_dev *rdev;  	struct rio_switch *rswitch = NULL;  	int result, rdid; +	size_t size; +	u32 swpinfo = 0; + +	size = sizeof(struct rio_dev); +	if (rio_mport_read_config_32(port, destid, hopcount, +				     RIO_PEF_CAR, &result)) +		return NULL; -	rdev = kzalloc(sizeof(struct rio_dev), GFP_KERNEL); +	if (result & (RIO_PEF_SWITCH | RIO_PEF_MULTIPORT)) { +		rio_mport_read_config_32(port, destid, hopcount, +					 RIO_SWP_INFO_CAR, &swpinfo); +		if (result & RIO_PEF_SWITCH) { +			size += (RIO_GET_TOTAL_PORTS(swpinfo) * +				sizeof(rswitch->nextdev[0])) + sizeof(*rswitch); +		} +	} + +	rdev = kzalloc(size, GFP_KERNEL);  	if (!rdev)  		return NULL;  	rdev->net = net; +	rdev->pef = result; +	rdev->swpinfo = swpinfo;  	rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_ID_CAR,  				 &result);  	rdev->did = result >> 16; @@ -397,8 +383,6 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,  	rio_mport_read_config_32(port, destid, hopcount, RIO_ASM_INFO_CAR,  				 &result);  	rdev->asm_rev = result >> 16; -	rio_mport_read_config_32(port, destid, hopcount, RIO_PEF_CAR, -				 &rdev->pef);  	if (rdev->pef & RIO_PEF_EXT_FEATURES) {  		rdev->efptr = result & 0xffff;  		rdev->phys_efptr = rio_mport_get_physefb(port, 0, destid, @@ -408,11 +392,6 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,  						hopcount, RIO_EFB_ERR_MGMNT);  	} -	if (rdev->pef & (RIO_PEF_SWITCH | RIO_PEF_MULTIPORT)) { -		rio_mport_read_config_32(port, destid, hopcount, -					 RIO_SWP_INFO_CAR, &rdev->swpinfo); -	} -  	rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR,  				 &rdev->src_ops);  	rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR, @@ -427,32 +406,35 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,  		rio_mport_write_config_32(port, destid, hopcount,  					  RIO_COMPONENT_TAG_CSR, next_comptag);  		rdev->comp_tag = next_comptag++; +		rdev->do_enum = true; +	}  else { +		rio_mport_read_config_32(port, destid, hopcount, +					 RIO_COMPONENT_TAG_CSR, +					 &rdev->comp_tag);  	}  	if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) {  		if (do_enum) {  			rio_set_device_id(port, destid, hopcount, next_destid); -			rdev->destid = next_destid++; -			if (next_destid == port->host_deviceid) -				next_destid++; +			rdev->destid = next_destid; +			next_destid = rio_destid_alloc(net);  		} else  			rdev->destid = rio_get_device_id(port, destid, hopcount); -	} else -		/* Switch device has an associated destID */ -		rdev->destid = RIO_INVALID_DESTID; + +		rdev->hopcount = 0xff; +	} else { +		/* Switch device has an associated destID which +		 * will be adjusted later +		 */ +		rdev->destid = destid; +		rdev->hopcount = hopcount; +	}  	/* If a PE has both switch and other functions, show it as a switch */  	if (rio_is_switch(rdev)) { -		rswitch = kzalloc(sizeof(*rswitch) + -				  RIO_GET_TOTAL_PORTS(rdev->swpinfo) * -				  sizeof(rswitch->nextdev[0]), -				  GFP_KERNEL); -		if (!rswitch) -			goto cleanup; -		rswitch->switchid = next_switchid; -		rswitch->hopcount = hopcount; -		rswitch->destid = destid; +		rswitch = rdev->rswitch;  		rswitch->port_ok = 0; +		spin_lock_init(&rswitch->lock);  		rswitch->route_table = kzalloc(sizeof(u8)*  					RIO_MAX_ROUTE_ENTRIES(port->sys_size),  					GFP_KERNEL); @@ -462,17 +444,13 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,  		for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES(port->sys_size);  				rdid++)  			rswitch->route_table[rdid] = RIO_INVALID_ROUTE; -		rdev->rswitch = rswitch; -		rswitch->rdev = rdev;  		dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id, -			     rdev->rswitch->switchid); -		rio_switch_init(rdev, do_enum); +			     rdev->comp_tag & RIO_CTAG_UDEVID); -		if (do_enum && rdev->rswitch->clr_table) -			rdev->rswitch->clr_table(port, destid, hopcount, -						 RIO_GLOBAL_TABLE); +		if (do_enum) +			rio_route_clr_table(rdev, RIO_GLOBAL_TABLE, 0); -		list_add_tail(&rswitch->node, &rio_switches); +		list_add_tail(&rswitch->node, &net->switches);  	} else {  		if (do_enum) @@ -480,11 +458,11 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,  			rio_enable_rx_tx_port(port, 0, destid, hopcount, 0);  		dev_set_name(&rdev->dev, "%02x:e:%04x", rdev->net->id, -			     rdev->destid); +			     rdev->comp_tag & RIO_CTAG_UDEVID);  	} -	rdev->dev.bus = &rio_bus_type; -	rdev->dev.parent = &rio_bus; +	rdev->dev.parent = &port->dev; +	rio_attach_device(rdev);  	device_initialize(&rdev->dev);  	rdev->dev.release = rio_release_dev; @@ -494,8 +472,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,  	rdev->dev.dma_mask = &rdev->dma_mask;  	rdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); -	if ((rdev->pef & RIO_PEF_INB_DOORBELL) && -	    (rdev->dst_ops & RIO_DST_OPS_DOORBELL)) +	if (rdev->dst_ops & RIO_DST_OPS_DOORBELL)  		rio_init_dbell_res(&rdev->riores[RIO_DOORBELL_RESOURCE],  				   0, 0xffff); @@ -506,10 +483,9 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,  	return rdev;  cleanup: -	if (rswitch) { +	if (rswitch)  		kfree(rswitch->route_table); -		kfree(rswitch); -	} +  	kfree(rdev);  	return NULL;  } @@ -557,156 +533,6 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)  }  /** - * rio_lock_device - Acquires host device lock for specified device - * @port: Master port to send transaction - * @destid: Destination ID for device/switch - * @hopcount: Hopcount to reach switch - * @wait_ms: Max wait time in msec (0 = no timeout) - * - * Attepts to acquire host device lock for specified device - * Returns 0 if device lock acquired or EINVAL if timeout expires. - */ -static int -rio_lock_device(struct rio_mport *port, u16 destid, u8 hopcount, int wait_ms) -{ -	u32 result; -	int tcnt = 0; - -	/* Attempt to acquire device lock */ -	rio_mport_write_config_32(port, destid, hopcount, -				  RIO_HOST_DID_LOCK_CSR, port->host_deviceid); -	rio_mport_read_config_32(port, destid, hopcount, -				 RIO_HOST_DID_LOCK_CSR, &result); - -	while (result != port->host_deviceid) { -		if (wait_ms != 0 && tcnt == wait_ms) { -			pr_debug("RIO: timeout when locking device %x:%x\n", -				destid, hopcount); -			return -EINVAL; -		} - -		/* Delay a bit */ -		mdelay(1); -		tcnt++; -		/* Try to acquire device lock again */ -		rio_mport_write_config_32(port, destid, -			hopcount, -			RIO_HOST_DID_LOCK_CSR, -			port->host_deviceid); -		rio_mport_read_config_32(port, destid, -			hopcount, -			RIO_HOST_DID_LOCK_CSR, &result); -	} - -	return 0; -} - -/** - * rio_unlock_device - Releases host device lock for specified device - * @port: Master port to send transaction - * @destid: Destination ID for device/switch - * @hopcount: Hopcount to reach switch - * - * Returns 0 if device lock released or EINVAL if fails. - */ -static int -rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount) -{ -	u32 result; - -	/* Release device lock */ -	rio_mport_write_config_32(port, destid, -				  hopcount, -				  RIO_HOST_DID_LOCK_CSR, -				  port->host_deviceid); -	rio_mport_read_config_32(port, destid, hopcount, -		RIO_HOST_DID_LOCK_CSR, &result); -	if ((result & 0xffff) != 0xffff) { -		pr_debug("RIO: badness when releasing device lock %x:%x\n", -			 destid, hopcount); -		return -EINVAL; -	} - -	return 0; -} - -/** - * rio_route_add_entry- Add a route entry to a switch routing table - * @mport: Master port to send transaction - * @rswitch: Switch device - * @table: Routing table ID - * @route_destid: Destination ID to be routed - * @route_port: Port number to be routed - * @lock: lock switch device flag - * - * Calls the switch specific add_entry() method to add a route entry - * on a switch. The route table can be specified using the @table - * argument if a switch has per port routing tables or the normal - * use is to specific all tables (or the global table) by passing - * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL - * on failure. - */ -static int -rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch, -		    u16 table, u16 route_destid, u8 route_port, int lock) -{ -	int rc; - -	if (lock) { -		rc = rio_lock_device(mport, rswitch->destid, -				     rswitch->hopcount, 1000); -		if (rc) -			return rc; -	} - -	rc = rswitch->add_entry(mport, rswitch->destid, -					rswitch->hopcount, table, -					route_destid, route_port); -	if (lock) -		rio_unlock_device(mport, rswitch->destid, rswitch->hopcount); - -	return rc; -} - -/** - * rio_route_get_entry- Read a route entry in a switch routing table - * @mport: Master port to send transaction - * @rswitch: Switch device - * @table: Routing table ID - * @route_destid: Destination ID to be routed - * @route_port: Pointer to read port number into - * @lock: lock switch device flag - * - * Calls the switch specific get_entry() method to read a route entry - * in a switch. The route table can be specified using the @table - * argument if a switch has per port routing tables or the normal - * use is to specific all tables (or the global table) by passing - * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL - * on failure. - */ -static int -rio_route_get_entry(struct rio_mport *mport, struct rio_switch *rswitch, u16 table, -		    u16 route_destid, u8 *route_port, int lock) -{ -	int rc; - -	if (lock) { -		rc = rio_lock_device(mport, rswitch->destid, -				     rswitch->hopcount, 1000); -		if (rc) -			return rc; -	} - -	rc = rswitch->get_entry(mport, rswitch->destid, -					rswitch->hopcount, table, -					route_destid, route_port); -	if (lock) -		rio_unlock_device(mport, rswitch->destid, rswitch->hopcount); - -	return rc; -} - -/**   * rio_get_host_deviceid_lock- Reads the Host Device ID Lock CSR on a device   * @port: Master port to send transaction   * @hopcount: Number of hops to the device @@ -735,15 +561,10 @@ static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount)   * Recursively enumerates a RIO network.  Transactions are sent via the   * master port passed in @port.   */ -static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, +static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,  			 u8 hopcount, struct rio_dev *prev, int prev_port)  { -	int port_num; -	int cur_destid; -	int sw_destid; -	int sw_inport;  	struct rio_dev *rdev; -	u16 destid;  	u32 regval;  	int tmp; @@ -809,20 +630,26 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,  		return -1;  	if (rio_is_switch(rdev)) { -		next_switchid++; +		int sw_destid; +		int cur_destid; +		int sw_inport; +		u16 destid; +		int port_num; +  		sw_inport = RIO_GET_PORT_NUM(rdev->swpinfo); -		rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, +		rio_route_add_entry(rdev, RIO_GLOBAL_TABLE,  				    port->host_deviceid, sw_inport, 0);  		rdev->rswitch->route_table[port->host_deviceid] = sw_inport; -		for (destid = 0; destid < next_destid; destid++) { -			if (destid == port->host_deviceid) -				continue; -			rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, -					    destid, sw_inport, 0); -			rdev->rswitch->route_table[destid] = sw_inport; +		destid = rio_destid_first(net); +		while (destid != RIO_INVALID_DESTID && destid < next_destid) { +			if (destid != port->host_deviceid) { +				rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, +						    destid, sw_inport, 0); +				rdev->rswitch->route_table[destid] = sw_inport; +			} +			destid = rio_destid_next(net, destid + 1);  		} -  		pr_debug(  		    "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n",  		    rio_name(rdev), rdev->vid, rdev->did, @@ -831,12 +658,10 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,  		for (port_num = 0;  		     port_num < RIO_GET_TOTAL_PORTS(rdev->swpinfo);  		     port_num++) { -			/*Enable Input Output Port (transmitter reviever)*/ -			rio_enable_rx_tx_port(port, 0, +			if (sw_inport == port_num) { +				rio_enable_rx_tx_port(port, 0,  					      RIO_ANY_DESTID(port->sys_size),  					      hopcount, port_num); - -			if (sw_inport == port_num) {  				rdev->rswitch->port_ok |= (1 << port_num);  				continue;  			} @@ -849,9 +674,11 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,  				pr_debug(  				    "RIO: scanning device on port %d\n",  				    port_num); +				rio_enable_rx_tx_port(port, 0, +					      RIO_ANY_DESTID(port->sys_size), +					      hopcount, port_num);  				rdev->rswitch->port_ok |= (1 << port_num); -				rio_route_add_entry(port, rdev->rswitch, -						RIO_GLOBAL_TABLE, +				rio_route_add_entry(rdev, RIO_GLOBAL_TABLE,  						RIO_ANY_DESTID(port->sys_size),  						port_num, 0); @@ -860,19 +687,22 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,  					return -1;  				/* Update routing tables */ -				if (next_destid > cur_destid) { +				destid = rio_destid_next(net, cur_destid + 1); +				if (destid != RIO_INVALID_DESTID) {  					for (destid = cur_destid; -					     destid < next_destid; destid++) { -						if (destid == port->host_deviceid) -							continue; -						rio_route_add_entry(port, rdev->rswitch, +					     destid < next_destid;) { +						if (destid != port->host_deviceid) { +							rio_route_add_entry(rdev,  								    RIO_GLOBAL_TABLE,  								    destid,  								    port_num,  								    0); -						rdev->rswitch-> -						    route_table[destid] = -						    port_num; +							rdev->rswitch-> +								route_table[destid] = +								port_num; +						} +						destid = rio_destid_next(net, +								destid + 1);  					}  				}  			} else { @@ -898,13 +728,10 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,  		rio_init_em(rdev);  		/* Check for empty switch */ -		if (next_destid == sw_destid) { -			next_destid++; -			if (next_destid == port->host_deviceid) -				next_destid++; -		} +		if (next_destid == sw_destid) +			next_destid = rio_destid_alloc(net); -		rdev->rswitch->destid = sw_destid; +		rdev->destid = sw_destid;  	} else  		pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n",  		    rio_name(rdev), rdev->vid, rdev->did); @@ -916,7 +743,7 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,   * rio_enum_complete- Tests if enumeration of a network is complete   * @port: Master port to send transaction   * - * Tests the Component Tag CSR for non-zero value (enumeration + * Tests the PGCCSR discovered bit for non-zero value (enumeration   * complete flag). Return %1 if enumeration is complete or %0 if   * enumeration is incomplete.   */ @@ -926,7 +753,7 @@ static int rio_enum_complete(struct rio_mport *port)  	rio_local_read_config_32(port, port->phys_efptr + RIO_PORT_GEN_CTL_CSR,  				 ®val); -	return (regval & RIO_PORT_GEN_MASTER) ? 1 : 0; +	return (regval & RIO_PORT_GEN_DISCOVERED) ? 1 : 0;  }  /** @@ -935,13 +762,15 @@ static int rio_enum_complete(struct rio_mport *port)   * @port: Master port to send transactions   * @destid: Current destination ID in network   * @hopcount: Number of hops into the network + * @prev: previous rio_dev + * @prev_port: previous port number   *   * Recursively discovers a RIO network.  Transactions are sent via the   * master port passed in @port.   */ -static int __devinit +static int  rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, -	      u8 hopcount) +	      u8 hopcount, struct rio_dev *prev, int prev_port)  {  	u8 port_num, route_port;  	struct rio_dev *rdev; @@ -951,14 +780,15 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,  	if ((rdev = rio_setup_device(net, port, destid, hopcount, 0))) {  		/* Add device to the global and bus/net specific list. */  		list_add_tail(&rdev->net_list, &net->devices); +		rdev->prev = prev; +		if (prev && rio_is_switch(prev)) +			prev->rswitch->nextdev[prev_port] = rdev;  	} else  		return -1;  	if (rio_is_switch(rdev)) { -		next_switchid++; -  		/* Associated destid is how we accessed this switch */ -		rdev->rswitch->destid = destid; +		rdev->destid = destid;  		pr_debug(  		    "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", @@ -981,7 +811,7 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,  				for (ndestid = 0;  				     ndestid < RIO_ANY_DESTID(port->sys_size);  				     ndestid++) { -					rio_route_get_entry(port, rdev->rswitch, +					rio_route_get_entry(rdev,  							    RIO_GLOBAL_TABLE,  							    ndestid,  							    &route_port, 0); @@ -992,8 +822,8 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,  				if (ndestid == RIO_ANY_DESTID(port->sys_size))  					continue;  				rio_unlock_device(port, destid, hopcount); -				if (rio_disc_peer -				    (net, port, ndestid, hopcount + 1) < 0) +				if (rio_disc_peer(net, port, ndestid, +					hopcount + 1, rdev, port_num) < 0)  					return -1;  			}  		} @@ -1037,65 +867,86 @@ static int rio_mport_is_active(struct rio_mport *port)  /**   * rio_alloc_net- Allocate and configure a new RIO network   * @port: Master port associated with the RIO network + * @do_enum: Enumeration/Discovery mode flag + * @start: logical minimal start id for new net   *   * Allocates a RIO network structure, initializes per-network   * list heads, and adds the associated master port to the   * network list of associated master ports. Returns a   * RIO network pointer on success or %NULL on failure.   */ -static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port) +static struct rio_net *rio_alloc_net(struct rio_mport *port, +					       int do_enum, u16 start)  {  	struct rio_net *net;  	net = kzalloc(sizeof(struct rio_net), GFP_KERNEL); +	if (net && do_enum) { +		net->destid_table.table = kcalloc( +			BITS_TO_LONGS(RIO_MAX_ROUTE_ENTRIES(port->sys_size)), +			sizeof(long), +			GFP_KERNEL); + +		if (net->destid_table.table == NULL) { +			pr_err("RIO: failed to allocate destID table\n"); +			kfree(net); +			net = NULL; +		} else { +			net->destid_table.start = start; +			net->destid_table.max = +					RIO_MAX_ROUTE_ENTRIES(port->sys_size); +			spin_lock_init(&net->destid_table.lock); +		} +	} +  	if (net) {  		INIT_LIST_HEAD(&net->node);  		INIT_LIST_HEAD(&net->devices); +		INIT_LIST_HEAD(&net->switches);  		INIT_LIST_HEAD(&net->mports);  		list_add_tail(&port->nnode, &net->mports);  		net->hport = port; -		net->id = next_net++; +		net->id = port->id;  	}  	return net;  }  /**   * rio_update_route_tables- Updates route tables in switches - * @port: Master port associated with the RIO network + * @net: RIO network to run update on   *   * For each enumerated device, ensure that each switch in a system   * has correct routing entries. Add routes for devices that where   * unknown dirung the first enumeration pass through the switch.   */ -static void rio_update_route_tables(struct rio_mport *port) +static void rio_update_route_tables(struct rio_net *net)  { -	struct rio_dev *rdev; +	struct rio_dev *rdev, *swrdev;  	struct rio_switch *rswitch;  	u8 sport;  	u16 destid; -	list_for_each_entry(rdev, &rio_devices, global_list) { +	list_for_each_entry(rdev, &net->devices, net_list) { -		destid = (rio_is_switch(rdev))?rdev->rswitch->destid:rdev->destid; +		destid = rdev->destid; -		list_for_each_entry(rswitch, &rio_switches, node) { +		list_for_each_entry(rswitch, &net->switches, node) {  			if (rio_is_switch(rdev)	&& (rdev->rswitch == rswitch))  				continue;  			if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) { +				swrdev = sw_to_rio_dev(rswitch); +  				/* Skip if destid ends in empty switch*/ -				if (rswitch->destid == destid) +				if (swrdev->destid == destid)  					continue; -				sport = RIO_GET_PORT_NUM(rswitch->rdev->swpinfo); +				sport = RIO_GET_PORT_NUM(swrdev->swpinfo); -				if (rswitch->add_entry)	{ -					rio_route_add_entry(port, rswitch, -						RIO_GLOBAL_TABLE, destid, -						sport, 0); -					rswitch->route_table[destid] = sport; -				} +				rio_route_add_entry(swrdev, RIO_GLOBAL_TABLE, +						    destid, sport, 0); +				rswitch->route_table[destid] = sport;  			}  		}  	} @@ -1111,8 +962,8 @@ static void rio_update_route_tables(struct rio_mport *port)  static void rio_init_em(struct rio_dev *rdev)  {  	if (rio_is_switch(rdev) && (rdev->em_efptr) && -	    (rdev->rswitch->em_init)) { -		rdev->rswitch->em_init(rdev); +	    rdev->rswitch->ops && rdev->rswitch->ops->em_init) { +		rdev->rswitch->ops->em_init(rdev);  	}  } @@ -1130,19 +981,30 @@ static void rio_pw_enable(struct rio_mport *port, int enable)  /**   * rio_enum_mport- Start enumeration through a master port   * @mport: Master port to send transactions + * @flags: Enumeration control flags   *   * Starts the enumeration process. If somebody has enumerated our   * master port device, then give up. If not and we have an active   * link, then start recursive peer enumeration. Returns %0 if   * enumeration succeeds or %-EBUSY if enumeration fails.   */ -int __devinit rio_enum_mport(struct rio_mport *mport) +static int rio_enum_mport(struct rio_mport *mport, u32 flags)  {  	struct rio_net *net = NULL;  	int rc = 0;  	printk(KERN_INFO "RIO: enumerate master port %d, %s\n", mport->id,  	       mport->name); + +	/* +	 * To avoid multiple start requests (repeat enumeration is not supported +	 * by this method) check if enumeration/discovery was performed for this +	 * mport: if mport was added into the list of mports for a net exit +	 * with error. +	 */ +	if (mport->nnode.next || mport->nnode.prev) +		return -EBUSY; +  	/* If somebody else enumerated our master port device, bail. */  	if (rio_enum_host(mport) < 0) {  		printk(KERN_INFO @@ -1154,12 +1016,16 @@ int __devinit rio_enum_mport(struct rio_mport *mport)  	/* If master port has an active link, allocate net and enum peers */  	if (rio_mport_is_active(mport)) { -		if (!(net = rio_alloc_net(mport))) { +		net = rio_alloc_net(mport, 1, 0); +		if (!net) {  			printk(KERN_ERR "RIO: failed to allocate new net\n");  			rc = -ENOMEM;  			goto out;  		} +		/* reserve mport destID in new net */ +		rio_destid_reserve(net, mport->host_deviceid); +  		/* Enable Input Output Port (transmitter reviever) */  		rio_enable_rx_tx_port(mport, 1, 0, 0, 0); @@ -1167,17 +1033,21 @@ int __devinit rio_enum_mport(struct rio_mport *mport)  		rio_local_write_config_32(mport, RIO_COMPONENT_TAG_CSR,  					  next_comptag++); +		next_destid = rio_destid_alloc(net); +  		if (rio_enum_peer(net, mport, 0, NULL, 0) < 0) {  			/* A higher priority host won enumeration, bail. */  			printk(KERN_INFO  			       "RIO: master port %d device has lost enumeration to a remote host\n",  			       mport->id); -			rio_clear_locks(mport); +			rio_clear_locks(net);  			rc = -EBUSY;  			goto out;  		} -		rio_update_route_tables(mport); -		rio_clear_locks(mport); +		/* free the last allocated destID (unused) */ +		rio_destid_free(net, next_destid); +		rio_update_route_tables(net); +		rio_clear_locks(net);  		rio_pw_enable(mport, 1);  	} else {  		printk(KERN_INFO "RIO: master port %d link inactive\n", @@ -1191,91 +1061,83 @@ int __devinit rio_enum_mport(struct rio_mport *mport)  /**   * rio_build_route_tables- Generate route tables from switch route entries + * @net: RIO network to run route tables scan on   *   * For each switch device, generate a route table by copying existing   * route entries from the switch.   */ -static void rio_build_route_tables(void) +static void rio_build_route_tables(struct rio_net *net)  { +	struct rio_switch *rswitch;  	struct rio_dev *rdev;  	int i;  	u8 sport; -	list_for_each_entry(rdev, &rio_devices, global_list) -		if (rio_is_switch(rdev)) { -			rio_lock_device(rdev->net->hport, rdev->rswitch->destid, -					rdev->rswitch->hopcount, 1000); -			for (i = 0; -			     i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size); -			     i++) { -				if (rio_route_get_entry -				    (rdev->net->hport, rdev->rswitch, -				     RIO_GLOBAL_TABLE, i, &sport, 0) < 0) -					continue; -				rdev->rswitch->route_table[i] = sport; -			} +	list_for_each_entry(rswitch, &net->switches, node) { +		rdev = sw_to_rio_dev(rswitch); -			rio_unlock_device(rdev->net->hport, -					  rdev->rswitch->destid, -					  rdev->rswitch->hopcount); +		rio_lock_device(net->hport, rdev->destid, +				rdev->hopcount, 1000); +		for (i = 0; +		     i < RIO_MAX_ROUTE_ENTRIES(net->hport->sys_size); +		     i++) { +			if (rio_route_get_entry(rdev, RIO_GLOBAL_TABLE, +						i, &sport, 0) < 0) +				continue; +			rswitch->route_table[i] = sport;  		} -} -/** - * rio_enum_timeout- Signal that enumeration timed out - * @data: Address of timeout flag. - * - * When the enumeration complete timer expires, set a flag that - * signals to the discovery process that enumeration did not - * complete in a sane amount of time. - */ -static void rio_enum_timeout(unsigned long data) -{ -	/* Enumeration timed out, set flag */ -	*(int *)data = 1; +		rio_unlock_device(net->hport, rdev->destid, rdev->hopcount); +	}  }  /**   * rio_disc_mport- Start discovery through a master port   * @mport: Master port to send transactions + * @flags: discovery control flags   *   * Starts the discovery process. If we have an active link, - * then wait for the signal that enumeration is complete. + * then wait for the signal that enumeration is complete (if wait + * is allowed).   * When enumeration completion is signaled, start recursive   * peer discovery. Returns %0 if discovery succeeds or %-EBUSY   * on failure.   */ -int __devinit rio_disc_mport(struct rio_mport *mport) +static int rio_disc_mport(struct rio_mport *mport, u32 flags)  {  	struct rio_net *net = NULL; -	int enum_timeout_flag = 0; +	unsigned long to_end;  	printk(KERN_INFO "RIO: discover master port %d, %s\n", mport->id,  	       mport->name);  	/* If master port has an active link, allocate net and discover peers */  	if (rio_mport_is_active(mport)) { -		if (!(net = rio_alloc_net(mport))) { -			printk(KERN_ERR "RIO: Failed to allocate new net\n"); -			goto bail; +		if (rio_enum_complete(mport)) +			goto enum_done; +		else if (flags & RIO_SCAN_ENUM_NO_WAIT) +			return -EAGAIN; + +		pr_debug("RIO: wait for enumeration to complete...\n"); + +		to_end = jiffies + CONFIG_RAPIDIO_DISC_TIMEOUT * HZ; +		while (time_before(jiffies, to_end)) { +			if (rio_enum_complete(mport)) +				goto enum_done; +			msleep(10);  		} -		pr_debug("RIO: wait for enumeration complete..."); - -		rio_enum_timer.expires = -		    jiffies + CONFIG_RAPIDIO_DISC_TIMEOUT * HZ; -		rio_enum_timer.data = (unsigned long)&enum_timeout_flag; -		add_timer(&rio_enum_timer); -		while (!rio_enum_complete(mport)) { -			mdelay(1); -			if (enum_timeout_flag) { -				del_timer_sync(&rio_enum_timer); -				goto timeout; -			} -		} -		del_timer_sync(&rio_enum_timer); +		pr_debug("RIO: discovery timeout on mport %d %s\n", +			 mport->id, mport->name); +		goto bail; +enum_done: +		pr_debug("RIO: ... enumeration done\n"); -		pr_debug("done\n"); +		net = rio_alloc_net(mport, 0, 0); +		if (!net) { +			printk(KERN_ERR "RIO: Failed to allocate new net\n"); +			goto bail; +		}  		/* Read DestID assigned by enumerator */  		rio_local_read_config_32(mport, RIO_DID_CSR, @@ -1284,20 +1146,56 @@ int __devinit rio_disc_mport(struct rio_mport *mport)  						   mport->host_deviceid);  		if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size), -					0) < 0) { +					0, NULL, 0) < 0) {  			printk(KERN_INFO  			       "RIO: master port %d device has failed discovery\n",  			       mport->id);  			goto bail;  		} -		rio_build_route_tables(); +		rio_build_route_tables(net);  	}  	return 0; - -      timeout: -	pr_debug("timeout\n"); -      bail: +bail:  	return -EBUSY;  } + +static struct rio_scan rio_scan_ops = { +	.owner = THIS_MODULE, +	.enumerate = rio_enum_mport, +	.discover = rio_disc_mport, +}; + +static bool scan; +module_param(scan, bool, 0); +MODULE_PARM_DESC(scan, "Start RapidIO network enumeration/discovery " +			"(default = 0)"); + +/** + * rio_basic_attach: + * + * When this enumeration/discovery method is loaded as a module this function + * registers its specific enumeration and discover routines for all available + * RapidIO mport devices. The "scan" command line parameter controls ability of + * the module to start RapidIO enumeration/discovery automatically. + * + * Returns 0 for success or -EIO if unable to register itself. + * + * This enumeration/discovery method cannot be unloaded and therefore does not + * provide a matching cleanup_module routine. + */ + +static int __init rio_basic_attach(void) +{ +	if (rio_register_scan(RIO_MPORT_ANY, &rio_scan_ops)) +		return -EIO; +	if (scan) +		rio_init_mports(); +	return 0; +} + +late_initcall(rio_basic_attach); + +MODULE_DESCRIPTION("Basic RapidIO enumeration/discovery"); +MODULE_LICENSE("GPL");  | 
