nodemgr.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,745 行 · 第 1/4 页

C
1,745
字号
}static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int generation){	struct device *dev;	if (ne->host != hi->host || ne->in_limbo)		return;	dev = get_device(&ne->device);	if (!dev)		return;	/* If "needs_probe", then this is either a new or changed node we	 * rescan totally. If the generation matches for an existing node	 * (one that existed prior to the bus reset) we send update calls	 * down to the drivers. Otherwise, this is a dead node and we	 * suspend it. */	if (ne->needs_probe)		nodemgr_process_root_directory(hi, ne);	else if (ne->generation == generation)		nodemgr_update_pdrv(ne);	else		nodemgr_suspend_ne(ne);	put_device(dev);}static void nodemgr_node_probe(struct host_info *hi, int generation){	struct hpsb_host *host = hi->host;	struct class *class = &nodemgr_ne_class;	struct class_device *cdev;	/* Do some processing of the nodes we've probed. This pulls them	 * into the sysfs layer if needed, and can result in processing of	 * unit-directories, or just updating the node and it's	 * unit-directories. */	down_read(&class->subsys.rwsem);	list_for_each_entry(cdev, &class->children, node)		nodemgr_probe_ne(hi, container_of(cdev, struct node_entry, class_dev), generation);        up_read(&class->subsys.rwsem);	/* If we had a bus reset while we were scanning the bus, it is	 * possible that we did not probe all nodes.  In that case, we	 * skip the clean up for now, since we could remove nodes that	 * were still on the bus.  The bus reset increased hi->reset_sem,	 * so there's a bus scan pending which will do the clean up	 * eventually.	 *	 * Now let's tell the bus to rescan our devices. This may seem	 * like overhead, but the driver-model core will only scan a	 * device for a driver when either the device is added, or when a	 * new driver is added. A bus reset is a good reason to rescan	 * devices that were there before.  For example, an sbp2 device	 * may become available for login, if the host that held it was	 * just removed.  */	if (generation == get_hpsb_generation(host))		bus_rescan_devices(&ieee1394_bus_type);	return;}/* Because we are a 1394a-2000 compliant IRM, we need to inform all the other * nodes of the broadcast channel.  (Really we're only setting the validity * bit). Other IRM responsibilities go in here as well. */static int nodemgr_do_irm_duties(struct hpsb_host *host, int cycles){	quadlet_t bc;	/* if irm_id == -1 then there is no IRM on this bus */	if (!host->is_irm || host->irm_id == (nodeid_t)-1)		return 1;	host->csr.broadcast_channel |= 0x40000000;  /* set validity bit */	bc = cpu_to_be32(host->csr.broadcast_channel);	hpsb_write(host, LOCAL_BUS | ALL_NODES, get_hpsb_generation(host),		   (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL),		   &bc, sizeof(quadlet_t));	/* If there is no bus manager then we should set the root node's	 * force_root bit to promote bus stability per the 1394	 * spec. (8.4.2.6) */	if (host->busmgr_id == 0xffff && host->node_count > 1)	{		u16 root_node = host->node_count - 1;		struct node_entry *ne = find_entry_by_nodeid(host, root_node | LOCAL_BUS);		if (ne && ne->busopt.cmc)			hpsb_send_phy_config(host, root_node, -1);		else {			HPSB_DEBUG("The root node is not cycle master capable; "				   "selecting a new root node and resetting...");			if (cycles >= 5) {				/* Oh screw it! Just leave the bus as it is */				HPSB_DEBUG("Stopping reset loop for IRM sanity");				return 1;			}			hpsb_send_phy_config(host, NODEID_TO_NODE(host->node_id), -1);			hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);			return 0;		}	}	return 1;}/* We need to ensure that if we are not the IRM, that the IRM node is capable of * everything we can do, otherwise issue a bus reset and try to become the IRM * ourselves. */static int nodemgr_check_irm_capability(struct hpsb_host *host, int cycles){	quadlet_t bc;	int status;	if (host->is_irm)		return 1;	status = hpsb_read(host, LOCAL_BUS | (host->irm_id),			   get_hpsb_generation(host),			   (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL),			   &bc, sizeof(quadlet_t));	if (status < 0 || !(be32_to_cpu(bc) & 0x80000000)) {		/* The current irm node does not have a valid BROADCAST_CHANNEL		 * register and we do, so reset the bus with force_root set */		HPSB_DEBUG("Current remote IRM is not 1394a-2000 compliant, resetting...");		if (cycles >= 5) {			/* Oh screw it! Just leave the bus as it is */			HPSB_DEBUG("Stopping reset loop for IRM sanity");			return 1;		}		hpsb_send_phy_config(host, NODEID_TO_NODE(host->node_id), -1);		hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);		return 0;	}	return 1;}static int nodemgr_host_thread(void *__hi){	struct host_info *hi = (struct host_info *)__hi;	struct hpsb_host *host = hi->host;	int reset_cycles = 0;	/* No userlevel access needed */	daemonize(hi->daemon_name);	/* Setup our device-model entries */	nodemgr_create_host_dev_files(host);	/* Sit and wait for a signal to probe the nodes on the bus. This	 * happens when we get a bus reset. */	while (1) {		unsigned int generation = 0;		int i;		if (down_interruptible(&hi->reset_sem) ||		    down_interruptible(&nodemgr_serialize)) {			if (current->flags & PF_FREEZE) {				refrigerator(0);				continue;			}			printk("NodeMgr: received unexpected signal?!\n" );			break;		}		if (hi->kill_me)			break;		/* Pause for 1/4 second in 1/16 second intervals,		 * to make sure things settle down. */		for (i = 0; i < 4 ; i++) {			set_current_state(TASK_INTERRUPTIBLE);			if (schedule_timeout(HZ/16)) {				up(&nodemgr_serialize);				goto caught_signal;			}			/* Now get the generation in which the node ID's we collect			 * are valid.  During the bus scan we will use this generation			 * for the read transactions, so that if another reset occurs			 * during the scan the transactions will fail instead of			 * returning bogus data. */			generation = get_hpsb_generation(host);			/* If we get a reset before we are done waiting, then			 * start the the waiting over again */			while (!down_trylock(&hi->reset_sem))				i = 0;			/* Check the kill_me again */			if (hi->kill_me)				goto caught_signal;		}		if (!nodemgr_check_irm_capability(host, reset_cycles)) {			reset_cycles++;			up(&nodemgr_serialize);			continue;		}		/* Scan our nodes to get the bus options and create node		 * entries. This does not do the sysfs stuff, since that		 * would trigger hotplug callbacks and such, which is a		 * bad idea at this point. */		nodemgr_node_scan(hi, generation);		if (!nodemgr_do_irm_duties(host, reset_cycles)) {			reset_cycles++;			up(&nodemgr_serialize);			continue;		}		reset_cycles = 0;		/* This actually does the full probe, with sysfs		 * registration. */		nodemgr_node_probe(hi, generation);		/* Update some of our sysfs symlinks */		nodemgr_update_host_dev_links(host);		up(&nodemgr_serialize);	}caught_signal:	HPSB_VERBOSE("NodeMgr: Exiting thread");	complete_and_exit(&hi->exited, 0);}struct node_entry *hpsb_guid_get_entry(u64 guid){        struct node_entry *ne;	down(&nodemgr_serialize);        ne = find_entry_by_guid(guid);	up(&nodemgr_serialize);        return ne;}struct node_entry *hpsb_nodeid_get_entry(struct hpsb_host *host, nodeid_t nodeid){	struct node_entry *ne;	down(&nodemgr_serialize);	ne = find_entry_by_nodeid(host, nodeid);	up(&nodemgr_serialize);	return ne;}int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *)){	struct class *class = &hpsb_host_class;	struct class_device *cdev;	struct hpsb_host *host;	int error = 0;	down_read(&class->subsys.rwsem);	list_for_each_entry(cdev, &class->children, node) {		host = container_of(cdev, struct hpsb_host, class_dev);		if ((error = cb(host, __data)))			break;	}	up_read(&class->subsys.rwsem);	return error;}/* The following four convenience functions use a struct node_entry * for addressing a node on the bus.  They are intended for use by any * process context, not just the nodemgr thread, so we need to be a * little careful when reading out the node ID and generation.  The * thing that can go wrong is that we get the node ID, then a bus * reset occurs, and then we read the generation.  The node ID is * possibly invalid, but the generation is current, and we end up * sending a packet to a the wrong node. * * The solution is to make sure we read the generation first, so that * if a reset occurs in the process, we end up with a stale generation * and the transactions will fail instead of silently using wrong node * ID's. */void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt){        pkt->host = ne->host;        pkt->generation = ne->generation;	barrier();        pkt->node_id = ne->nodeid;}int hpsb_node_read(struct node_entry *ne, u64 addr,		   quadlet_t *buffer, size_t length){	unsigned int generation = ne->generation;	barrier();	return hpsb_read(ne->host, ne->nodeid, generation,			 addr, buffer, length);}int hpsb_node_write(struct node_entry *ne, u64 addr,		    quadlet_t *buffer, size_t length){	unsigned int generation = ne->generation;	barrier();	return hpsb_write(ne->host, ne->nodeid, generation,			  addr, buffer, length);}int hpsb_node_lock(struct node_entry *ne, u64 addr,		   int extcode, quadlet_t *data, quadlet_t arg){	unsigned int generation = ne->generation;	barrier();	return hpsb_lock(ne->host, ne->nodeid, generation,			 addr, extcode, data, arg);}static void nodemgr_add_host(struct hpsb_host *host){	struct host_info *hi;	hi = hpsb_create_hostinfo(&nodemgr_highlevel, host, sizeof(*hi));	if (!hi) {		HPSB_ERR ("NodeMgr: out of memory in add host");		return;	}	hi->host = host;	init_completion(&hi->exited);        sema_init(&hi->reset_sem, 0);	sprintf(hi->daemon_name, "knodemgrd_%d", host->id);	hi->pid = kernel_thread(nodemgr_host_thread, hi, CLONE_KERNEL);	if (hi->pid < 0) {		HPSB_ERR ("NodeMgr: failed to start %s thread for %s",			  hi->daemon_name, host->driver->name);		hpsb_destroy_hostinfo(&nodemgr_highlevel, host);		return;	}	return;}static void nodemgr_host_reset(struct hpsb_host *host){	struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host);	if (hi != NULL) {		HPSB_VERBOSE("NodeMgr: Processing host reset for %s", hi->daemon_name);		up(&hi->reset_sem);	} else		HPSB_ERR ("NodeMgr: could not process reset of unused host");	return;}static void nodemgr_remove_host(struct hpsb_host *host){	struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host);	if (hi) {		if (hi->pid >= 0) {			hi->kill_me = 1;			mb();			up(&hi->reset_sem);			wait_for_completion(&hi->exited);			nodemgr_remove_host_dev(&host->device);		}	} else		HPSB_ERR("NodeMgr: host %s does not exist, cannot remove",			 host->driver->name);	return;}static struct hpsb_highlevel nodemgr_highlevel = {	.name =		"Node manager",	.add_host =	nodemgr_add_host,	.host_reset =	nodemgr_host_reset,	.remove_host =	nodemgr_remove_host,};int init_ieee1394_nodemgr(void){	int ret;	ret = class_register(&nodemgr_ne_class);	if (ret < 0)		return ret;	ret = class_register(&nodemgr_ud_class);	if (ret < 0) {		class_unregister(&nodemgr_ne_class);		return ret;	}	hpsb_register_highlevel(&nodemgr_highlevel);	return 0;}void cleanup_ieee1394_nodemgr(void){        hpsb_unregister_highlevel(&nodemgr_highlevel);	class_unregister(&nodemgr_ud_class);	class_unregister(&nodemgr_ne_class);}

⌨️ 快捷键说明

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