nodemgr.c
来自「linux 内核源代码」· C语言 代码 · 共 1,910 行 · 第 1/4 页
C
1,910 行
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; set_freezable(); /* 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++) { msleep_interruptible(63); if (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 + =
减小字号Ctrl + -
显示快捷键?