rio-scan.c

来自「linux 内核源代码」· C语言 代码 · 共 1,001 行 · 第 1/2 页

C
1,001
字号
	rio_mport_read_config_32(mport, destid, hopcount, RIO_SWP_INFO_CAR,				 &result);	return (u8) (result & 0xff);}/** * rio_get_swpinfo_tports- Gets total number of ports on the switch * @mport: Master port to send transaction * @destid: Destination ID associated with the switch * @hopcount: Number of hops to the device * * Returns total numbers of ports implemented by the switch device. */static u8 rio_get_swpinfo_tports(struct rio_mport *mport, u16 destid,				 u8 hopcount){	u32 result;	rio_mport_read_config_32(mport, destid, hopcount, RIO_SWP_INFO_CAR,				 &result);	return RIO_GET_TOTAL_PORTS(result);}/** * rio_net_add_mport- Add a master port to a RIO network * @net: RIO network * @port: Master port to add * * Adds a master port to the network list of associated master * ports.. */static void rio_net_add_mport(struct rio_net *net, struct rio_mport *port){	spin_lock(&rio_global_list_lock);	list_add_tail(&port->nnode, &net->mports);	spin_unlock(&rio_global_list_lock);}/** * rio_enum_peer- Recursively enumerate a RIO network through a master port * @net: RIO network being enumerated * @port: Master port to send transactions * @hopcount: Number of hops into the network * * Recursively enumerates a RIO network.  Transactions are sent via the * master port passed in @port. */static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,			 u8 hopcount){	int port_num;	int num_ports;	int cur_destid;	int sw_destid;	int sw_inport;	struct rio_dev *rdev;	u16 destid;	int tmp;	if (rio_get_host_deviceid_lock(port, hopcount) == port->host_deviceid) {		pr_debug("RIO: PE already discovered by this host\n");		/*		 * Already discovered by this host. Add it as another		 * master port for the current network.		 */		rio_net_add_mport(net, port);		return 0;	}	/* Attempt to acquire device lock */	rio_mport_write_config_32(port, RIO_ANY_DESTID, hopcount,				  RIO_HOST_DID_LOCK_CSR, port->host_deviceid);	while ((tmp = rio_get_host_deviceid_lock(port, hopcount))	       < port->host_deviceid) {		/* Delay a bit */		mdelay(1);		/* Attempt to acquire device lock again */		rio_mport_write_config_32(port, RIO_ANY_DESTID, hopcount,					  RIO_HOST_DID_LOCK_CSR,					  port->host_deviceid);	}	if (rio_get_host_deviceid_lock(port, hopcount) > port->host_deviceid) {		pr_debug(		    "RIO: PE locked by a higher priority host...retreating\n");		return -1;	}	/* Setup new RIO device */	if ((rdev = rio_setup_device(net, port, RIO_ANY_DESTID, hopcount, 1))) {		/* Add device to the global and bus/net specific list. */		list_add_tail(&rdev->net_list, &net->devices);	} else		return -1;	if (rio_is_switch(rdev)) {		next_switchid++;		sw_inport = rio_get_swpinfo_inport(port, RIO_ANY_DESTID, hopcount);		rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE,				    port->host_deviceid, sw_inport);		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);			rdev->rswitch->route_table[destid] = sw_inport;		}		num_ports =		    rio_get_swpinfo_tports(port, RIO_ANY_DESTID, hopcount);		pr_debug(		    "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n",		    rio_name(rdev), rdev->vid, rdev->did, num_ports);		sw_destid = next_destid;		for (port_num = 0; port_num < num_ports; port_num++) {			if (sw_inport == port_num)				continue;			cur_destid = next_destid;			if (rio_sport_is_active			    (port, RIO_ANY_DESTID, hopcount, port_num)) {				pr_debug(				    "RIO: scanning device on port %d\n",				    port_num);				rio_route_add_entry(port, rdev->rswitch,						    RIO_GLOBAL_TABLE,						    RIO_ANY_DESTID, port_num);				if (rio_enum_peer(net, port, hopcount + 1) < 0)					return -1;				/* Update routing tables */				if (next_destid > cur_destid) {					for (destid = cur_destid;					     destid < next_destid; destid++) {						if (destid == port->host_deviceid)							continue;						rio_route_add_entry(port, rdev->rswitch,								    RIO_GLOBAL_TABLE,								    destid,								    port_num);						rdev->rswitch->						    route_table[destid] =						    port_num;					}				}			}		}		/* Check for empty switch */		if (next_destid == sw_destid) {			next_destid++;			if (next_destid == port->host_deviceid)				next_destid++;		}		rdev->rswitch->destid = sw_destid;	} else		pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n",		    rio_name(rdev), rdev->vid, rdev->did);	return 0;}/** * rio_enum_complete- Tests if enumeration of a network is complete * @port: Master port to send transaction * * Tests the Component Tag CSR for presence of the magic enumeration * complete flag. Return %1 if enumeration is complete or %0 if * enumeration is incomplete. */static int rio_enum_complete(struct rio_mport *port){	u32 tag_csr;	int ret = 0;	rio_local_read_config_32(port, RIO_COMPONENT_TAG_CSR, &tag_csr);	if (tag_csr == RIO_ENUM_CMPL_MAGIC)		ret = 1;	return ret;}/** * rio_disc_peer- Recursively discovers a RIO network through a master port * @net: RIO network being discovered * @port: Master port to send transactions * @destid: Current destination ID in network * @hopcount: Number of hops into the network * * Recursively discovers a RIO network.  Transactions are sent via the * master port passed in @port. */static intrio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,	      u8 hopcount){	u8 port_num, route_port;	int num_ports;	struct rio_dev *rdev;	u16 ndestid;	/* Setup new RIO device */	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);	} else		return -1;	if (rio_is_switch(rdev)) {		next_switchid++;		/* Associated destid is how we accessed this switch */		rdev->rswitch->destid = destid;		num_ports = rio_get_swpinfo_tports(port, destid, hopcount);		pr_debug(		    "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n",		    rio_name(rdev), rdev->vid, rdev->did, num_ports);		for (port_num = 0; port_num < num_ports; port_num++) {			if (rio_get_swpinfo_inport(port, destid, hopcount) ==			    port_num)				continue;			if (rio_sport_is_active			    (port, destid, hopcount, port_num)) {				pr_debug(				    "RIO: scanning device on port %d\n",				    port_num);				for (ndestid = 0; ndestid < RIO_ANY_DESTID;				     ndestid++) {					rio_route_get_entry(port, rdev->rswitch,							    RIO_GLOBAL_TABLE,							    ndestid,							    &route_port);					if (route_port == port_num)						break;				}				if (rio_disc_peer				    (net, port, ndestid, hopcount + 1) < 0)					return -1;			}		}	} else		pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n",		    rio_name(rdev), rdev->vid, rdev->did);	return 0;}/** * rio_mport_is_active- Tests if master port link is active * @port: Master port to test * * Reads the port error status CSR for the master port to * determine if the port has an active link.  Returns * %PORT_N_ERR_STS_PORT_OK if the  master port is active * or %0 if it is inactive. */static int rio_mport_is_active(struct rio_mport *port){	u32 result = 0;	u32 ext_ftr_ptr;	int *entry = rio_mport_phys_table;	do {		if ((ext_ftr_ptr =		     rio_mport_get_feature(port, 1, 0, 0, *entry)))			break;	} while (*++entry >= 0);	if (ext_ftr_ptr)		rio_local_read_config_32(port,					 ext_ftr_ptr +					 RIO_PORT_N_ERR_STS_CSR(port->index),					 &result);	return (result & PORT_N_ERR_STS_PORT_OK);}/** * rio_alloc_net- Allocate and configure a new RIO network * @port: Master port associated with the RIO network * * 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){	struct rio_net *net;	net = kzalloc(sizeof(struct rio_net), GFP_KERNEL);	if (net) {		INIT_LIST_HEAD(&net->node);		INIT_LIST_HEAD(&net->devices);		INIT_LIST_HEAD(&net->mports);		list_add_tail(&port->nnode, &net->mports);		net->hport = port;		net->id = next_net++;	}	return net;}/** * rio_update_route_tables- Updates route tables in switches * @port: Master port associated with the RIO network * * 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){	struct rio_dev *rdev;	struct rio_switch *rswitch;	u8 sport;	u16 destid;	list_for_each_entry(rdev, &rio_devices, global_list) {		destid = (rio_is_switch(rdev))?rdev->rswitch->destid:rdev->destid;		list_for_each_entry(rswitch, &rio_switches, node) {			if (rio_is_switch(rdev)	&& (rdev->rswitch == rswitch))				continue;			if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) {				sport = rio_get_swpinfo_inport(port,						rswitch->destid, rswitch->hopcount);				if (rswitch->add_entry)	{					rio_route_add_entry(port, rswitch, RIO_GLOBAL_TABLE, destid, sport);					rswitch->route_table[destid] = sport;				}			}		}	}}/** * rio_enum_mport- Start enumeration through a master port * @mport: Master port to send transactions * * 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 rio_enum_mport(struct rio_mport *mport){	struct rio_net *net = NULL;	int rc = 0;	printk(KERN_INFO "RIO: enumerate master port %d, %s\n", mport->id,	       mport->name);	/* If somebody else enumerated our master port device, bail. */	if (rio_enum_host(mport) < 0) {		printk(KERN_INFO		       "RIO: master port %d device has been enumerated by a remote host\n",		       mport->id);		rc = -EBUSY;		goto out;	}	/* If master port has an active link, allocate net and enum peers */	if (rio_mport_is_active(mport)) {		if (!(net = rio_alloc_net(mport))) {			printk(KERN_ERR "RIO: failed to allocate new net\n");			rc = -ENOMEM;			goto out;		}		if (rio_enum_peer(net, mport, 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);			rc = -EBUSY;			goto out;		}		rio_update_route_tables(mport);		rio_clear_locks(mport);	} else {		printk(KERN_INFO "RIO: master port %d link inactive\n",		       mport->id);		rc = -EINVAL;	}      out:	return rc;}/** * rio_build_route_tables- Generate route tables from switch route entries * * For each switch device, generate a route table by copying existing * route entries from the switch. */static void rio_build_route_tables(void){	struct rio_dev *rdev;	int i;	u8 sport;	list_for_each_entry(rdev, &rio_devices, global_list)	    if (rio_is_switch(rdev))		for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) {			if (rio_route_get_entry			    (rdev->net->hport, rdev->rswitch, RIO_GLOBAL_TABLE,			     i, &sport) < 0)				continue;			rdev->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_disc_mport- Start discovery through a master port * @mport: Master port to send transactions * * Starts the discovery process. If we have an active link, * then wait for the signal that enumeration is complete. * When enumeration completion is signaled, start recursive * peer discovery. Returns %0 if discovery succeeds or %-EBUSY * on failure. */int rio_disc_mport(struct rio_mport *mport){	struct rio_net *net = NULL;	int enum_timeout_flag = 0;	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;		}		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("done\n");		if (rio_disc_peer(net, mport, RIO_ANY_DESTID, 0) < 0) {			printk(KERN_INFO			       "RIO: master port %d device has failed discovery\n",			       mport->id);			goto bail;		}		rio_build_route_tables();	}	return 0;      timeout:	pr_debug("timeout\n");      bail:	return -EBUSY;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?