deferred_probe_initcall

    /*
     * Deferred Probe infrastructure.
     *
     * Sometimes driver probe order matters, but the kernel doesn't always have
     * dependency information which means some drivers will get probed before a
     * resource it depends on is available.  For example, an SDHCI driver may
     * first need a GPIO line from an i2c GPIO controller before it can be
     * initialized.  If a required resource is not available yet, a driver can
     * request probing to be deferred by returning -EPROBE_DEFER from its probe hook 
     *
     * Deferred probe maintains two lists of devices, a pending list and an active
     * list.  A driver returning -EPROBE_DEFER causes the device to be added to the
     * pending list.  A successful driver probe will trigger moving all devices
     * from the pending to the active list so that the workqueue will eventually
     * retry them.
     *
     * The deferred_probe_mutex must be held any time the deferred_probe_*_list
     * of the (struct device*)->p->deferred_probe pointers are manipulated
     */
    static DEFINE_MUTEX(deferred_probe_mutex);
    static LIST_HEAD(deferred_probe_pending_list);
    static LIST_HEAD(deferred_probe_active_list);
    static atomic_t deferred_trigger_count = ATOMIC_INIT(0);
    static bool initcalls_done;
    
    
    /*
     * In some cases, like suspend to RAM or hibernation, It might be reasonable
     * to prohibit probing of devices as it could be unsafe.
     * Once defer_all_probes is true all drivers probes will be forcibly deferred.
     */
    static bool defer_all_probes;
    
    /*
     * For initcall_debug, show the deferred probes executed in late_initcall
     * processing.
     */
    static void deferred_probe_debug(struct device *dev)
    {
            ktime_t calltime, delta, rettime;
            unsigned long long duration;
    
            printk(KERN_DEBUG "deferred probe %s @ %i\n", dev_name(dev),
                   task_pid_nr(current));
            calltime = ktime_get();
            bus_probe_device(dev);
            rettime = ktime_get();
            delta = ktime_sub(rettime, calltime);
            duration = (unsigned long long) ktime_to_ns(delta) >> 10;
            printk(KERN_DEBUG "deferred probe %s returned after %lld usecs\n",
                   dev_name(dev), duration);
    }
    
    /*
     * deferred_probe_work_func() - Retry probing devices in the active list.
     */
    static void deferred_probe_work_func(struct work_struct *work)
    {
            struct device *dev;
            struct device_private *private;
            /*
             * This block processes every device in the deferred 'active' list.
             * Each device is removed from the active list and passed to
             * bus_probe_device() to re-attempt the probe.  The loop continues
             * until every device in the active list is removed and retried.
             *
             * Note: Once the device is removed from the list and the mutex is
             * released, it is possible for the device get freed by another thread
             * and cause a illegal pointer dereference.  This code uses
             * get/put_device() to ensure the device structure cannot disappear
             * from under our feet.
             */
            mutex_lock(&deferred_probe_mutex);
            while (!list_empty(&deferred_probe_active_list)) {
                    private = list_first_entry(&deferred_probe_active_list,
                                            typeof(*dev->p), deferred_probe);
                    dev = private->device;
                    list_del_init(&private->deferred_probe);
    
                    get_device(dev);
    
                    /*
                     * Drop the mutex while probing each device; the probe path may
                     * manipulate the deferred list
                     */
                    mutex_unlock(&deferred_probe_mutex);
    
                    /*
                     * Force the device to the end of the dpm_list since
                     * the PM code assumes that the order we add things to
                     * the list is a good order for suspend but deferred
                     * probe makes that very unsafe.
                     */
                    device_pm_lock();
                    device_pm_move_last(dev);
                    device_pm_unlock();
    
                    dev_dbg(dev, "Retrying from deferred list\n");
                    if (initcall_debug && !initcalls_done)
                            deferred_probe_debug(dev);
                    else
                            bus_probe_device(dev);
    
                    mutex_lock(&deferred_probe_mutex);
    
                    put_device(dev);
            }
            mutex_unlock(&deferred_probe_mutex);
    }
    static DECLARE_WORK(deferred_probe_work, deferred_probe_work_func);
    
    static void driver_deferred_probe_add(struct device *dev)
    {
            mutex_lock(&deferred_probe_mutex);
            if (list_empty(&dev->p->deferred_probe)) {
                    dev_dbg(dev, "Added to deferred list\n");
                    list_add_tail(&dev->p->deferred_probe, &deferred_probe_pending_list);
            }
            mutex_unlock(&deferred_probe_mutex);
    }
    
    void driver_deferred_probe_del(struct device *dev)
    {
            mutex_lock(&deferred_probe_mutex);
            if (!list_empty(&dev->p->deferred_probe)) {
                    dev_dbg(dev, "Removed from deferred list\n");
                    list_del_init(&dev->p->deferred_probe);
            }
            mutex_unlock(&deferred_probe_mutex);
    }
    
    static bool driver_deferred_probe_enable = false;
    
    /**
     * driver_deferred_probe_trigger() - Kick off re-probing deferred devices
     *
     * This functions moves all devices from the pending list to the active
     * list and schedules the deferred probe workqueue to process them.  It
     * should be called anytime a driver is successfully bound to a device.
     *
     * Note, there is a race condition in multi-threaded probe. In the case where
     * more than one device is probing at the same time, it is possible for one
     * probe to complete successfully while another is about to defer. If the second
     * depends on the first, then it will get put on the pending list after the
     * trigger event has already occurred and will be stuck there.
     *
     * The atomic 'deferred_trigger_count' is used to determine if a successful
     * trigger has occurred in the midst of probing a driver. If the trigger count
     * changes in the midst of a probe, then deferred processing should be triggered
     * again.
     */
    static void driver_deferred_probe_trigger(void)
    {
            if (!driver_deferred_probe_enable)
                    return;
    
            /*
             * A successful probe means that all the devices in the pending list
             * should be triggered to be reprobed.  Move all the deferred devices
             * into the active list so they can be retried by the workqueue
             */
            mutex_lock(&deferred_probe_mutex);
            atomic_inc(&deferred_trigger_count);
            list_splice_tail_init(&deferred_probe_pending_list,
                                  &deferred_probe_active_list);
            mutex_unlock(&deferred_probe_mutex);
    
            /*
             * Kick the re-probe thread.  It may already be scheduled, but it is
             * safe to kick it again.
             */
            schedule_work(&deferred_probe_work);
    }
    
    /**
     * device_block_probing() - Block/defere device's probes
     *
     *      It will disable probing of devices and defer their probes instead.
     */
    void device_block_probing(void)
    {
            defer_all_probes = true;
            /* sync with probes to avoid races. */
            wait_for_device_probe();
    }
    
    /**
     * device_unblock_probing() - Unblock/enable device's probes
     *
     *      It will restore normal behavior and trigger re-probing of deferred
     * devices.
     */
    void device_unblock_probing(void)
    {
            defer_all_probes = false;
            driver_deferred_probe_trigger();
    }
    
    /**
     * deferred_probe_initcall() - Enable probing of deferred devices
     *
     * We don't want to get in the way when the bulk of drivers are getting probed.
     * Instead, this initcall makes sure that deferred probing is delayed until
     * late_initcall time.
     */
    static int deferred_probe_initcall(void)
    {
            driver_deferred_probe_enable = true;
            driver_deferred_probe_trigger();
            /* Sort as many dependencies as possible before exiting initcalls */
            flush_work(&deferred_probe_work);
            initcalls_done = true;
            return 0;
    }
    late_initcall(deferred_probe_initcall);
    
    
    static void driver_bound(struct device *dev)
    {
            if (device_is_bound(dev)) {
                    printk(KERN_WARNING "%s: device %s already bound\n",
                            __func__, kobject_name(&dev->kobj));
                    return;
            }
    
            pr_debug("driver: '%s': %s: bound to device '%s'\n", dev->driver->name,
                     __func__, dev_name(dev));
    
            klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
            device_links_driver_bound(dev);
    
            device_pm_check_callbacks(dev);
    
            /*
             * Make sure the device is no longer in one of the deferred lists and
             * kick off retrying all pending devices
             */
            driver_deferred_probe_del(dev);
            driver_deferred_probe_trigger();
    
            if (dev->bus)
                    blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                                                 BUS_NOTIFY_BOUND_DRIVER, dev);
    
            kobject_uevent(&dev->kobj, KOBJ_BIND);
    }

static int really_probe(struct device *dev, struct device_driver *drv)
{
        int ret = -EPROBE_DEFER;
        int local_trigger_count = atomic_read(&deferred_trigger_count);
        bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE) &&
                           !drv->suppress_bind_attrs;

        if (defer_all_probes) {
                /*
                 * Value of defer_all_probes can be set only by
                 * device_defer_all_probes_enable() which, in turn, will call
                 * wait_for_device_probe() right after that to avoid any races.
                 */
                dev_dbg(dev, "Driver %s force probe deferral\n", drv->name);
                driver_deferred_probe_add(dev);
                return ret;
        }

        ret = device_links_check_suppliers(dev);
        if (ret)
                return ret;

        atomic_inc(&probe_count);
        pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
                 drv->bus->name, __func__, drv->name, dev_name(dev));
        WARN_ON(!list_empty(&dev->devres_head));

re_probe:
        dev->driver = drv;

        /* If using pinctrl, bind pins now before probing */
        ret = pinctrl_bind_pins(dev);
        if (ret)
                goto pinctrl_bind_failed;

        ret = dma_configure(dev);
        if (ret)
                goto dma_failed;

        if (driver_sysfs_add(dev)) {
                printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
                        __func__, dev_name(dev));
                goto probe_failed;
        }

        if (dev->pm_domain && dev->pm_domain->activate) {
                ret = dev->pm_domain->activate(dev);
                if (ret)
                        goto probe_failed;
        }

        /*
         * Ensure devices are listed in devices_kset in correct order
         * It's important to move Dev to the end of devices_kset before
         * calling .probe, because it could be recursive and parent Dev
         * should always go first
         */
        devices_kset_move_last(dev);

        if (dev->bus->probe) {
                ret = dev->bus->probe(dev);
                if (ret)
                        goto probe_failed;
        } else if (drv->probe) {
                ret = drv->probe(dev);
                if (ret)
                        goto probe_failed;
        }

        if (test_remove) {
                test_remove = false;

                if (dev->bus->remove)
                        dev->bus->remove(dev);
                else if (drv->remove)
                        drv->remove(dev);

                devres_release_all(dev);
                driver_sysfs_remove(dev);
                dev->driver = NULL;
                dev_set_drvdata(dev, NULL);
                if (dev->pm_domain && dev->pm_domain->dismiss)
                        dev->pm_domain->dismiss(dev);
                pm_runtime_reinit(dev);

                goto re_probe;
        }

        pinctrl_init_done(dev);

        if (dev->pm_domain && dev->pm_domain->sync)
                dev->pm_domain->sync(dev);

        driver_bound(dev);
        ret = 1;
        pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
                 drv->bus->name, __func__, dev_name(dev), drv->name);
        goto done;

probe_failed:
        dma_deconfigure(dev);
dma_failed:
        if (dev->bus)
                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                                             BUS_NOTIFY_DRIVER_NOT_BOUND, dev);
pinctrl_bind_failed:
        device_links_no_driver(dev);
        devres_release_all(dev);
        driver_sysfs_remove(dev);
        dev->driver = NULL;
        dev_set_drvdata(dev, NULL);
        if (dev->pm_domain && dev->pm_domain->dismiss)
                dev->pm_domain->dismiss(dev);
        pm_runtime_reinit(dev);

        switch (ret) {
        case -EPROBE_DEFER:
                /* Driver requested deferred probing */
                dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name);
                driver_deferred_probe_add(dev);
                /* Did a trigger occur while probing? Need to re-trigger if yes */
                if (local_trigger_count != atomic_read(&deferred_trigger_count))
                        driver_deferred_probe_trigger();
                break;
        case -ENODEV:
        case -ENXIO:
                pr_debug("%s: probe of %s rejects match %d\n",
                         drv->name, dev_name(dev), ret);
                break;
        default:
                /* driver matched but the probe failed */
                printk(KERN_WARNING
                       "%s: probe of %s failed with error %d\n",
                       drv->name, dev_name(dev), ret);
        }
        /*
         * Ignore errors returned by ->probe so that the next driver can try
         * its luck.
         */
        ret = 0;
done:
        atomic_dec(&probe_count);
        wake_up(&probe_waitqueue);
        return ret;
}

/**
 * wait_for_device_probe
 * Wait for device probing to be completed.
 */
void wait_for_device_probe(void)
{
        /* wait for the deferred probe workqueue to finish */
        flush_work(&deferred_probe_work);

        /* wait for the known devices to complete their probing */
        wait_event(probe_waitqueue, atomic_read(&probe_count) == 0);
        async_synchronize_full();
}
EXPORT_SYMBOL_GPL(wait_for_device_probe);

static int __device_attach_driver(struct device_driver *drv, void *_data)
{
        struct device_attach_data *data = _data;
        struct device *dev = data->dev;
        bool async_allowed;
        int ret;

        /*
         * Check if device has already been claimed. This may
         * happen with driver loading, device discovery/registration,
         * and deferred probe processing happens all at once with
         * multiple threads.
         */
        if (dev->driver)
                return -EBUSY;

        ret = driver_match_device(drv, dev);
        if (ret == 0) {
                /* no match */
                return 0;
        } else if (ret == -EPROBE_DEFER) {
                dev_dbg(dev, "Device match requests probe deferral\n");
                driver_deferred_probe_add(dev);
        } else if (ret < 0) {
                dev_dbg(dev, "Bus failed to match device: %d", ret);
                return ret;
        } /* ret > 0 means positive match */

        async_allowed = driver_allows_async_probing(drv);

        if (async_allowed)
                data->have_async = true;

        if (data->check_async && async_allowed != data->want_async)
                return 0;

        return driver_probe_device(drv, dev);
}
static int __driver_attach(struct device *dev, void *data)
{
        struct device_driver *drv = data;
        int ret;

        /*
         * Lock device and try to bind to it. We drop the error
         * here and always return 0, because we need to keep trying
         * to bind to devices and some drivers will return an error
         * simply if it didn't support the device.
         *
         * driver_probe_device() will spit a warning if there
         * is an error.
         */

        ret = driver_match_device(drv, dev);
        if (ret == 0) {
                /* no match */
                return 0;
        } else if (ret == -EPROBE_DEFER) {
                dev_dbg(dev, "Device match requests probe deferral\n");
                driver_deferred_probe_add(dev);
        } else if (ret < 0) {
                dev_dbg(dev, "Bus failed to match device: %d", ret);
                return ret;
        } /* ret > 0 means positive match */

        if (dev->parent)        /* Needed for USB */
                device_lock(dev->parent);
        device_lock(dev);
        if (!dev->driver)
                driver_probe_device(drv, dev);
        device_unlock(dev);
        if (dev->parent)
                device_unlock(dev->parent);

        return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值