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

📄 nodemgr.c

📁 1394在linux下单独的驱动程序代码
💻 C
📖 第 1 页 / 共 3 页
字号:
								unsigned int generation){	struct list_head *lh;	struct unit_directory *ud;		if (ne->nodeid != nodeid) {		HPSB_DEBUG("Node changed: " NODE_BUS_FMT " -> " NODE_BUS_FMT,			NODE_BUS_ARGS(ne->host, ne->nodeid),			NODE_BUS_ARGS(ne->host, nodeid));		ne->nodeid = nodeid;	}		ne->generation = generation;		if (ne->busopt.generation != ((busoptions >> 4) & 0xf))		nodemgr_process_config_rom (ne, busoptions);		list_for_each (lh, &ne->unit_directories) {		ud = list_entry (lh, struct unit_directory, node_list);		if (ud->driver && 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.  */		HPSB_VERBOSE("Initiating ConfigROM request for node " NODE_BUS_FMT,		NODE_BUS_ARGS(host, nodeid));			/* 		* 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(host, 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 == 1) {		HPSB_INFO("Node " NODE_BUS_FMT " has a minimal ROM.  "			"Vendor is %08x",			NODE_BUS_ARGS(host, nodeid), buffer[0] & 0x00ffffff);		return -1;	}		if (header_size < 4) {		HPSB_INFO("Node " NODE_BUS_FMT " has non-standard ROM "			"format (%d quads), cannot parse",			NODE_BUS_ARGS(host, 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(host, nodeid));			return -1;		}	}		return 0;}		static void nodemgr_remove_node(struct node_entry *ne){	HPSB_DEBUG("Node removed: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",		NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);		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 host_info *hi,								   nodeid_t nodeid, int generation){	struct hpsb_host *host = hi->host;	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(host, nodeid), buffer[1]);	}		guid = ((u64)buffer[3] << 32) | buffer[4];	ne = find_entry_by_guid(guid);		if (!ne)		nodemgr_create_node(guid, buffer[2], hi, nodeid, generation);	else		nodemgr_update_node(ne, buffer[2], hi, 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 host_info *hi, int generation){	int count;	struct hpsb_host *host = hi->host;	struct selfid *sid = (struct selfid *)host->topology_map;	nodeid_t nodeid = LOCAL_BUS;		/* 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(hi, 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;}/* 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 void nodemgr_do_irm_duties(struct hpsb_host *host){	quadlet_t bc;		if (!host->is_irm)		return;		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...");			hpsb_send_phy_config(host, NODEID_TO_NODE(host->node_id), -1);			hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);		}	}}/* 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();		strcpy(current->comm, hi->daemon_name);		/* 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)) {		unsigned int generation = 0;		int i;				/* 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;		}				if (!nodemgr_check_irm_capability(host, reset_cycles++)) {			/* Do nothing, we are resetting */			up(&nodemgr_serialize);			continue;		}				reset_cycles = 0;				nodemgr_node_probe(hi, generation);		nodemgr_do_irm_duties(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;}/* 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_FS | CLONE_FILES | CLONE_SIGHAND);		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 list_head *lh, *next;	struct node_entry *ne;	struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host);		if (hi) {		if (hi->pid >= 0) {			kill_proc(hi->pid, SIGTERM, 1);			wait_for_completion(&hi->exited);		}	} 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 nodemgr_highlevel = {	.name =		"Node manager",		.add_host =	nodemgr_add_host,		.host_reset =	nodemgr_host_reset,		.remove_host =	nodemgr_remove_host,};#define PROC_ENTRY "devices"void init_ieee1394_nodemgr(void){#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	hpsb_register_highlevel(&nodemgr_highlevel);}void cleanup_ieee1394_nodemgr(void){	hpsb_unregister_highlevel(&nodemgr_highlevel);#ifdef CONFIG_PROC_FS	remove_proc_entry(PROC_ENTRY, ieee1394_procfs_entry);#endif}

⌨️ 快捷键说明

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