/* Read power domain data */ static void remove_domain_devices(struct acpi_power_meter_resource *resource) { int i; if (!resource->num_domain_devices) return; for (i = 0; i < resource->num_domain_devices; i++) { struct acpi_device *obj = resource->domain_devices[i]; if (!obj) continue; sysfs_remove_link(resource->holders_dir, kobject_name(&obj->dev.kobj)); put_device(&obj->dev); } kfree(resource->domain_devices); kobject_put(resource->holders_dir); resource->num_domain_devices = 0; }
/* * __device_release_driver() must be called with @dev->sem held. * When called for a USB interface, @dev->parent->sem must be held as well. */ static void __device_release_driver(struct device *dev) { struct device_driver *drv; drv = dev->driver; if (drv) { driver_sysfs_remove(dev); sysfs_remove_link(&dev->kobj, "driver"); if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_UNBIND_DRIVER, dev); if (dev->bus && dev->bus->remove) dev->bus->remove(dev); else if (drv->remove) drv->remove(dev); devres_release_all(dev); dev->driver = NULL; klist_remove(&dev->knode_driver); } }
static int __acpi_processor_start(struct acpi_device *device) { struct acpi_processor *pr = acpi_driver_data(device); acpi_status status; int result = 0; if (!pr) return -ENODEV; if (pr->flags.need_hotplug_init) return 0; #ifdef CONFIG_CPU_FREQ acpi_processor_ppc_has_changed(pr, 0); acpi_processor_load_module(pr); #endif acpi_processor_get_throttling_info(pr); acpi_processor_get_limit_info(pr); if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver) acpi_processor_power_init(pr); pr->cdev = thermal_cooling_device_register("Processor", device, &processor_cooling_ops); if (IS_ERR(pr->cdev)) { result = PTR_ERR(pr->cdev); goto err_power_exit; } dev_dbg(&device->dev, "registered as cooling_device%d\n", pr->cdev->id); result = sysfs_create_link(&device->dev.kobj, &pr->cdev->device.kobj, "thermal_cooling"); if (result) { dev_err(&device->dev, "Failed to create sysfs link 'thermal_cooling'\n"); goto err_thermal_unregister; } result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj, "device"); if (result) { dev_err(&pr->cdev->device, "Failed to create sysfs link 'device'\n"); goto err_remove_sysfs_thermal; } status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, acpi_processor_notify, device); if (ACPI_SUCCESS(status)) return 0; sysfs_remove_link(&pr->cdev->device.kobj, "device"); err_remove_sysfs_thermal: sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); err_thermal_unregister: thermal_cooling_device_unregister(pr->cdev); err_power_exit: acpi_processor_power_exit(pr); return result; }
/** * pdcspath_hwpath_write - This function handles hardware path modifying. * @entry: An allocated and populated pdscpath_entry struct. * @buf: The input buffer to read from. * @count: The number of bytes to be read. * * We will call this function to change the current hardware path. * Hardware paths are to be given '/'-delimited, without brackets. * We make sure that the provided path actually maps to an existing * device, BUT nothing would prevent some foolish user to set the path to some * PCI bridge or even a CPU... * A better work around would be to make sure we are at the end of a device tree * for instance, but it would be IMHO beyond the simple scope of that driver. * The aim is to provide a facility. Data correctness is left to userland. */ static ssize_t pdcspath_hwpath_write(struct pdcspath_entry *entry, const char *buf, size_t count) { struct hardware_path hwpath; unsigned short i; char in[count+1], *temp; struct device *dev; int ret; if (!entry || !buf || !count) return -EINVAL; /* We'll use a local copy of buf */ memset(in, 0, count+1); strncpy(in, buf, count); /* Let's clean up the target. 0xff is a blank pattern */ memset(&hwpath, 0xff, sizeof(hwpath)); /* First, pick the mod field (the last one of the input string) */ if (!(temp = strrchr(in, '/'))) return -EINVAL; hwpath.mod = simple_strtoul(temp+1, NULL, 10); in[temp-in] = '\0'; /* truncate the remaining string. just precaution */ DPRINTK("%s: mod: %d\n", __func__, hwpath.mod); /* Then, loop for each delimiter, making sure we don't have too many. we write the bc fields in a down-top way. No matter what, we stop before writing the last field. If there are too many fields anyway, then the user is a moron and it'll be caught up later when we'll check the consistency of the given hwpath. */ for (i=5; ((temp = strrchr(in, '/'))) && (temp-in > 0) && (likely(i)); i--) { hwpath.bc[i] = simple_strtoul(temp+1, NULL, 10); in[temp-in] = '\0'; DPRINTK("%s: bc[%d]: %d\n", __func__, i, hwpath.bc[i]); } /* Store the final field */ hwpath.bc[i] = simple_strtoul(in, NULL, 10); DPRINTK("%s: bc[%d]: %d\n", __func__, i, hwpath.bc[i]); /* Now we check that the user isn't trying to lure us */ if (!(dev = hwpath_to_device((struct hardware_path *)&hwpath))) { printk(KERN_WARNING "%s: attempt to set invalid \"%s\" " "hardware path: %s\n", __func__, entry->name, buf); return -EINVAL; } /* So far so good, let's get in deep */ write_lock(&entry->rw_lock); entry->ready = 0; entry->dev = dev; /* Now, dive in. Write back to the hardware */ pdcspath_store(entry); /* Update the symlink to the real device */ sysfs_remove_link(&entry->kobj, "device"); ret = sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device"); WARN_ON(ret); write_unlock(&entry->rw_lock); printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" path to \"%s\"\n", entry->name, buf); return count; }
list_for_each_entry_safe(data, n, kobj_list, node) { list_del(&data->node); if (data->hdr->id == id_nic) sysfs_remove_link(&data->kobj, "device"); kobject_put(&data->kobj); };
/* Line6 device disconnected. */ static void line6_disconnect(struct usb_interface *interface) { struct usb_line6 *line6; struct usb_device *usbdev; int interface_number; if (interface == NULL) return; usbdev = interface_to_usbdev(interface); if (usbdev == NULL) return; /* removal of additional special files should go here */ sysfs_remove_link(&interface->dev.kobj, "usb_device"); interface_number = interface->cur_altsetting->desc.bInterfaceNumber; line6 = usb_get_intfdata(interface); if (line6 != NULL) { if (line6->urb_listen != NULL) line6_stop_listen(line6); if (usbdev != line6->usbdev) dev_err(line6->ifcdev, "driver bug: inconsistent usb device\n"); switch (line6->usbdev->descriptor.idProduct) { case LINE6_DEVID_BASSPODXT: case LINE6_DEVID_BASSPODXTLIVE: case LINE6_DEVID_BASSPODXTPRO: case LINE6_DEVID_POCKETPOD: case LINE6_DEVID_PODX3: case LINE6_DEVID_PODX3LIVE: case LINE6_DEVID_PODXT: case LINE6_DEVID_PODXTPRO: line6_pod_disconnect(interface); break; case LINE6_DEVID_PODHD300: case LINE6_DEVID_PODHD500: line6_podhd_disconnect(interface); break; case LINE6_DEVID_PODXTLIVE: switch (interface_number) { case PODXTLIVE_INTERFACE_POD: line6_pod_disconnect(interface); break; case PODXTLIVE_INTERFACE_VARIAX: line6_variax_disconnect(interface); break; } break; case LINE6_DEVID_VARIAX: line6_variax_disconnect(interface); break; case LINE6_DEVID_PODSTUDIO_GX: case LINE6_DEVID_PODSTUDIO_UX1: case LINE6_DEVID_PODSTUDIO_UX2: case LINE6_DEVID_TONEPORT_GX: case LINE6_DEVID_TONEPORT_UX1: case LINE6_DEVID_TONEPORT_UX2: case LINE6_DEVID_GUITARPORT: line6_toneport_disconnect(interface); break; default: MISSING_CASE; } dev_info(&interface->dev, "Line6 %s now disconnected\n", line6->properties->name); } line6_destruct(interface); /* decrement reference counters: */ usb_put_intf(interface); usb_put_dev(usbdev); }
void ath10k_thermal_unregister(struct ath10k *ar) { sysfs_remove_link(&ar->dev->kobj, "cooling_device"); thermal_cooling_device_unregister(ar->thermal.cdev); }
/* Line6 device disconnected. */ static void line6_disconnect(struct usb_interface *interface) { struct usb_line6 *line6; struct usb_device *usbdev; int interface_number, i; if (interface == NULL) return; usbdev = interface_to_usbdev(interface); if (usbdev == NULL) return; sysfs_remove_link(&interface->dev.kobj, "usb_device"); interface_number = interface->cur_altsetting->desc.bInterfaceNumber; line6 = usb_get_intfdata(interface); if (line6 != NULL) { if (line6->urb_listen != NULL) usb_kill_urb(line6->urb_listen); if (usbdev != line6->usbdev) dev_err(line6->ifcdev, "driver bug: inconsistent usb device\n"); switch (line6->usbdev->descriptor.idProduct) { case LINE6_DEVID_BASSPODXT: case LINE6_DEVID_BASSPODXTLIVE: case LINE6_DEVID_BASSPODXTPRO: case LINE6_DEVID_POCKETPOD: case LINE6_DEVID_PODX3: case LINE6_DEVID_PODX3LIVE: case LINE6_DEVID_PODXT: case LINE6_DEVID_PODXTPRO: pod_disconnect(interface); break; case LINE6_DEVID_PODXTLIVE: switch (interface_number) { case PODXTLIVE_INTERFACE_POD: pod_disconnect(interface); break; case PODXTLIVE_INTERFACE_VARIAX: variax_disconnect(interface); break; } break; case LINE6_DEVID_VARIAX: variax_disconnect(interface); break; case LINE6_DEVID_TONEPORT_GX: case LINE6_DEVID_TONEPORT_UX1: case LINE6_DEVID_TONEPORT_UX2: case LINE6_DEVID_GUITARPORT: toneport_disconnect(interface); break; default: MISSING_CASE; } dev_info(&interface->dev, "Line6 %s now disconnected\n", line6->properties->name); for (i = LINE6_MAX_DEVICES; i--;) if (line6_devices[i] == line6) line6_devices[i] = NULL; } line6_destruct(interface); /* decrement reference counters: */ usb_put_intf(interface); usb_put_dev(usbdev); line6_list_devices(); }
void sysfs_remove_device_from_node(struct device *dev, int nid) { struct node *node = node_devices[nid]; sysfs_remove_link(&node->dev.kobj, kobject_name(&dev->kobj)); }
static int __cpuinit acpi_processor_add(struct acpi_device *device) { struct acpi_processor *pr = NULL; int result = 0; struct sys_device *sysdev; pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL); if (!pr) return -ENOMEM; if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) { kfree(pr); return -ENOMEM; } pr->handle = device->handle; strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS); device->driver_data = pr; processor_extcntl_init(); result = acpi_processor_get_info(device); if (result || ((pr->id == -1) && !processor_cntl_external())) { /* Processor is physically not present */ return 0; } BUG_ON(!processor_cntl_external() && ((pr->id >= nr_cpu_ids) || (pr->id < 0))); /* * Buggy BIOS check * ACPI id of processors can be reported wrongly by the BIOS. * Don't trust it blindly */ #ifndef CONFIG_XEN if (per_cpu(processor_device_array, pr->id) != NULL && per_cpu(processor_device_array, pr->id) != device) { #else BUG_ON(pr->acpi_id >= NR_ACPI_CPUS); if (processor_device_array[pr->acpi_id] != NULL && processor_device_array[pr->acpi_id] != device) { #endif printk(KERN_WARNING "BIOS reported wrong ACPI id " "for the processor\n"); result = -ENODEV; goto err_free_cpumask; } #ifndef CONFIG_XEN per_cpu(processor_device_array, pr->id) = device; per_cpu(processors, pr->id) = pr; #else processor_device_array[pr->acpi_id] = device; if (pr->id != -1) per_cpu(processors, pr->id) = pr; #endif result = acpi_processor_add_fs(device); if (result) goto err_free_cpumask; if (pr->id != -1) { sysdev = get_cpu_sysdev(pr->id); if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev")) { result = -EFAULT; goto err_remove_fs; } } /* _PDC call should be done before doing anything else (if reqd.). */ arch_acpi_processor_init_pdc(pr); acpi_processor_set_pdc(pr); arch_acpi_processor_cleanup_pdc(pr); #if defined(CONFIG_CPU_FREQ) || defined(CONFIG_PROCESSOR_EXTERNAL_CONTROL) acpi_processor_ppc_has_changed(pr); #endif /* * pr->id may equal to -1 while processor_cntl_external enabled. * throttle and thermal module don't support this case. * Tx only works when dom0 vcpu == pcpu num by far, as we give * control to dom0. */ if (pr->id != -1) { acpi_processor_get_throttling_info(pr); acpi_processor_get_limit_info(pr); } acpi_processor_power_init(pr, device); result = processor_extcntl_prepare(pr); if (result) goto err_power_exit; pr->cdev = thermal_cooling_device_register("Processor", device, &processor_cooling_ops); if (IS_ERR(pr->cdev)) { result = PTR_ERR(pr->cdev); goto err_power_exit; } dev_info(&device->dev, "registered as cooling_device%d\n", pr->cdev->id); result = sysfs_create_link(&device->dev.kobj, &pr->cdev->device.kobj, "thermal_cooling"); if (result) { printk(KERN_ERR PREFIX "Create sysfs link\n"); goto err_thermal_unregister; } result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj, "device"); if (result) { printk(KERN_ERR PREFIX "Create sysfs link\n"); goto err_remove_sysfs; } return 0; err_remove_sysfs: sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); err_thermal_unregister: thermal_cooling_device_unregister(pr->cdev); err_power_exit: acpi_processor_power_exit(pr, device); err_remove_fs: acpi_processor_remove_fs(device); err_free_cpumask: free_cpumask_var(pr->throttling.shared_cpu_map); return result; } static int acpi_processor_remove(struct acpi_device *device, int type) { struct acpi_processor *pr = NULL; if (!device || !acpi_driver_data(device)) return -EINVAL; pr = acpi_driver_data(device); if (!processor_cntl_external() && pr->id >= nr_cpu_ids) goto free; if (type == ACPI_BUS_REMOVAL_EJECT) { if (acpi_processor_handle_eject(pr)) return -EINVAL; } acpi_processor_power_exit(pr, device); if (pr->id != -1) sysfs_remove_link(&device->dev.kobj, "sysdev"); acpi_processor_remove_fs(device); if (pr->cdev) { sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); sysfs_remove_link(&pr->cdev->device.kobj, "device"); thermal_cooling_device_unregister(pr->cdev); pr->cdev = NULL; } #ifndef CONFIG_XEN per_cpu(processors, pr->id) = NULL; per_cpu(processor_device_array, pr->id) = NULL; #else if (pr->id != -1) per_cpu(processors, pr->id) = NULL; processor_device_array[pr->acpi_id] = NULL; #endif free: free_cpumask_var(pr->throttling.shared_cpu_map); kfree(pr); return 0; } #ifdef CONFIG_ACPI_HOTPLUG_CPU /**************************************************************************** * Acpi processor hotplug support * ****************************************************************************/ static int is_processor_present(acpi_handle handle) { acpi_status status; unsigned long long sta = 0; status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_PRESENT)) return 1; /* * _STA is mandatory for a processor that supports hot plug */ if (status == AE_NOT_FOUND) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor does not support hot plug\n")); else ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present")); return 0; }
/** * pci_hp_remove_link - remove symbolic link to the hotplug driver module. * @pci_slot: struct pci_slot * * Helper function for pci_hotplug_core.c to remove symbolic link to * the hotplug driver module. */ void pci_hp_remove_module_link(struct pci_slot *pci_slot) { sysfs_remove_link(&pci_slot->kobj, "module"); }
void op_sysfs_remove_link(struct kobject *kobj, const char *name) { sysfs_remove_link(kobj, name); }
static ssize_t pdcspath_hwpath_write(struct pdcspath_entry *entry, const char *buf, size_t count) { struct hardware_path hwpath; unsigned short i; char in[count+1], *temp; struct device *dev; int ret; if (!entry || !buf || !count) return -EINVAL; memset(in, 0, count+1); strncpy(in, buf, count); memset(&hwpath, 0xff, sizeof(hwpath)); if (!(temp = strrchr(in, '/'))) return -EINVAL; hwpath.mod = simple_strtoul(temp+1, NULL, 10); in[temp-in] = '\0'; DPRINTK("%s: mod: %d\n", __func__, hwpath.mod); for (i=5; ((temp = strrchr(in, '/'))) && (temp-in > 0) && (likely(i)); i--) { hwpath.bc[i] = simple_strtoul(temp+1, NULL, 10); in[temp-in] = '\0'; DPRINTK("%s: bc[%d]: %d\n", __func__, i, hwpath.bc[i]); } hwpath.bc[i] = simple_strtoul(in, NULL, 10); DPRINTK("%s: bc[%d]: %d\n", __func__, i, hwpath.bc[i]); if (!(dev = hwpath_to_device((struct hardware_path *)&hwpath))) { printk(KERN_WARNING "%s: attempt to set invalid \"%s\" " "hardware path: %s\n", __func__, entry->name, buf); return -EINVAL; } write_lock(&entry->rw_lock); entry->ready = 0; entry->dev = dev; pdcspath_store(entry); sysfs_remove_link(&entry->kobj, "device"); ret = sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device"); WARN_ON(ret); write_unlock(&entry->rw_lock); printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" path to \"%s\"\n", entry->name, buf); return count; }
/* * Do not put anything in here which needs the core to be online. * For example MSR access or setting up things which check for cpuinfo_x86 * (cpu_data(cpu)) values, like CPU feature flags, family, model, etc. * Such things have to be put in and set up above in acpi_processor_start() */ static int __cpuinit acpi_processor_add(struct acpi_device *device) { struct acpi_processor *pr = NULL; int result = 0; struct device *dev; pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL); if (!pr) return -ENOMEM; if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) { result = -ENOMEM; goto err_free_pr; } pr->handle = device->handle; strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS); device->driver_data = pr; result = acpi_processor_get_info(device); if (result) { /* Processor is physically not present */ return 0; } #ifdef CONFIG_SMP if (pr->id >= setup_max_cpus && pr->id != 0) return 0; #endif BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0)); /* * Buggy BIOS check * ACPI id of processors can be reported wrongly by the BIOS. * Don't trust it blindly */ if (per_cpu(processor_device_array, pr->id) != NULL && per_cpu(processor_device_array, pr->id) != device) { printk(KERN_WARNING "BIOS reported wrong ACPI id " "for the processor\n"); result = -ENODEV; goto err_free_cpumask; } per_cpu(processor_device_array, pr->id) = device; per_cpu(processors, pr->id) = pr; dev = get_cpu_device(pr->id); if (sysfs_create_link(&device->dev.kobj, &dev->kobj, "sysdev")) { result = -EFAULT; goto err_clear_processor; } /* * Do not start hotplugged CPUs now, but when they * are onlined the first time */ if (pr->flags.need_hotplug_init) return 0; result = acpi_processor_start(pr); if (result) goto err_remove_sysfs; return 0; err_remove_sysfs: sysfs_remove_link(&device->dev.kobj, "sysdev"); err_clear_processor: /* * processor_device_array is not cleared to allow checks for buggy BIOS */ per_cpu(processors, pr->id) = NULL; err_free_cpumask: free_cpumask_var(pr->throttling.shared_cpu_map); err_free_pr: kfree(pr); return result; }
static int link_peers(struct usb_port *left, struct usb_port *right) { struct usb_port *ss_port, *hs_port; int rc; if (left->peer == right && right->peer == left) return 0; if (left->peer || right->peer) { struct usb_port *lpeer = left->peer; struct usb_port *rpeer = right->peer; char *method; if (left->location && left->location == right->location) method = "location"; else method = "default"; pr_warn("usb: failed to peer %s and %s by %s (%s:%s) (%s:%s)\n", dev_name(&left->dev), dev_name(&right->dev), method, dev_name(&left->dev), lpeer ? dev_name(&lpeer->dev) : "none", dev_name(&right->dev), rpeer ? dev_name(&rpeer->dev) : "none"); return -EBUSY; } rc = sysfs_create_link(&left->dev.kobj, &right->dev.kobj, "peer"); if (rc) return rc; rc = sysfs_create_link(&right->dev.kobj, &left->dev.kobj, "peer"); if (rc) { sysfs_remove_link(&left->dev.kobj, "peer"); return rc; } /* * We need to wake the HiSpeed port to make sure we don't race * setting ->peer with usb_port_runtime_suspend(). Otherwise we * may miss a suspend event for the SuperSpeed port. */ if (left->is_superspeed) { ss_port = left; WARN_ON(right->is_superspeed); hs_port = right; } else { ss_port = right; WARN_ON(!right->is_superspeed); hs_port = left; } pm_runtime_get_sync(&hs_port->dev); left->peer = right; right->peer = left; /* * The SuperSpeed reference is dropped when the HiSpeed port in * this relationship suspends, i.e. when it is safe to allow a * SuperSpeed connection to drop since there is no risk of a * device degrading to its powered-off HiSpeed connection. * * Also, drop the HiSpeed ref taken above. */ pm_runtime_get_sync(&ss_port->dev); pm_runtime_put(&hs_port->dev); return 0; }
static void remove_deprecated_bus_links(struct device *dev) { sysfs_remove_link(&dev->kobj, "bus"); }
void o2cb_sys_shutdown(void) { mlog_sys_shutdown(); sysfs_remove_link(NULL, "o2cb"); kset_unregister(o2cb_kset); }
static int __cpuinit acpi_processor_add(struct acpi_device *device) { struct acpi_processor *pr = NULL; int result = 0; struct sys_device *sysdev; pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL); if (!pr) return -ENOMEM; if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) { kfree(pr); return -ENOMEM; } pr->handle = device->handle; strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS); device->driver_data = pr; result = acpi_processor_get_info(device); if (result) { /* Processor is physically not present */ return 0; } BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0)); /* * Buggy BIOS check * ACPI id of processors can be reported wrongly by the BIOS. * Don't trust it blindly */ if (per_cpu(processor_device_array, pr->id) != NULL && per_cpu(processor_device_array, pr->id) != device) { printk(KERN_WARNING "BIOS reported wrong ACPI id " "for the processor\n"); result = -ENODEV; goto err_free_cpumask; } per_cpu(processor_device_array, pr->id) = device; per_cpu(processors, pr->id) = pr; result = acpi_processor_add_fs(device); if (result) goto err_free_cpumask; sysdev = get_cpu_sysdev(pr->id); if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev")) { result = -EFAULT; goto err_remove_fs; } /* _PDC call should be done before doing anything else (if reqd.). */ arch_acpi_processor_init_pdc(pr); acpi_processor_set_pdc(pr); arch_acpi_processor_cleanup_pdc(pr); #ifdef CONFIG_CPU_FREQ acpi_processor_ppc_has_changed(pr); #endif acpi_processor_get_throttling_info(pr); acpi_processor_get_limit_info(pr); acpi_processor_power_init(pr, device); pr->cdev = thermal_cooling_device_register("Processor", device, &processor_cooling_ops); if (IS_ERR(pr->cdev)) { result = PTR_ERR(pr->cdev); goto err_power_exit; } dev_info(&device->dev, "registered as cooling_device%d\n", pr->cdev->id); result = sysfs_create_link(&device->dev.kobj, &pr->cdev->device.kobj, "thermal_cooling"); if (result) { printk(KERN_ERR PREFIX "Create sysfs link\n"); goto err_thermal_unregister; } result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj, "device"); if (result) { printk(KERN_ERR PREFIX "Create sysfs link\n"); goto err_remove_sysfs; } return 0; err_remove_sysfs: sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); err_thermal_unregister: thermal_cooling_device_unregister(pr->cdev); err_power_exit: acpi_processor_power_exit(pr, device); err_remove_fs: acpi_processor_remove_fs(device); err_free_cpumask: free_cpumask_var(pr->throttling.shared_cpu_map); return result; }
static int __cpuinit acpi_processor_add(struct acpi_device *device) { struct acpi_processor *pr = NULL; int result = 0; struct device *dev; pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL); if (!pr) return -ENOMEM; if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) { result = -ENOMEM; goto err_free_pr; } pr->handle = device->handle; strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS); device->driver_data = pr; result = acpi_processor_get_info(device); if (result) { return 0; } #ifdef CONFIG_SMP if (pr->id >= setup_max_cpus && pr->id != 0) return 0; #endif BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0)); if (per_cpu(processor_device_array, pr->id) != NULL && per_cpu(processor_device_array, pr->id) != device) { printk(KERN_WARNING "BIOS reported wrong ACPI id " "for the processor\n"); result = -ENODEV; goto err_free_cpumask; } per_cpu(processor_device_array, pr->id) = device; per_cpu(processors, pr->id) = pr; dev = get_cpu_device(pr->id); if (sysfs_create_link(&device->dev.kobj, &dev->kobj, "sysdev")) { result = -EFAULT; goto err_clear_processor; } if (pr->flags.need_hotplug_init) return 0; result = acpi_processor_start(pr); if (result) goto err_remove_sysfs; return 0; err_remove_sysfs: sysfs_remove_link(&device->dev.kobj, "sysdev"); err_clear_processor: per_cpu(processors, pr->id) = NULL; err_free_cpumask: free_cpumask_var(pr->throttling.shared_cpu_map); err_free_pr: kfree(pr); return result; }