nodemgr.c
来自「linux 内核源代码」· C语言 代码 · 共 1,910 行 · 第 1/4 页
C
1,910 行
} /* This implementation currently only scans the config rom and its * immediate unit directories looking for software_id and * software_version entries, in order to get driver autoloading working. */static struct unit_directory *nodemgr_process_unit_directory (struct host_info *hi, struct node_entry *ne, struct csr1212_keyval *ud_kv, unsigned int *id, struct unit_directory *parent){ struct unit_directory *ud; struct unit_directory *ud_child = NULL; struct csr1212_dentry *dentry; struct csr1212_keyval *kv; u8 last_key_id = 0; ud = kzalloc(sizeof(*ud), GFP_KERNEL); if (!ud) goto unit_directory_error; ud->ne = ne; ud->ignore_driver = ignore_drivers; ud->address = ud_kv->offset + CSR1212_REGISTER_SPACE_BASE; ud->directory_id = ud->address & 0xffffff; ud->ud_kv = ud_kv; ud->id = (*id)++; csr1212_for_each_dir_entry(ne->csr, kv, ud_kv, dentry) { switch (kv->key.id) { case CSR1212_KV_ID_VENDOR: if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) { ud->vendor_id = kv->value.immediate; ud->flags |= UNIT_DIRECTORY_VENDOR_ID; } break; case CSR1212_KV_ID_MODEL: ud->model_id = kv->value.immediate; ud->flags |= UNIT_DIRECTORY_MODEL_ID; break; case CSR1212_KV_ID_SPECIFIER_ID: ud->specifier_id = kv->value.immediate; ud->flags |= UNIT_DIRECTORY_SPECIFIER_ID; break; case CSR1212_KV_ID_VERSION: ud->version = kv->value.immediate; ud->flags |= UNIT_DIRECTORY_VERSION; break; case CSR1212_KV_ID_DESCRIPTOR: if (kv->key.type == CSR1212_KV_TYPE_LEAF && CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 && CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 && CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 && CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 && CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) { switch (last_key_id) { case CSR1212_KV_ID_VENDOR: csr1212_keep_keyval(kv); ud->vendor_name_kv = kv; break; case CSR1212_KV_ID_MODEL: csr1212_keep_keyval(kv); ud->model_name_kv = kv; break; } } /* else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) ... */ break; case CSR1212_KV_ID_DEPENDENT_INFO: /* Logical Unit Number */ if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) { if (ud->flags & UNIT_DIRECTORY_HAS_LUN) { ud_child = kmemdup(ud, sizeof(*ud_child), GFP_KERNEL); if (!ud_child) goto unit_directory_error; nodemgr_register_device(ne, ud_child, &ne->device); ud_child = NULL; ud->id = (*id)++; } ud->lun = kv->value.immediate; ud->flags |= UNIT_DIRECTORY_HAS_LUN; /* Logical Unit Directory */ } else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) { /* This should really be done in SBP2 as this is * doing SBP2 specific parsing. */ /* first register the parent unit */ ud->flags |= UNIT_DIRECTORY_HAS_LUN_DIRECTORY; if (ud->device.bus != &ieee1394_bus_type) nodemgr_register_device(ne, ud, &ne->device); /* process the child unit */ ud_child = nodemgr_process_unit_directory(hi, ne, kv, id, ud); if (ud_child == NULL) break; /* inherit unspecified values, the driver core picks it up */ if ((ud->flags & UNIT_DIRECTORY_MODEL_ID) && !(ud_child->flags & UNIT_DIRECTORY_MODEL_ID)) { ud_child->flags |= UNIT_DIRECTORY_MODEL_ID; ud_child->model_id = ud->model_id; } if ((ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) && !(ud_child->flags & UNIT_DIRECTORY_SPECIFIER_ID)) { ud_child->flags |= UNIT_DIRECTORY_SPECIFIER_ID; ud_child->specifier_id = ud->specifier_id; } if ((ud->flags & UNIT_DIRECTORY_VERSION) && !(ud_child->flags & UNIT_DIRECTORY_VERSION)) { ud_child->flags |= UNIT_DIRECTORY_VERSION; ud_child->version = ud->version; } /* register the child unit */ ud_child->flags |= UNIT_DIRECTORY_LUN_DIRECTORY; nodemgr_register_device(ne, ud_child, &ud->device); } break; case CSR1212_KV_ID_DIRECTORY_ID: ud->directory_id = kv->value.immediate; break; default: break; } last_key_id = kv->key.id; } /* do not process child units here and only if not already registered */ if (!parent && ud->device.bus != &ieee1394_bus_type) nodemgr_register_device(ne, ud, &ne->device); return ud;unit_directory_error: kfree(ud); return NULL;}static void nodemgr_process_root_directory(struct host_info *hi, struct node_entry *ne){ unsigned int ud_id = 0; struct csr1212_dentry *dentry; struct csr1212_keyval *kv, *vendor_name_kv = NULL; u8 last_key_id = 0; ne->needs_probe = 0; csr1212_for_each_dir_entry(ne->csr, kv, ne->csr->root_kv, dentry) { switch (kv->key.id) { case CSR1212_KV_ID_VENDOR: ne->vendor_id = kv->value.immediate; break; case CSR1212_KV_ID_NODE_CAPABILITIES: ne->capabilities = kv->value.immediate; break; case CSR1212_KV_ID_UNIT: nodemgr_process_unit_directory(hi, ne, kv, &ud_id, NULL); break; case CSR1212_KV_ID_DESCRIPTOR: if (last_key_id == CSR1212_KV_ID_VENDOR) { if (kv->key.type == CSR1212_KV_TYPE_LEAF && CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 && CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 && CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 && CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 && CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) { csr1212_keep_keyval(kv); vendor_name_kv = kv; } } break; } last_key_id = kv->key.id; } if (ne->vendor_name_kv) { kv = ne->vendor_name_kv; ne->vendor_name_kv = vendor_name_kv; csr1212_release_keyval(kv); } else if (vendor_name_kv) { ne->vendor_name_kv = vendor_name_kv; if (device_create_file(&ne->device, &dev_attr_ne_vendor_name_kv) != 0) HPSB_ERR("Failed to add sysfs attribute"); }}#ifdef CONFIG_HOTPLUGstatic int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env){ struct unit_directory *ud; int retval = 0; /* ieee1394:venNmoNspNverN */ char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1]; if (!dev) return -ENODEV; ud = container_of(dev, struct unit_directory, unit_dev); if (ud->ne->in_limbo || ud->ignore_driver) return -ENODEV;#define PUT_ENVP(fmt,val) \do { \ retval = add_uevent_var(env, fmt, val); \ if (retval) \ return retval; \} while (0) PUT_ENVP("VENDOR_ID=%06x", ud->vendor_id); PUT_ENVP("MODEL_ID=%06x", ud->model_id); PUT_ENVP("GUID=%016Lx", (unsigned long long)ud->ne->guid); PUT_ENVP("SPECIFIER_ID=%06x", ud->specifier_id); PUT_ENVP("VERSION=%06x", ud->version); snprintf(buf, sizeof(buf), "ieee1394:ven%08Xmo%08Xsp%08Xver%08X", ud->vendor_id, ud->model_id, ud->specifier_id, ud->version); PUT_ENVP("MODALIAS=%s", buf);#undef PUT_ENVP return 0;}#elsestatic int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env){ return -ENODEV;}#endif /* CONFIG_HOTPLUG */int __hpsb_register_protocol(struct hpsb_protocol_driver *drv, struct module *owner){ int error; drv->driver.bus = &ieee1394_bus_type; drv->driver.owner = owner; drv->driver.name = drv->name; /* This will cause a probe for devices */ error = driver_register(&drv->driver); if (!error) nodemgr_create_drv_files(drv); return error;}void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver){ nodemgr_remove_drv_files(driver); /* This will subsequently disconnect all devices that our driver * is attached to. */ driver_unregister(&driver->driver);}/* * This function updates nodes that were present on the bus before the * reset and still are after the reset. The nodeid and the config rom * may have changed, and the drivers managing this device must be * informed that this device just went through a bus reset, to allow * the to take whatever actions required. */static void nodemgr_update_node(struct node_entry *ne, struct csr1212_csr *csr, struct host_info *hi, nodeid_t nodeid, unsigned int generation){ if (ne->nodeid != nodeid) { HPSB_DEBUG("Node changed: " NODE_BUS_FMT " -> " NODE_BUS_FMT, NODE_BUS_ARGS(ne->host, ne->nodeid), NODE_BUS_ARGS(ne->host, nodeid)); ne->nodeid = nodeid; } if (ne->busopt.generation != ((be32_to_cpu(csr->bus_info_data[2]) >> 4) & 0xf)) { kfree(ne->csr->private); csr1212_destroy_csr(ne->csr); ne->csr = csr; /* If the node's configrom generation has changed, we * unregister all the unit directories. */ nodemgr_remove_uds(ne); nodemgr_update_bus_options(ne); /* Mark the node as new, so it gets re-probed */ ne->needs_probe = 1; } else { /* old cache is valid, so update its generation */ struct nodemgr_csr_info *ci = ne->csr->private; ci->generation = generation; /* free the partially filled now unneeded new cache */ kfree(csr->private); csr1212_destroy_csr(csr); } if (ne->in_limbo) nodemgr_resume_ne(ne); /* Mark the node current */ ne->generation = generation;}static void nodemgr_node_scan_one(struct host_info *hi, nodeid_t nodeid, int generation){ struct hpsb_host *host = hi->host; struct node_entry *ne; octlet_t guid; struct csr1212_csr *csr; struct nodemgr_csr_info *ci; u8 *speed; ci = kmalloc(sizeof(*ci), GFP_KERNEL); if (!ci) return; ci->host = host; ci->nodeid = nodeid; ci->generation = generation; /* Prepare for speed probe which occurs when reading the ROM */ speed = &(host->speed[NODEID_TO_NODE(nodeid)]); if (*speed > host->csr.lnk_spd) *speed = host->csr.lnk_spd; ci->speed_unverified = *speed > IEEE1394_SPEED_100; /* We need to detect when the ConfigROM's generation has changed, * so we only update the node's info when it needs to be. */ csr = csr1212_create_csr(&nodemgr_csr_ops, 5 * sizeof(quadlet_t), ci); if (!csr || csr1212_parse_csr(csr) != CSR1212_SUCCESS) { HPSB_ERR("Error parsing configrom for node " NODE_BUS_FMT, NODE_BUS_ARGS(host, nodeid)); if (csr) csr1212_destroy_csr(csr); kfree(ci); return; } if (csr->bus_info_data[1] != IEEE1394_BUSID_MAGIC) { /* This isn't a 1394 device, but we let it slide. There * was a report of a device with broken firmware which * reported '2394' instead of '1394', which is obviously a * mistake. One would hope that a non-1394 device never * gets connected to Firewire bus. If someone does, we * shouldn't be held responsible, so we'll allow it with a * warning. */ HPSB_WARN("Node " NODE_BUS_FMT " has invalid busID magic [0x%08x]", NODE_BUS_ARGS(host, nodeid), csr->bus_info_data[1]); } guid = ((u64)be32_to_cpu(csr->bus_info_data[3]) << 32) | be32_to_cpu(csr->bus_info_data[4]); ne = find_entry_by_guid(guid); if (ne && ne->host != host && ne->in_limbo) { /* Must have moved this device from one host to another */ nodemgr_remove_ne(ne); ne = NULL; } if (!ne) nodemgr_create_node(guid, csr, hi, nodeid, generation); else nodemgr_update_node(ne, csr, hi, nodeid, generation);}static void nodemgr_node_scan(struct host_info *hi, int generation){ int count; struct hpsb_host *host = hi->host; struct selfid *sid = (struct selfid *)host->topology_map; nodeid_t nodeid = LOCAL_BUS; /* Scan each node on the bus */ for (count = host->selfid_count; count; count--, sid++) { if (sid->extended) continue; if (!sid->link_active) { nodeid++; continue; } nodemgr_node_scan_one(hi, nodeid++, generation); }}static void nodemgr_suspend_ne(struct node_entry *ne){ struct device *dev; struct unit_directory *ud; struct device_driver *drv; int error; HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid); ne->in_limbo = 1; WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo)); 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 = 1; /* release if suspend is not implemented */ if (drv->suspend) { down(&ud->device.sem); error = drv->suspend(&ud->device, PMSG_SUSPEND); up(&ud->device.sem); } if (error) device_release_driver(&ud->device); put_driver(drv); } up(&nodemgr_ud_class.sem);}static void nodemgr_resume_ne(struct node_entry *ne){ struct device *dev; struct unit_directory *ud; struct device_driver *drv; ne->in_limbo = 0; device_remove_file(&ne->device, &dev_attr_ne_in_limbo); 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; if (drv->resume) { down(&ud->device.sem); drv->resume(&ud->device); up(&ud->device.sem); }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?