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

📄 nodemgr.c

📁 Ieee1394驱动实现
💻 C
📖 第 1 页 / 共 4 页
字号:
			drv->resume(&ud->device);
			up(&ud->device.sem);
		}
		put_driver(drv);
	}
	up(&nodemgr_ud_class.sem);

	HPSB_DEBUG("Node resumed: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
		   NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
}


static void nodemgr_update_pdrv(struct node_entry *ne)
{
	struct device *dev;
	struct unit_directory *ud;
	struct device_driver *drv;
	struct hpsb_protocol_driver *pdrv;
	int error;

	down(&nodemgr_ud_class.sem);
	list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
		ud = container_of(dev, struct unit_directory, unit_dev);
		if (ud->ne != ne)
			continue;

		drv = get_driver(ud->device.driver);
		if (!drv)
			continue;

		error = 0;
		pdrv = container_of(drv, struct hpsb_protocol_driver, driver);
		if (pdrv->update) {
			down(&ud->device.sem);
			error = pdrv->update(ud);
			up(&ud->device.sem);
		}
		if (error)
			device_release_driver(&ud->device);
		put_driver(drv);
	}
	up(&nodemgr_ud_class.sem);
}


/* Write the BROADCAST_CHANNEL as per IEEE1394a 8.3.2.3.11 and 8.4.2.3.  This
 * seems like an optional service but in the end it is practically mandatory
 * as a consequence of these clauses.
 *
 * Note that we cannot do a broadcast write to all nodes at once because some
 * pre-1394a devices would hang. */
static void nodemgr_irm_write_bc(struct node_entry *ne, int generation)
{
	const u64 bc_addr = (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL);
	quadlet_t bc_remote, bc_local;
	int error;

	if (!ne->host->is_irm || ne->generation != generation ||
	    ne->nodeid == ne->host->node_id)
		return;

	bc_local = cpu_to_be32(ne->host->csr.broadcast_channel);

	/* Check if the register is implemented and 1394a compliant. */
	error = hpsb_read(ne->host, ne->nodeid, generation, bc_addr, &bc_remote,
			  sizeof(bc_remote));
	if (!error && bc_remote & cpu_to_be32(0x80000000) &&
	    bc_remote != bc_local)
		hpsb_node_write(ne, bc_addr, &bc_local, sizeof(bc_local));
}


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;

	nodemgr_irm_write_bc(ne, generation);

	/* 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 device *dev;
	struct node_entry *ne;

	/* 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.
	 *
	 * Run updates before probes. Usually, updates are time-critical
	 * while probes are time-consuming. (Well, those probes need some
	 * improvement...) */

	down(&nodemgr_ne_class.sem);
	list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
		ne = container_of(dev, struct node_entry, node_dev);
		if (!ne->needs_probe)
			nodemgr_probe_ne(hi, ne, generation);
	}
	list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
		ne = container_of(dev, struct node_entry, node_dev);
		if (ne->needs_probe)
			nodemgr_probe_ne(hi, ne, generation);
	}
	up(&nodemgr_ne_class.sem);


	/* 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.  Another bus scan is 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))
		if (bus_rescan_devices(&ieee1394_bus_type))
			HPSB_DEBUG("bus_rescan_devices had an error");
}

static int nodemgr_send_resume_packet(struct hpsb_host *host)
{
	struct hpsb_packet *packet;
	int error = -ENOMEM;

	packet = hpsb_make_phypacket(host,
			EXTPHYPACKET_TYPE_RESUME |
			NODEID_TO_NODE(host->node_id) << PHYPACKET_PORT_SHIFT);
	if (packet) {
		packet->no_waiter = 1;
		packet->generation = get_hpsb_generation(host);
		error = hpsb_send_packet(packet);
	}
	if (error)
		HPSB_WARN("fw-host%d: Failed to broadcast resume packet",
			  host->id);
	return error;
}

/* Perform a few high-level IRM responsibilities. */
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;

	/* We are a 1394a-2000 compliant IRM. Set the validity bit. */
	host->csr.broadcast_channel |= 0x40000000;

	/* 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;

		/* get cycle master capability flag from root node */
		if (host->is_cycmst ||
		    (!hpsb_read(host, LOCAL_BUS | root_node, get_hpsb_generation(host),
				(CSR_REGISTER_BASE + CSR_CONFIG_ROM + 2 * sizeof(quadlet_t)),
				&bc, sizeof(quadlet_t)) &&
		     be32_to_cpu(bc) & 1 << CSR_CMC_SHIFT))
			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;
		}
	}

	/* Some devices suspend their ports while being connected to an inactive
	 * host adapter, i.e. if connected before the low-level driver is
	 * loaded.  They become visible either when physically unplugged and
	 * replugged, or when receiving a resume packet.  Send one once. */
	if (!host->resume_packet_sent && !nodemgr_send_resume_packet(host))
		host->resume_packet_sent = 1;

	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 (hpsb_disable_irm || 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;
	unsigned int g, generation = 0;
	int i, reset_cycles = 0;

	/* Setup our device-model entries */
	nodemgr_create_host_dev_files(host);

	for (;;) {
		/* Sleep until next bus reset */
		set_current_state(TASK_INTERRUPTIBLE);
		if (get_hpsb_generation(host) == generation &&
		    !kthread_should_stop())
			schedule();
		__set_current_state(TASK_RUNNING);

		/* Thread may have been woken up to freeze or to exit */
		if (try_to_freeze())
			continue;
		if (kthread_should_stop())
			goto exit;

		/* Pause for 1/4 second in 1/16 second intervals,
		 * to make sure things settle down. */
		g = get_hpsb_generation(host);
		for (i = 0; i < 4 ; i++) {
			if (msleep_interruptible(63) || kthread_should_stop())
				goto exit;

			/* 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 waiting over again */
			if (generation != g)
				g = generation, i = 0;
		}

		if (!nodemgr_check_irm_capability(host, reset_cycles) ||
		    !nodemgr_do_irm_duties(host, reset_cycles)) {
			reset_cycles++;
			continue;
		}
		reset_cycles = 0;

		/* Scan our nodes to get the bus options and create node
		 * entries. This does not do the sysfs stuff, since that
		 * would trigger uevents and such, which is a bad idea at
		 * this point. */
		nodemgr_node_scan(hi, generation);

		/* 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);
	}
exit:
	HPSB_VERBOSE("NodeMgr: Exiting thread");
	return 0;
}

/**
 * nodemgr_for_each_host - call a function for each IEEE 1394 host
 * @data: an address to supply to the callback
 * @cb: function to call for each host
 *
 * Iterate the hosts, calling a given function with supplied data for each host.
 * If the callback fails on a host, i.e. if it returns a non-zero value, the
 * iteration is stopped.
 *
 * Return value: 0 on success, non-zero on failure (same as returned by last run
 * of the callback).
 */
int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *))
{
	struct device *dev;
	struct hpsb_host *host;
	int error = 0;

	down(&hpsb_host_class.sem);
	list_for_each_entry(dev, &hpsb_host_class.devices, node) {
		host = container_of(dev, struct hpsb_host, host_dev);

		if ((error = cb(host, data)))
			break;
	}
	up(&hpsb_host_class.sem);

	return error;
}

/* The following two 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.
 */

/**
 * hpsb_node_fill_packet - fill some destination information into a packet
 * @ne: destination node
 * @packet: packet to fill in
 *
 * This will fill in the given, pre-initialised hpsb_packet with the current
 * information from the node entry (host, node ID, bus generation number).
 */
void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet)
{
	packet->host = ne->host;
	packet->generation = ne->generation;
	barrier();
	packet->node_id = ne->nodeid;
}

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);
}

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;
	hi->thread = kthread_run(nodemgr_host_thread, hi, "knodemgrd_%d",
				 host->id);
	if (IS_ERR(hi->thread)) {
		HPSB_ERR("NodeMgr: cannot start thread for host %d", host->id);
		hpsb_destroy_hostinfo(&nodemgr_highlevel, host);
	}
}

static void nodemgr_host_reset(struct hpsb_host *host)
{
	struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host);

	if (hi) {
		HPSB_VERBOSE("NodeMgr: Processing reset for host %d", host->id);
		wake_up_process(hi->thread);
	}
}

static void nodemgr_remove_host(struct hpsb_host *host)
{
	struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host);

	if (hi) {
		kthread_stop(hi->thread);
		nodemgr_remove_host_dev(&host->device);
	}
}

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 error;

	error = class_register(&nodemgr_ne_class);
	if (error)
		goto fail_ne;
	error = class_register(&nodemgr_ud_class);
	if (error)
		goto fail_ud;
	error = driver_register(&nodemgr_mid_layer_driver);
	if (error)
		goto fail_ml;
	/* This driver is not used if nodemgr is off (disable_nodemgr=1). */
	nodemgr_dev_template_host.driver = &nodemgr_mid_layer_driver;

	hpsb_register_highlevel(&nodemgr_highlevel);
	return 0;

fail_ml:
	class_unregister(&nodemgr_ud_class);
fail_ud:
	class_unregister(&nodemgr_ne_class);
fail_ne:
	return error;
}

void cleanup_ieee1394_nodemgr(void)
{
	hpsb_unregister_highlevel(&nodemgr_highlevel);
	driver_unregister(&nodemgr_mid_layer_driver);
	class_unregister(&nodemgr_ud_class);
	class_unregister(&nodemgr_ne_class);
}

⌨️ 快捷键说明

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