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

📄 nodemgr.c

📁 idt mips 32365上面移植实现的iee1394驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
	list_add_tail(&driver->list, &driver_list);	write_unlock_irqrestore(&driver_lock, flags);	write_lock_irqsave(&unit_directory_lock, flags);	INIT_LIST_HEAD(&driver->unit_directories);	lh = unit_directory_list.next;	while (lh != &unit_directory_list) {		ud = list_entry(lh, struct unit_directory, driver_list);		lh = lh->next;		if (nodemgr_match_driver(driver, ud) && driver->probe(ud) == 0)			nodemgr_claim_unit_directory(ud, driver);	}	write_unlock_irqrestore(&unit_directory_lock, flags);	/*	 * Right now registration always succeeds, but maybe we should	 * detect clashes in protocols handled by other drivers.	 */	return 0;}void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver){	struct list_head *lh;	struct unit_directory *ud;	unsigned long flags;        write_lock_irqsave(&driver_lock, flags);	list_del(&driver->list);	write_unlock_irqrestore(&driver_lock, flags);	write_lock_irqsave(&unit_directory_lock, flags);	lh = driver->unit_directories.next;	while (lh != &driver->unit_directories) {		ud = list_entry(lh, struct unit_directory, driver_list);		lh = lh->next;		if (ud->driver && ud->driver->disconnect)			ud->driver->disconnect(ud);		nodemgr_release_unit_directory(ud);	}	write_unlock_irqrestore(&unit_directory_lock, flags);}static void nodemgr_process_config_rom(struct node_entry *ne, 				       quadlet_t busoptions){	unsigned long flags;	ne->busopt.irmc		= (busoptions >> 31) & 1;	ne->busopt.cmc		= (busoptions >> 30) & 1;	ne->busopt.isc		= (busoptions >> 29) & 1;	ne->busopt.bmc		= (busoptions >> 28) & 1;	ne->busopt.pmc		= (busoptions >> 27) & 1;	ne->busopt.cyc_clk_acc	= (busoptions >> 16) & 0xff;	ne->busopt.max_rec	= 1 << (((busoptions >> 12) & 0xf) + 1);	ne->busopt.generation	= (busoptions >> 4) & 0xf;	ne->busopt.lnkspd	= busoptions & 0x7;#ifdef CONFIG_IEEE1394_VERBOSEDEBUG	HPSB_DEBUG("NodeMgr: raw=0x%08x irmc=%d cmc=%d isc=%d bmc=%d pmc=%d "		   "cyc_clk_acc=%d max_rec=%d gen=%d lspd=%d",		   busoptions, ne->busopt.irmc, ne->busopt.cmc,		   ne->busopt.isc, ne->busopt.bmc, ne->busopt.pmc,		   ne->busopt.cyc_clk_acc, ne->busopt.max_rec,		   ne->busopt.generation, ne->busopt.lnkspd);#endif	/*	 * 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.	 */	write_lock_irqsave(&unit_directory_lock, flags);	nodemgr_free_unit_directories(ne);	nodemgr_process_root_directory(ne);	nodemgr_bind_drivers(ne);	write_unlock_irqrestore(&unit_directory_lock, flags);}/* * 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){	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 */	atomic_set(&ne->generation, get_hpsb_generation(ne->host));	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,			      quadlet_t *buffer, int buffer_length){	octlet_t base = CSR_REGISTER_BASE + CSR_CONFIG_ROM;	int retries = 3;	int header_count;	unsigned header_size;	quadlet_t quad;retry_configrom:	if (!retries--) {		HPSB_ERR("Giving up on node " NODE_BUS_FMT			 " for ConfigROM probe, too many errors",			 NODE_BUS_ARGS(nodeid));		return -1;	}	header_count = 0;	header_size = 0;#ifdef CONFIG_IEEE1394_VERBOSEDEBUG	HPSB_INFO("Initiating ConfigROM request for node " NODE_BUS_FMT,		  NODE_BUS_ARGS(nodeid));#endif	/* Now, 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.  */	if (hpsb_read(host, nodeid, base, &quad, 4)) {		HPSB_ERR("ConfigROM quadlet transaction error for node " NODE_BUS_FMT,			 NODE_BUS_ARGS(nodeid));		goto retry_configrom;	}	buffer[header_count++] = be32_to_cpu(quad);	header_size = buffer[0] >> 24;	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;	}	while (header_count <= header_size && header_count < buffer_length) {		if (hpsb_read(host, nodeid, base + (header_count<<2), &quad, 4)) {			HPSB_ERR("ConfigROM quadlet transaction error for " NODE_BUS_FMT,				 NODE_BUS_ARGS(nodeid));			goto retry_configrom;		}		buffer[header_count++] = be32_to_cpu(quad);	}	return 0;}static void nodemgr_remove_node(struct node_entry *ne){	unsigned long flags;	HPSB_DEBUG("Device removed: node " NODE_BUS_FMT ", GUID %016Lx",		   NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid);	write_lock_irqsave(&unit_directory_lock, flags);	nodemgr_free_unit_directories(ne);	write_unlock_irqrestore(&unit_directory_lock, flags);	list_del(&ne->list);	kfree(ne);	return;}/* Used to schedule each nodes config rom probe */struct node_probe_task {	nodeid_t nodeid;	struct hpsb_host *host;	atomic_t *count;	struct tq_struct task;};/* This is where we probe the nodes for their information and provided * features.  */static void nodemgr_node_probe_one(void *__npt){	struct node_probe_task *npt = (struct node_probe_task *)__npt;	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 (npt->host, npt->nodeid, buffer, sizeof(buffer) >> 2))		goto probe_complete;	if (buffer[1] != IEEE1394_BUSID_MAGIC) {		/* This isn't a 1394 device */		HPSB_ERR("Node " NODE_BUS_FMT " isn't an IEEE 1394 device",			 NODE_BUS_ARGS(npt->nodeid));		goto probe_complete;	}	guid = ((u64)buffer[3] << 32) | buffer[4];	ne = hpsb_guid_get_entry(guid);	if (!ne)		nodemgr_create_node(guid, buffer[2], npt->host, npt->nodeid);	else		nodemgr_update_node(ne, buffer[2], npt->host, npt->nodeid);probe_complete:	atomic_dec(npt->count);	kfree(npt);	return;}static void nodemgr_node_probe_cleanup(void *__npt){	struct node_probe_task *npt = (struct node_probe_task *)__npt;	unsigned long flags;	struct list_head *lh, *next;	struct node_entry *ne;	/* If things aren't done yet, reschedule ourselves. */        if (atomic_read(npt->count)) {                schedule_task(&npt->task);		return;	}	kfree(npt->count);	/* Now check to see if we have any nodes that aren't referenced	 * any longer.  */	write_lock_irqsave(&node_lock, flags);	for (lh = node_list.next; lh != &node_list; lh = next) {		ne = list_entry(lh, struct node_entry, list);		next = lh->next;		/* Only checking this host */		if (ne->host != npt->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 (!hpsb_node_entry_valid(ne))			nodemgr_remove_node(ne);	}	write_unlock_irqrestore(&node_lock, flags);	kfree(npt);	return;}static void nodemgr_node_probe(void *__host){	struct hpsb_host *host = (struct hpsb_host *)__host;	int nodecount = host->node_count;	struct selfid *sid = (struct selfid *)host->topology_map;	nodeid_t nodeid = LOCAL_BUS;	struct node_probe_task *npt;	atomic_t *count;	count = kmalloc(sizeof (*count), GFP_KERNEL);	if (count == NULL) {		HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe");		return;	}	atomic_set(count, 0);	for (; nodecount; nodecount--, nodeid++, sid++) {		while (sid->extended)			sid++;		if (!sid->link_active || nodeid == host->node_id)			continue;		npt = kmalloc(sizeof (*npt), GFP_KERNEL);		if (npt == NULL) {			HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe");			break;		}		INIT_TQUEUE(&npt->task, nodemgr_node_probe_one, npt);		npt->host = host;		npt->nodeid = nodeid;		npt->count = count;		atomic_inc(count);		schedule_task(&npt->task);	}	/* Now schedule a task to clean things up after the node probes	 * are done.  */	npt = kmalloc (sizeof (*npt), GFP_KERNEL);	if (npt == NULL) {		HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe");		return;	}	INIT_TQUEUE(&npt->task, nodemgr_node_probe_cleanup, npt);	npt->host = host;	npt->nodeid = 0;	npt->count = count;	schedule_task(&npt->task);	return;}struct node_entry *hpsb_guid_get_entry(u64 guid){        unsigned long flags;        struct node_entry *ne;        read_lock_irqsave(&node_lock, flags);        ne = find_entry_by_guid(guid);        read_unlock_irqrestore(&node_lock, flags);        return ne;}struct node_entry *hpsb_nodeid_get_entry(nodeid_t nodeid){	unsigned long flags;	struct node_entry *ne;	read_lock_irqsave(&node_lock, flags);	ne = find_entry_by_nodeid(nodeid);	read_unlock_irqrestore(&node_lock, flags);	return ne;}struct hpsb_host *hpsb_get_host_by_ne(struct node_entry *ne){        if (atomic_read(&ne->generation) != get_hpsb_generation(ne->host))		return NULL;        if (ne->nodeid == ne->host->node_id) return ne->host;        return NULL;}int hpsb_guid_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt){        if (atomic_read(&ne->generation) != get_hpsb_generation(ne->host))		return 0;        pkt->host = ne->host;        pkt->node_id = ne->nodeid;        pkt->generation = atomic_read(&ne->generation);        return 1;}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;	}	/* We simply initialize the struct here. We don't start the thread	 * until the first bus reset.  */	hi->host = host;	INIT_LIST_HEAD(&hi->list);	INIT_TQUEUE(&hi->task, nodemgr_node_probe, host);	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) {		HPSB_ERR ("NodeMgr: could not process reset of non-existent host");		goto done_reset_host;	}	schedule_task(&hi->task);done_reset_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;	/* Make sure we have no active scans */	flush_scheduled_tasks();	/* First remove all node entries for this host */	write_lock_irqsave(&node_lock, flags);	for (lh = node_list.next; lh != &node_list; lh = next) {		ne = list_entry(lh, struct node_entry, list);		next = lh->next;		/* Only checking this host */		if (ne->host != host)			continue;		nodemgr_remove_node(ne);	}	write_unlock_irqrestore(&node_lock, flags);	spin_lock_irqsave (&host_info_lock, flags);	list_for_each_safe(lh, next, &host_info_list) {		struct host_info *hi = list_entry(lh, struct host_info, list);		if (hi->host == host) {			list_del(&hi->list);			kfree (hi);			break;		}	}	if (lh == host_info_list.next)		HPSB_ERR ("NodeMgr: could not remove non-existent host");	spin_unlock_irqrestore (&host_info_lock, flags);	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;void init_ieee1394_nodemgr(void){        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);}

⌨️ 快捷键说明

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