nodemgr.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,745 行 · 第 1/4 页
C
1,745 行
}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; /* 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 *class = &nodemgr_ne_class; struct class_device *cdev; /* 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. */ down_read(&class->subsys.rwsem); list_for_each_entry(cdev, &class->children, node) nodemgr_probe_ne(hi, container_of(cdev, struct node_entry, class_dev), generation); up_read(&class->subsys.rwsem); /* 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. * * 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)) bus_rescan_devices(&ieee1394_bus_type); 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 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; 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..."); 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;}/* 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(hi->daemon_name); /* Setup our device-model entries */ nodemgr_create_host_dev_files(host); /* Sit and wait for a signal to probe the nodes on the bus. This * happens when we get a bus reset. */ while (1) { unsigned int generation = 0; int i; if (down_interruptible(&hi->reset_sem) || down_interruptible(&nodemgr_serialize)) { if (current->flags & PF_FREEZE) { refrigerator(0); continue; } printk("NodeMgr: received unexpected signal?!\n" ); break; } if (hi->kill_me) break; /* 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; /* Check the kill_me again */ if (hi->kill_me) goto caught_signal; } if (!nodemgr_check_irm_capability(host, reset_cycles)) { reset_cycles++; up(&nodemgr_serialize); continue; } /* Scan our nodes to get the bus options and create node * entries. This does not do the sysfs stuff, since that * would trigger hotplug callbacks and such, which is a * bad idea at this point. */ nodemgr_node_scan(hi, generation); if (!nodemgr_do_irm_duties(host, reset_cycles)) { reset_cycles++; up(&nodemgr_serialize); continue; } reset_cycles = 0; /* 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); 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;}int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *)){ struct class *class = &hpsb_host_class; struct class_device *cdev; struct hpsb_host *host; int error = 0; down_read(&class->subsys.rwsem); list_for_each_entry(cdev, &class->children, node) { host = container_of(cdev, struct hpsb_host, class_dev); if ((error = cb(host, __data))) break; } up_read(&class->subsys.rwsem); 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_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_KERNEL); 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 host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host); if (hi) { if (hi->pid >= 0) { hi->kill_me = 1; mb(); up(&hi->reset_sem); wait_for_completion(&hi->exited); nodemgr_remove_host_dev(&host->device); } } else HPSB_ERR("NodeMgr: host %s does not exist, cannot remove", host->driver->name); 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,};int init_ieee1394_nodemgr(void){ int ret; ret = class_register(&nodemgr_ne_class); if (ret < 0) return ret; ret = class_register(&nodemgr_ud_class); if (ret < 0) { class_unregister(&nodemgr_ne_class); return ret; } hpsb_register_highlevel(&nodemgr_highlevel); return 0;}void cleanup_ieee1394_nodemgr(void){ hpsb_unregister_highlevel(&nodemgr_highlevel); class_unregister(&nodemgr_ud_class); class_unregister(&nodemgr_ne_class);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?