📄 nodemgr.c
字号:
down(&nodemgr_ud_class.sem); list_for_each_entry(cdev, &nodemgr_ud_class.children, node) { ud = container_of(cdev, struct unit_directory, class_dev); if (ud->ne != ne) continue; down_read(&ieee1394_bus_type.subsys.rwsem); if (ud->device.driver && ud->device.driver->resume) ud->device.driver->resume(&ud->device); up_read(&ieee1394_bus_type.subsys.rwsem); } 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 unit_directory *ud; struct hpsb_protocol_driver *pdrv; struct class_device *cdev; down(&nodemgr_ud_class.sem); list_for_each_entry(cdev, &nodemgr_ud_class.children, node) { ud = container_of(cdev, struct unit_directory, class_dev); if (ud->ne != ne) continue; down_write(&ieee1394_bus_type.subsys.rwsem); if (ud->device.driver) { pdrv = container_of(ud->device.driver, struct hpsb_protocol_driver, driver); if (pdrv->update && pdrv->update(ud)) device_release_driver(&ud->device); } up_write(&ieee1394_bus_type.subsys.rwsem); } 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 class_device *cdev; 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(cdev, &nodemgr_ne_class.children, node) { ne = container_of(cdev, struct node_entry, class_dev); if (!ne->needs_probe) nodemgr_probe_ne(hi, ne, generation); } list_for_each_entry(cdev, &nodemgr_ne_class.children, node) { ne = container_of(cdev, struct node_entry, class_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; if (mutex_lock_interruptible(&nodemgr_serialize)) { if (try_to_freeze()) continue; 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 unlock_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 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++; mutex_unlock(&nodemgr_serialize); 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); mutex_unlock(&nodemgr_serialize); }unlock_exit: mutex_unlock(&nodemgr_serialize);exit: HPSB_VERBOSE("NodeMgr: Exiting thread"); return 0;}int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *)){ struct class_device *cdev; struct hpsb_host *host; int error = 0; down(&hpsb_host_class.sem); list_for_each_entry(cdev, &hpsb_host_class.children, node) { host = container_of(cdev, struct hpsb_host, class_dev); if ((error = cb(host, __data))) break; } up(&hpsb_host_class.sem); return error;}/* 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_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 + -