📄 nodemgr.c
字号:
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 + -