⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nodemgr.c

📁 这个是uClinux下的ieee1394驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
	/*	 * When the config rom changes we disconnect all drivers and	 * free the cached unit directories and reread the whole	 * thing.  If this was a new device, the call to	 * nodemgr_disconnect_drivers is a no-op and all is well.	 */	nodemgr_free_unit_directories(ne);	nodemgr_process_root_directory(ne);	nodemgr_bind_drivers(ne);}/* * This function updates nodes that were present on the bus before the * reset and still are after the reset.  The nodeid and the config rom * may have changed, and the drivers managing this device must be * informed that this device just went through a bus reset, to allow * the to take whatever actions required. */static void nodemgr_update_node(struct node_entry *ne, quadlet_t busoptions,                               struct hpsb_host *host,				nodeid_t nodeid, unsigned int generation){	struct list_head *lh;	struct unit_directory *ud;	if (ne->nodeid != nodeid) {		HPSB_DEBUG("Node " NODE_BUS_FMT " changed to " NODE_BUS_FMT,			   NODE_BUS_ARGS(ne->nodeid), NODE_BUS_ARGS(nodeid));		ne->nodeid = nodeid;	}	if (ne->busopt.generation != ((busoptions >> 4) & 0xf))		nodemgr_process_config_rom (ne, busoptions);	/* Since that's done, we can declare this record current */	ne->generation = generation;	list_for_each (lh, &ne->unit_directories) {		ud = list_entry (lh, struct unit_directory, node_list);		if (ud->driver != NULL && ud->driver->update != NULL)			ud->driver->update(ud);	}}static int read_businfo_block(struct hpsb_host *host, nodeid_t nodeid, unsigned int generation,			      quadlet_t *buffer, int buffer_length){	octlet_t addr = CSR_REGISTER_BASE + CSR_CONFIG_ROM;	unsigned header_size;	int i;	/* IEEE P1212 says that devices should support 64byte block	 * reads, aligned on 64byte boundaries. That doesn't seem to	 * work though, and we are forced to doing quadlet sized	 * reads.  */#ifdef CONFIG_IEEE1394_VERBOSEDEBUG	HPSB_INFO("Initiating ConfigROM request for node " NODE_BUS_FMT,		  NODE_BUS_ARGS(nodeid));#endif	/* 	 * Must retry a few times if config rom read returns zero (how long?). Will	 * not normally occur, but we should do the right thing. For example, with	 * some sbp2 devices, the bridge chipset cannot return valid config rom reads	 * immediately after power-on, since they need to detect the type of 	 * device attached (disk or CD-ROM).	 */	for (i = 0; i < 4; i++) {		if (nodemgr_read_quadlet(host, nodeid, generation,					 addr, &buffer[0]) < 0) {			HPSB_ERR("ConfigROM quadlet transaction error for node "				 NODE_BUS_FMT, NODE_BUS_ARGS(nodeid));			return -1;		}		if (buffer[0])			break;		set_current_state(TASK_INTERRUPTIBLE);		if (schedule_timeout (HZ/4))			return -1;	}	header_size = buffer[0] >> 24;	addr += 4;	if (header_size < 4) {		HPSB_INFO("Node " NODE_BUS_FMT " has non-standard ROM "			  "format (%d quads), cannot parse",			  NODE_BUS_ARGS(nodeid), header_size);		return -1;	}	for (i = 1; i < buffer_length; i++, addr += 4) {		if (nodemgr_read_quadlet(host, nodeid, generation,					 addr, &buffer[i]) < 0) {			HPSB_ERR("ConfigROM quadlet transaction "				 "error for node " NODE_BUS_FMT,				 NODE_BUS_ARGS(nodeid));			return -1;		}	}	return 0;}		static void nodemgr_remove_node(struct node_entry *ne){	HPSB_DEBUG("%s removed: Node[" NODE_BUS_FMT "]  GUID[%016Lx]  [%s]",		   (ne->host->node_id == ne->nodeid) ? "Host" : "Device",		   NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid,		   ne->vendor_name ?: "Unknown");	nodemgr_free_unit_directories(ne);	list_del(&ne->list);	kfree(ne);	return;}/* This is where we probe the nodes for their information and provided * features.  */static void nodemgr_node_probe_one(struct hpsb_host *host,				   nodeid_t nodeid, int generation){	struct node_entry *ne;	quadlet_t buffer[5];	octlet_t guid;	/* We need to detect when the ConfigROM's generation has changed,	 * so we only update the node's info when it needs to be.  */	if (read_businfo_block (host, nodeid, generation,				buffer, sizeof(buffer) >> 2))		return;	if (buffer[1] != IEEE1394_BUSID_MAGIC) {		/* This isn't a 1394 device, but we let it slide. There		 * was a report of a device with broken firmware which		 * reported '2394' instead of '1394', which is obviously a		 * mistake. One would hope that a non-1394 device never		 * gets connected to Firewire bus. If someone does, we		 * shouldn't be held responsible, so we'll allow it with a		 * warning.  */		HPSB_WARN("Node " NODE_BUS_FMT " has invalid busID magic [0x%08x]",			 NODE_BUS_ARGS(nodeid), buffer[1]);	}	guid = ((u64)buffer[3] << 32) | buffer[4];	ne = find_entry_by_guid(guid);	if (!ne)		nodemgr_create_node(guid, buffer[2], host, nodeid, generation);	else		nodemgr_update_node(ne, buffer[2], host, nodeid, generation);	return;}static void nodemgr_node_probe_cleanup(struct hpsb_host *host, unsigned int generation){	struct list_head *lh, *next;	struct node_entry *ne;	/* Now check to see if we have any nodes that aren't referenced	 * any longer.  */	list_for_each_safe(lh, next, &node_list) {		ne = list_entry(lh, struct node_entry, list);		/* Only checking this host */		if (ne->host != host)			continue;		/* If the generation didn't get updated, then either the		 * node was removed, or it failed the above probe. Either		 * way, we remove references to it, since they are		 * invalid.  */		if (ne->generation != generation)			nodemgr_remove_node(ne);	}	return;}static void nodemgr_node_probe(struct hpsb_host *host){	int count;	struct selfid *sid = (struct selfid *)host->topology_map;	nodeid_t nodeid = LOCAL_BUS;	unsigned int generation;	/* Pause for 1/4 second, to make sure things settle down. If	 * schedule_timeout returns non-zero, it means we caught a signal	 * and need to return. */	set_current_state(TASK_INTERRUPTIBLE);	if (schedule_timeout (HZ/4))		return;	/* 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);	/* Scan each node on the bus */	for (count = host->selfid_count; count; count--, sid++) {		if (sid->extended)			continue;		if (!sid->link_active) {			nodeid++;			continue;		}		nodemgr_node_probe_one(host, nodeid++, generation);	}	/* 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. */	if (generation == get_hpsb_generation(host))		nodemgr_node_probe_cleanup(host, generation);	return;}static int nodemgr_host_thread(void *__hi){	struct host_info *hi = (struct host_info *)__hi;	/* No userlevel access needed */	daemonize();	strcpy(current->comm, "knodemgrd");		/* Sit and wait for a signal to probe the nodes on the bus. This	 * happens when we get a bus reset. */	while (!down_interruptible(&hi->reset_sem) &&	       !down_interruptible(&nodemgr_serialize)) {		nodemgr_node_probe(hi->host);		up(&nodemgr_serialize);	}#ifdef CONFIG_IEEE1394_VERBOSEDEBUG	HPSB_DEBUG ("NodeMgr: Exiting thread for %s", hi->host->driver->name);#endif	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(nodeid_t nodeid){	struct node_entry *ne;	down(&nodemgr_serialize);	ne = find_entry_by_nodeid(nodeid);	up(&nodemgr_serialize);	return ne;}/* 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 = kmalloc (sizeof (struct host_info), GFP_KERNEL);	unsigned long flags;	if (!hi) {		HPSB_ERR ("NodeMgr: out of memory in add host");		return;	}	/* Initialize the hostinfo here and start the thread.  The	 * thread blocks on the reset semaphore until a bus reset	 * happens. */	hi->host = host;	INIT_LIST_HEAD(&hi->list);	init_completion(&hi->exited);        sema_init(&hi->reset_sem, 0);	hi->pid = kernel_thread(nodemgr_host_thread, hi,				CLONE_FS | CLONE_FILES | CLONE_SIGHAND);		if (hi->pid < 0) {		HPSB_ERR ("NodeMgr: failed to start NodeMgr thread for %s",			  host->driver->name);		kfree(hi);		return;	}	spin_lock_irqsave (&host_info_lock, flags);	list_add_tail (&hi->list, &host_info_list);	spin_unlock_irqrestore (&host_info_lock, flags);	return;}static void nodemgr_host_reset(struct hpsb_host *host){	struct list_head *lh;	struct host_info *hi = NULL;	unsigned long flags;	spin_lock_irqsave (&host_info_lock, flags);	list_for_each(lh, &host_info_list) {		struct host_info *myhi = list_entry(lh, struct host_info, list);		if (myhi->host == host) {			hi = myhi;			break;		}	}	if (hi != NULL) {#ifdef CONFIG_IEEE1394_VERBOSEDEBUG		HPSB_DEBUG ("NodeMgr: Processing host reset for %s", host->driver->name);#endif		up(&hi->reset_sem);	} else		HPSB_ERR ("NodeMgr: could not process reset of non-existent host");	spin_unlock_irqrestore (&host_info_lock, flags);	return;}static void nodemgr_remove_host(struct hpsb_host *host){	struct list_head *lh, *next;	struct node_entry *ne;	unsigned long flags;	struct host_info *hi = NULL;	spin_lock_irqsave (&host_info_lock, flags);	list_for_each_safe(lh, next, &host_info_list) {		struct host_info *myhi = list_entry(lh, struct host_info, list);		if (myhi->host == host) {			list_del(&myhi->list);			hi = myhi;			break;		}	}	spin_unlock_irqrestore (&host_info_lock, flags);	if (hi) {		if (hi->pid >= 0) {			kill_proc(hi->pid, SIGTERM, 1);			wait_for_completion(&hi->exited);		}		kfree(hi);	}	else		HPSB_ERR("NodeMgr: host %s does not exist, cannot remove",			 host->driver->name);	down(&nodemgr_serialize);	/* Even if we fail the host_info part, remove all the node	 * entries.  */	list_for_each_safe(lh, next, &node_list) {		ne = list_entry(lh, struct node_entry, list);		if (ne->host == host)			nodemgr_remove_node(ne);	}	up(&nodemgr_serialize);	return;}static struct hpsb_highlevel_ops nodemgr_ops = {	.add_host =	nodemgr_add_host,	.host_reset =	nodemgr_host_reset,	.remove_host =	nodemgr_remove_host,};static struct hpsb_highlevel *hl;#define PROC_ENTRY "devices"void init_ieee1394_nodemgr(int disable_hotplug){	nodemgr_disable_hotplug = disable_hotplug;#ifdef CONFIG_PROC_FS	if (!create_proc_read_entry(PROC_ENTRY, 0444, ieee1394_procfs_entry, raw1394_read_proc, NULL))		HPSB_ERR("Can't create devices procfs entry");#endif        hl = hpsb_register_highlevel("Node manager", &nodemgr_ops);        if (!hl) {		HPSB_ERR("NodeMgr: out of memory during ieee1394 initialization");        }}void cleanup_ieee1394_nodemgr(void){        hpsb_unregister_highlevel(hl);#ifdef CONFIG_PROC_FS	remove_proc_entry(PROC_ENTRY, ieee1394_procfs_entry);#endif}

⌨️ 快捷键说明

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