diff options
Diffstat (limited to 'drivers')
140 files changed, 1757 insertions, 2030 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 499536504698..87b704e41877 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -985,8 +985,6 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) state->flags = 0; switch (cx->type) { case ACPI_STATE_C1: - if (cx->entry_method != ACPI_CSTATE_FFH) - state->flags |= CPUIDLE_FLAG_TIME_INVALID; state->enter = acpi_idle_enter_c1; state->enter_dead = acpi_idle_play_dead; diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 1eaadff2e198..c72e79d2c5ad 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -505,6 +505,23 @@ static struct dmi_system_id video_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY 15 Notebook PC"), }, }, + + { + .callback = video_disable_native_backlight, + .ident = "SAMSUNG 870Z5E/880Z5E/680Z5E", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "870Z5E/880Z5E/680Z5E"), + }, + }, + { + .callback = video_disable_native_backlight, + .ident = "SAMSUNG 370R4E/370R4V/370R5E/3570RE/370R5V", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "370R4E/370R4V/370R5E/3570RE/370R5V"), + }, + }, {} }; diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 6a103a35ea9b..0d8780c04a5e 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -2088,7 +2088,7 @@ EXPORT_SYMBOL_GPL(of_genpd_del_provider); * Returns a valid pointer to struct generic_pm_domain on success or ERR_PTR() * on failure. */ -static struct generic_pm_domain *of_genpd_get_from_provider( +struct generic_pm_domain *of_genpd_get_from_provider( struct of_phandle_args *genpdspec) { struct generic_pm_domain *genpd = ERR_PTR(-ENOENT); @@ -2108,6 +2108,7 @@ static struct generic_pm_domain *of_genpd_get_from_provider( return genpd; } +EXPORT_SYMBOL_GPL(of_genpd_get_from_provider); /** * genpd_dev_pm_detach - Detach a device from its PM domain. diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index d24dd614a0bd..106c69359306 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -108,6 +108,14 @@ static LIST_HEAD(dev_opp_list); /* Lock to allow exclusive modification to the device and opp lists */ static DEFINE_MUTEX(dev_opp_list_lock); +#define opp_rcu_lockdep_assert() \ +do { \ + rcu_lockdep_assert(rcu_read_lock_held() || \ + lockdep_is_held(&dev_opp_list_lock), \ + "Missing rcu_read_lock() or " \ + "dev_opp_list_lock protection"); \ +} while (0) + /** * find_device_opp() - find device_opp struct using device pointer * @dev: device pointer used to lookup device OPPs @@ -208,9 +216,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq); * This function returns the number of available opps if there are any, * else returns 0 if none or the corresponding error value. * - * Locking: This function must be called under rcu_read_lock(). This function - * internally references two RCU protected structures: device_opp and opp which - * are safe as long as we are under a common RCU locked section. + * Locking: This function takes rcu_read_lock(). */ int dev_pm_opp_get_opp_count(struct device *dev) { @@ -218,11 +224,14 @@ int dev_pm_opp_get_opp_count(struct device *dev) struct dev_pm_opp *temp_opp; int count = 0; + rcu_read_lock(); + dev_opp = find_device_opp(dev); if (IS_ERR(dev_opp)) { - int r = PTR_ERR(dev_opp); - dev_err(dev, "%s: device OPP not found (%d)\n", __func__, r); - return r; + count = PTR_ERR(dev_opp); + dev_err(dev, "%s: device OPP not found (%d)\n", + __func__, count); + goto out_unlock; } list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) { @@ -230,6 +239,8 @@ int dev_pm_opp_get_opp_count(struct device *dev) count++; } +out_unlock: + rcu_read_unlock(); return count; } EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count); @@ -267,6 +278,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, struct device_opp *dev_opp; struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE); + opp_rcu_lockdep_assert(); + dev_opp = find_device_opp(dev); if (IS_ERR(dev_opp)) { int r = PTR_ERR(dev_opp); @@ -313,6 +326,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev, struct device_opp *dev_opp; struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE); + opp_rcu_lockdep_assert(); + if (!dev || !freq) { dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq); return ERR_PTR(-EINVAL); @@ -361,6 +376,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, struct device_opp *dev_opp; struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE); + opp_rcu_lockdep_assert(); + if (!dev || !freq) { dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq); return ERR_PTR(-EINVAL); @@ -783,9 +800,15 @@ void of_free_opp_table(struct device *dev) /* Check for existing list for 'dev' */ dev_opp = find_device_opp(dev); - if (WARN(IS_ERR(dev_opp), "%s: dev_opp: %ld\n", dev_name(dev), - PTR_ERR(dev_opp))) + if (IS_ERR(dev_opp)) { + int error = PTR_ERR(dev_opp); + if (error != -ENODEV) + WARN(1, "%s: dev_opp: %d\n", + IS_ERR_OR_NULL(dev) ? + "Invalid device" : dev_name(dev), + error); return; + } /* Hold our list modification lock here */ mutex_lock(&dev_opp_list_lock); diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index 19db03667650..dcbbb4ea3cc1 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -417,6 +417,6 @@ static void __exit agp_ali_cleanup(void) module_init(agp_ali_init); module_exit(agp_ali_cleanup); -MODULE_AUTHOR("Dave Jones <davej@redhat.com>"); +MODULE_AUTHOR("Dave Jones"); MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 3b47ed0310e1..0ef350010766 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -813,6 +813,6 @@ static void __exit agp_amd64_cleanup(void) module_init(agp_amd64_mod_init); module_exit(agp_amd64_cleanup); -MODULE_AUTHOR("Dave Jones <davej@redhat.com>, Andi Kleen"); +MODULE_AUTHOR("Dave Jones, Andi Kleen"); module_param(agp_try_unsupported, bool, 0); MODULE_LICENSE("GPL"); diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index 18a7a6baa304..75a9786a77e6 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -579,6 +579,6 @@ static void __exit agp_ati_cleanup(void) module_init(agp_ati_init); module_exit(agp_ati_cleanup); -MODULE_AUTHOR("Dave Jones <davej@redhat.com>"); +MODULE_AUTHOR("Dave Jones"); MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 317c28ce8328..38ffb281df97 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -356,7 +356,7 @@ static __init int agp_setup(char *s) __setup("agp=", agp_setup); #endif -MODULE_AUTHOR("Dave Jones <davej@redhat.com>"); +MODULE_AUTHOR("Dave Jones, Jeff Hartmann"); MODULE_DESCRIPTION("AGP GART driver"); MODULE_LICENSE("GPL and additional rights"); MODULE_ALIAS_MISCDEV(AGPGART_MINOR); diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index f9b9ca5d31b7..0a21daed5b62 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -920,5 +920,5 @@ static void __exit agp_intel_cleanup(void) module_init(agp_intel_init); module_exit(agp_intel_cleanup); -MODULE_AUTHOR("Dave Jones <davej@redhat.com>"); +MODULE_AUTHOR("Dave Jones, Various @Intel"); MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index f3334829e55a..92aa43fa8d70 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1438,5 +1438,5 @@ void intel_gmch_remove(void) } EXPORT_SYMBOL(intel_gmch_remove); -MODULE_AUTHOR("Dave Jones <davej@redhat.com>"); +MODULE_AUTHOR("Dave Jones, Various @Intel"); MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index a1861b75eb31..6c8d39cb566e 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -1,7 +1,7 @@ /* * Nvidia AGPGART routines. * Based upon a 2.4 agpgart diff by the folks from NVIDIA, and hacked up - * to work in 2.5 by Dave Jones <davej@redhat.com> + * to work in 2.5 by Dave Jones. */ #include <linux/module.h> diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index 228f20cddc05..a4961d35e940 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -595,4 +595,4 @@ module_init(agp_via_init); module_exit(agp_via_cleanup); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Dave Jones <davej@redhat.com>"); +MODULE_AUTHOR("Dave Jones"); diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 5fa83f751378..6b65fa4e0c55 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -199,18 +199,6 @@ struct bmc_device { int guid_set; char name[16]; struct kref usecount; - - /* bmc device attributes */ - struct device_attribute device_id_attr; - struct device_attribute provides_dev_sdrs_attr; - struct device_attribute revision_attr; - struct device_attribute firmware_rev_attr; - struct device_attribute version_attr; - struct device_attribute add_dev_support_attr; - struct device_attribute manufacturer_id_attr; - struct device_attribute product_id_attr; - struct device_attribute guid_attr; - struct device_attribute aux_firmware_rev_attr; }; #define to_bmc_device(x) container_of((x), struct bmc_device, pdev.dev) @@ -2252,7 +2240,7 @@ static ssize_t device_id_show(struct device *dev, return snprintf(buf, 10, "%u\n", bmc->id.device_id); } -DEVICE_ATTR(device_id, S_IRUGO, device_id_show, NULL); +static DEVICE_ATTR(device_id, S_IRUGO, device_id_show, NULL); static ssize_t provides_device_sdrs_show(struct device *dev, struct device_attribute *attr, @@ -2263,7 +2251,8 @@ static ssize_t provides_device_sdrs_show(struct device *dev, return snprintf(buf, 10, "%u\n", (bmc->id.device_revision & 0x80) >> 7); } -DEVICE_ATTR(provides_device_sdrs, S_IRUGO, provides_device_sdrs_show, NULL); +static DEVICE_ATTR(provides_device_sdrs, S_IRUGO, provides_device_sdrs_show, + NULL); static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -2273,7 +2262,7 @@ static ssize_t revision_show(struct device *dev, struct device_attribute *attr, return snprintf(buf, 20, "%u\n", bmc->id.device_revision & 0x0F); } -DEVICE_ATTR(revision, S_IRUGO, revision_show, NULL); +static DEVICE_ATTR(revision, S_IRUGO, revision_show, NULL); static ssize_t firmware_revision_show(struct device *dev, struct device_attribute *attr, @@ -2284,7 +2273,7 @@ static ssize_t firmware_revision_show(struct device *dev, return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1, bmc->id.firmware_revision_2); } -DEVICE_ATTR(firmware_revision, S_IRUGO, firmware_revision_show, NULL); +static DEVICE_ATTR(firmware_revision, S_IRUGO, firmware_revision_show, NULL); static ssize_t ipmi_version_show(struct device *dev, struct device_attribute *attr, @@ -2296,7 +2285,7 @@ static ssize_t ipmi_version_show(struct device *dev, ipmi_version_major(&bmc->id), ipmi_version_minor(&bmc->id)); } -DEVICE_ATTR(ipmi_version, S_IRUGO, ipmi_version_show, NULL); +static DEVICE_ATTR(ipmi_version, S_IRUGO, ipmi_version_show, NULL); static ssize_t add_dev_support_show(struct device *dev, struct device_attribute *attr, @@ -2307,7 +2296,8 @@ static ssize_t add_dev_support_show(struct device *dev, return snprintf(buf, 10, "0x%02x\n", bmc->id.additional_device_support); } -DEVICE_ATTR(additional_device_support, S_IRUGO, add_dev_support_show, NULL); +static DEVICE_ATTR(additional_device_support, S_IRUGO, add_dev_support_show, + NULL); static ssize_t manufacturer_id_show(struct device *dev, struct device_attribute *attr, @@ -2317,7 +2307,7 @@ static ssize_t manufacturer_id_show(struct device *dev, return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id); } -DEVICE_ATTR(manufacturer_id, S_IRUGO, manufacturer_id_show, NULL); +static DEVICE_ATTR(manufacturer_id, S_IRUGO, manufacturer_id_show, NULL); static ssize_t product_id_show(struct device *dev, struct device_attribute *attr, @@ -2327,7 +2317,7 @@ static ssize_t product_id_show(struct device *dev, return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id); } -DEVICE_ATTR(product_id, S_IRUGO, product_id_show, NULL); +static DEVICE_ATTR(product_id, S_IRUGO, product_id_show, NULL); static ssize_t aux_firmware_rev_show(struct device *dev, struct device_attribute *attr, @@ -2341,7 +2331,7 @@ static ssize_t aux_firmware_rev_show(struct device *dev, bmc->id.aux_firmware_revision[1], bmc->id.aux_firmware_revision[0]); } -DEVICE_ATTR(aux_firmware_revision, S_IRUGO, aux_firmware_rev_show, NULL); +static DEVICE_ATTR(aux_firmware_revision, S_IRUGO, aux_firmware_rev_show, NULL); static ssize_t guid_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -2352,7 +2342,7 @@ static ssize_t guid_show(struct device *dev, struct device_attribute *attr, (long long) bmc->guid[0], (long long) bmc->guid[8]); } -DEVICE_ATTR(guid, S_IRUGO, guid_show, NULL); +static DEVICE_ATTR(guid, S_IRUGO, guid_show, NULL); static struct attribute *bmc_dev_attrs[] = { &dev_attr_device_id.attr, @@ -2392,10 +2382,10 @@ cleanup_bmc_device(struct kref *ref) if (bmc->id.aux_firmware_revision_set) device_remove_file(&bmc->pdev.dev, - &bmc->aux_firmware_rev_attr); + &dev_attr_aux_firmware_revision); if (bmc->guid_set) device_remove_file(&bmc->pdev.dev, - &bmc->guid_attr); + &dev_attr_guid); platform_device_unregister(&bmc->pdev); } @@ -2422,16 +2412,14 @@ static int create_bmc_files(struct bmc_device *bmc) int err; if (bmc->id.aux_firmware_revision_set) { - bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision"; err = device_create_file(&bmc->pdev.dev, - &bmc->aux_firmware_rev_attr); + &dev_attr_aux_firmware_revision); if (err) goto out; } if (bmc->guid_set) { - bmc->guid_attr.attr.name = "guid"; err = device_create_file(&bmc->pdev.dev, - &bmc->guid_attr); + &dev_attr_guid); if (err) goto out_aux_firm; } @@ -2441,7 +2429,7 @@ static int create_bmc_files(struct bmc_device *bmc) out_aux_firm: if (bmc->id.aux_firmware_revision_set) device_remove_file(&bmc->pdev.dev, - &bmc->aux_firmware_rev_attr); + &dev_attr_aux_firmware_revision); out: return err; } diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index e178ac27e73c..fd5a5e85d7dc 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -52,6 +52,7 @@ #include <linux/dmi.h> #include <linux/kthread.h> #include <linux/acpi.h> +#include <linux/ctype.h> #define PFX "ipmi_ssif: " #define DEVICE_NAME "ipmi_ssif" diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 6a79fc4f900c..095c1774592c 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -462,7 +462,7 @@ static void __init arch_counter_register(unsigned type) /* Register the CP15 based counter if we have one */ if (type & ARCH_CP15_TIMER) { - if (arch_timer_use_virtual) + if (IS_ENABLED(CONFIG_ARM64) || arch_timer_use_virtual) arch_timer_read_counter = arch_counter_get_cntvct; else arch_timer_read_counter = arch_counter_get_cntpct; diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index f56147a1daed..fde97d6e31d6 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -211,6 +211,17 @@ static int cpufreq_init(struct cpufreq_policy *policy) /* OPPs might be populated at runtime, don't check for error here */ of_init_opp_table(cpu_dev); + /* + * But we need OPP table to function so if it is not there let's + * give platform code chance to provide it for us. + */ + ret = dev_pm_opp_get_opp_count(cpu_dev); + if (ret <= 0) { + pr_debug("OPP table is not ready, deferring probe\n"); + ret = -EPROBE_DEFER; + goto out_free_opp; + } + priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { ret = -ENOMEM; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index a09a29c312a9..46bed4f81cde 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2028,6 +2028,12 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, /* Don't start any governor operations if we are entering suspend */ if (cpufreq_suspended) return 0; + /* + * Governor might not be initiated here if ACPI _PPC changed + * notification happened, so check it. + */ + if (!policy->governor) + return -EINVAL; if (policy->governor->max_transition_latency && policy->cpuinfo.transition_latency > diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c index 37263d9a1051..401c0106ed34 100644 --- a/drivers/cpuidle/governors/ladder.c +++ b/drivers/cpuidle/governors/ladder.c @@ -79,12 +79,7 @@ static int ladder_select_state(struct cpuidle_driver *drv, last_state = &ldev->states[last_idx]; - if (!(drv->states[last_idx].flags & CPUIDLE_FLAG_TIME_INVALID)) { - last_residency = cpuidle_get_last_residency(dev) - \ - drv->states[last_idx].exit_latency; - } - else - last_residency = last_state->threshold.promotion_time + 1; + last_residency = cpuidle_get_last_residency(dev) - drv->states[last_idx].exit_latency; /* consider promotion */ if (last_idx < drv->state_count - 1 && diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 659d7b0c9ebf..40580794e23d 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -396,8 +396,8 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) * power state and occurrence of the wakeup event. * * If the entered idle state didn't support residency measurements, - * we are basically lost in the dark how much time passed. - * As a compromise, assume we slept for the whole expected time. + * we use them anyway if they are short, and if long, + * truncate to the whole expected time. * * Any measured amount of time will include the exit latency. * Since we are interested in when the wakeup begun, not when it @@ -405,22 +405,17 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) * the measured amount of time is less than the exit latency, * assume the state was never reached and the exit latency is 0. */ - if (unlikely(target->flags & CPUIDLE_FLAG_TIME_INVALID)) { - /* Use timer value as is */ - measured_us = data->next_timer_us; - } else { - /* Use measured value */ - measured_us = cpuidle_get_last_residency(dev); + /* measured value */ + measured_us = cpuidle_get_last_residency(dev); - /* Deduct exit latency */ - if (measured_us > target->exit_latency) - measured_us -= target->exit_latency; + /* Deduct exit latency */ + if (measured_us > target->exit_latency) + measured_us -= target->exit_latency; - /* Make sure our coefficients do not exceed unity */ - if (measured_us > data->next_timer_us) - measured_us = data->next_timer_us; - } + /* Make sure our coefficients do not exceed unity */ + if (measured_us > data->next_timer_us) + measured_us = data->next_timer_us; /* Update our correction ratio */ new_factor = data->correction_factor[data->bucket]; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 4f7b275f2f7b..7d4974b83af7 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -121,13 +121,9 @@ static int kfd_open(struct inode *inode, struct file *filep) if (IS_ERR(process)) return PTR_ERR(process); - process->is_32bit_user_mode = is_32bit_user_mode; - dev_dbg(kfd_device, "process %d opened, compat mode (32 bit) - %d\n", process->pasid, process->is_32bit_user_mode); - kfd_init_apertures(process); - return 0; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c index 66df4da01c29..e64aa99e5e41 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c @@ -299,13 +299,13 @@ int kfd_init_apertures(struct kfd_process *process) struct kfd_dev *dev; struct kfd_process_device *pdd; - mutex_lock(&process->mutex); - /*Iterating over all devices*/ while ((dev = kfd_topology_enum_kfd_devices(id)) != NULL && id < NUM_OF_SUPPORTED_GPUS) { pdd = kfd_get_process_device_data(dev, process, 1); + if (!pdd) + return -1; /* * For 64 bit process aperture will be statically reserved in @@ -348,8 +348,6 @@ int kfd_init_apertures(struct kfd_process *process) id++; } - mutex_unlock(&process->mutex); - return 0; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index b85eb0b830b4..3c76ef05cbcf 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -26,6 +26,8 @@ #include <linux/slab.h> #include <linux/amd-iommu.h> #include <linux/notifier.h> +#include <linux/compat.h> + struct mm_struct; #include "kfd_priv.h" @@ -285,8 +287,15 @@ static struct kfd_process *create_process(const struct task_struct *thread) if (err != 0) goto err_process_pqm_init; + /* init process apertures*/ + process->is_32bit_user_mode = is_compat_task(); + if (kfd_init_apertures(process) != 0) + goto err_init_apretures; + return process; +err_init_apretures: + pqm_uninit(&process->pqm); err_process_pqm_init: hash_del_rcu(&process->kfd_processes); synchronize_rcu(); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 5733e2859e8a..b11792d7e70e 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -700,8 +700,6 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr, dev->node_props.simd_per_cu); sysfs_show_32bit_prop(buffer, "max_slots_scratch_cu", dev->node_props.max_slots_scratch_cu); - sysfs_show_32bit_prop(buffer, "engine_id", - dev->node_props.engine_id); sysfs_show_32bit_prop(buffer, "vendor_id", dev->node_props.vendor_id); sysfs_show_32bit_prop(buffer, "device_id", @@ -715,6 +713,12 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr, dev->gpu->kgd)); sysfs_show_64bit_prop(buffer, "local_mem_size", kfd2kgd->get_vmem_size(dev->gpu->kgd)); + + sysfs_show_32bit_prop(buffer, "fw_version", + kfd2kgd->get_fw_version( + dev->gpu->kgd, + KGD_ENGINE_MEC1)); + } ret = sysfs_show_32bit_prop(buffer, "max_engine_clk_ccompute", diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h index 9c729dd8dd50..47b551970a14 100644 --- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h @@ -45,6 +45,17 @@ enum kgd_memory_pool { KGD_POOL_FRAMEBUFFER = 3, }; +enum kgd_engine_type { + KGD_ENGINE_PFP = 1, + KGD_ENGINE_ME, + KGD_ENGINE_CE, + KGD_ENGINE_MEC1, + KGD_ENGINE_MEC2, + KGD_ENGINE_RLC, + KGD_ENGINE_SDMA, + KGD_ENGINE_MAX +}; + struct kgd2kfd_shared_resources { /* Bit n == 1 means VMID n is available for KFD. */ unsigned int compute_vmid_bitmap; @@ -137,6 +148,8 @@ struct kgd2kfd_calls { * * @hqd_destroy: Destructs and preempts the queue assigned to that hqd slot. * + * @get_fw_version: Returns FW versions from the header + * * This structure contains function pointers to services that the kgd driver * provides to amdkfd driver. * @@ -176,6 +189,8 @@ struct kfd2kgd_calls { int (*hqd_destroy)(struct kgd_dev *kgd, uint32_t reset_type, unsigned int timeout, uint32_t pipe_id, uint32_t queue_id); + uint16_t (*get_fw_version)(struct kgd_dev *kgd, + enum kgd_engine_type type); }; bool kgd2kfd_init(unsigned interface_version, diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 4a78a773151c..bbdbe4721573 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -61,7 +61,7 @@ drm_atomic_helper_plane_changed(struct drm_atomic_state *state, struct drm_crtc_state *crtc_state; if (plane->state->crtc) { - crtc_state = state->crtc_states[drm_crtc_index(plane->crtc)]; + crtc_state = state->crtc_states[drm_crtc_index(plane->state->crtc)]; if (WARN_ON(!crtc_state)) return; diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index f5a5f18efa5b..4d79dad9d44f 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -830,6 +830,8 @@ drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, * vblank events since the system was booted, including lost events due to * modesetting activity. * + * This is the legacy version of drm_crtc_vblank_count(). + * * Returns: * The software vblank counter. */ @@ -844,6 +846,25 @@ u32 drm_vblank_count(struct drm_device *dev, int crtc) EXPORT_SYMBOL(drm_vblank_count); /** + * drm_crtc_vblank_count - retrieve "cooked" vblank counter value + * @crtc: which counter to retrieve + * + * Fetches the "cooked" vblank count value that represents the number of + * vblank events since the system was booted, including lost events due to + * modesetting activity. + * + * This is the native KMS version of drm_vblank_count(). + * + * Returns: + * The software vblank counter. + */ +u32 drm_crtc_vblank_count(struct drm_crtc *crtc) +{ + return drm_vblank_count(crtc->dev, drm_crtc_index(crtc)); +} +EXPORT_SYMBOL(drm_crtc_vblank_count); + +/** * drm_vblank_count_and_time - retrieve "cooked" vblank counter value * and the system timestamp corresponding to that vblank counter value. * @@ -904,6 +925,8 @@ static void send_vblank_event(struct drm_device *dev, * * Updates sequence # and timestamp on event, and sends it to userspace. * Caller must hold event lock. + * + * This is the legacy version of drm_crtc_send_vblank_event(). */ void drm_send_vblank_event(struct drm_device *dev, int crtc, struct drm_pending_vblank_event *e) @@ -923,6 +946,23 @@ void drm_send_vblank_event(struct drm_device *dev, int crtc, EXPORT_SYMBOL(drm_send_vblank_event); /** + * drm_crtc_send_vblank_event - helper to send vblank event after pageflip + * @crtc: the source CRTC of the vblank event + * @e: the event to send + * + * Updates sequence # and timestamp on event, and sends it to userspace. + * Caller must hold event lock. + * + * This is the native KMS version of drm_send_vblank_event(). + */ +void drm_crtc_send_vblank_event(struct drm_crtc *crtc, + struct drm_pending_vblank_event *e) +{ + drm_send_vblank_event(crtc->dev, drm_crtc_index(crtc), e); +} +EXPORT_SYMBOL(drm_crtc_send_vblank_event); + +/** * drm_vblank_enable - enable the vblank interrupt on a CRTC * @dev: DRM device * @crtc: CRTC in question @@ -1594,6 +1634,8 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc) * * Drivers should call this routine in their vblank interrupt handlers to * update the vblank counter and send any signals that may be pending. + * + * This is the legacy version of drm_crtc_handle_vblank(). */ bool drm_handle_vblank(struct drm_device *dev, int crtc) { @@ -1670,3 +1712,21 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) return true; } EXPORT_SYMBOL(drm_handle_vblank); + +/** + * drm_crtc_handle_vblank - handle a vblank event + * @crtc: where this event occurred + * + * Drivers should call this routine in their vblank interrupt handlers to + * update the vblank counter and send any signals that may be pending. + * + * This is the native KMS version of drm_handle_vblank(). + * + * Returns: + * True if the event was successfully handled, false on failure. + */ +bool drm_crtc_handle_vblank(struct drm_crtc *crtc) +{ + return drm_handle_vblank(crtc->dev, drm_crtc_index(crtc)); +} +EXPORT_SYMBOL(drm_crtc_handle_vblank); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index f990ab4c3efb..574057cd1d09 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -811,6 +811,8 @@ int i915_reset(struct drm_device *dev) if (!i915.reset) return 0; + intel_reset_gt_powersave(dev); + mutex_lock(&dev->struct_mutex); i915_gem_reset(dev); @@ -880,7 +882,7 @@ int i915_reset(struct drm_device *dev) * of re-init after reset. */ if (INTEL_INFO(dev)->gen > 5) - intel_reset_gt_powersave(dev); + intel_enable_gt_powersave(dev); } else { mutex_unlock(&dev->struct_mutex); } @@ -1584,7 +1586,7 @@ static struct drm_driver driver = { .gem_prime_import = i915_gem_prime_import, .dumb_create = i915_gem_dumb_create, - .dumb_map_offset = i915_gem_dumb_map_offset, + .dumb_map_offset = i915_gem_mmap_gtt, .dumb_destroy = drm_gem_dumb_destroy, .ioctls = i915_ioctls, .fops = &i915_driver_fops, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 63bcda5541ec..70d0f0f06f1a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2501,9 +2501,8 @@ void i915_vma_move_to_active(struct i915_vma *vma, int i915_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args); -int i915_gem_dumb_map_offset(struct drm_file *file_priv, - struct drm_device *dev, uint32_t handle, - uint64_t *offset); +int i915_gem_mmap_gtt(struct drm_file *file_priv, struct drm_device *dev, + uint32_t handle, uint64_t *offset); /** * Returns true if seq1 is later than seq2. */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4a9faea626db..52adcb680be3 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -401,7 +401,6 @@ static int i915_gem_create(struct drm_file *file, struct drm_device *dev, uint64_t size, - bool dumb, uint32_t *handle_p) { struct drm_i915_gem_object *obj; @@ -417,7 +416,6 @@ i915_gem_create(struct drm_file *file, if (obj == NULL) return -ENOMEM; - obj->base.dumb = dumb; ret = drm_gem_handle_create(file, &obj->base, &handle); /* drop reference from allocate - handle holds it now */ drm_gem_object_unreference_unlocked(&obj->base); @@ -437,7 +435,7 @@ i915_gem_dumb_create(struct drm_file *file, args->pitch = ALIGN(args->width * DIV_ROUND_UP(args->bpp, 8), 64); args->size = args->pitch * args->height; return i915_gem_create(file, dev, - args->size, true, &args->handle); + args->size, &args->handle); } /** @@ -450,7 +448,7 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data, struct drm_i915_gem_create *args = data; return i915_gem_create(file, dev, - args->size, false, &args->handle); + args->size, &args->handle); } static inline int @@ -1840,10 +1838,10 @@ static void i915_gem_object_free_mmap_offset(struct drm_i915_gem_object *obj) drm_gem_free_mmap_offset(&obj->base); } -static int +int i915_gem_mmap_gtt(struct drm_file *file, struct drm_device *dev, - uint32_t handle, bool dumb, + uint32_t handle, uint64_t *offset) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1860,13 +1858,6 @@ i915_gem_mmap_gtt(struct drm_file *file, goto unlock; } - /* - * We don't allow dumb mmaps on objects created using another - * interface. - */ - WARN_ONCE(dumb && !(obj->base.dumb || obj->base.import_attach), - "Illegal dumb map of accelerated buffer.\n"); - if (obj->base.size > dev_priv->gtt.mappable_end) { ret = -E2BIG; goto out; @@ -1891,15 +1882,6 @@ unlock: return ret; } -int -i915_gem_dumb_map_offset(struct drm_file *file, - struct drm_device *dev, - uint32_t handle, - uint64_t *offset) -{ - return i915_gem_mmap_gtt(file, dev, handle, true, offset); -} - /** * i915_gem_mmap_gtt_ioctl - prepare an object for GTT mmap'ing * @dev: DRM device @@ -1921,7 +1903,7 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, { struct drm_i915_gem_mmap_gtt *args = data; - return i915_gem_mmap_gtt(file, dev, args->handle, false, &args->offset); + return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset); } static inline int diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index d17ff435f276..d011ec82ef1e 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -473,7 +473,12 @@ mi_set_context(struct intel_engine_cs *ring, u32 hw_flags) { u32 flags = hw_flags | MI_MM_SPACE_GTT; - int ret; + const int num_rings = + /* Use an extended w/a on ivb+ if signalling from other rings */ + i915_semaphore_is_enabled(ring->dev) ? + hweight32(INTEL_INFO(ring->dev)->ring_mask) - 1 : + 0; + int len, i, ret; /* w/a: If Flush TLB Invalidation Mode is enabled, driver must do a TLB * invalidation prior to MI_SET_CONTEXT. On GEN6 we don't set the value @@ -490,15 +495,31 @@ mi_set_context(struct intel_engine_cs *ring, if (!IS_HASWELL(ring->dev) && INTEL_INFO(ring->dev)->gen < 8) flags |= (MI_SAVE_EXT_STATE_EN | MI_RESTORE_EXT_STATE_EN); - ret = intel_ring_begin(ring, 6); + + len = 4; + if (INTEL_INFO(ring->dev)->gen >= 7) + len += 2 + (num_rings ? 4*num_rings + 2 : 0); + + ret = intel_ring_begin(ring, len); if (ret) return ret; /* WaProgramMiArbOnOffAroundMiSetContext:ivb,vlv,hsw,bdw,chv */ - if (INTEL_INFO(ring->dev)->gen >= 7) + if (INTEL_INFO(ring->dev)->gen >= 7) { intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_DISABLE); - else - intel_ring_emit(ring, MI_NOOP); + if (num_rings) { + struct intel_engine_cs *signaller; + + intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(num_rings)); + for_each_ring(signaller, to_i915(ring->dev), i) { + if (signaller == ring) + continue; + + intel_ring_emit(ring, RING_PSMI_CTL(signaller->mmio_base)); + intel_ring_emit(ring, _MASKED_BIT_ENABLE(GEN6_PSMI_SLEEP_MSG_DISABLE)); + } + } + } intel_ring_emit(ring, MI_NOOP); intel_ring_emit(ring, MI_SET_CONTEXT); @@ -510,10 +531,21 @@ mi_set_context(struct intel_engine_cs *ring, */ intel_ring_emit(ring, MI_NOOP); - if (INTEL_INFO(ring->dev)->gen >= 7) + if (INTEL_INFO(ring->dev)->gen >= 7) { + if (num_rings) { + struct intel_engine_cs *signaller; + + intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(num_rings)); + for_each_ring(signaller, to_i915(ring->dev), i) { + if (signaller == ring) + continue; + + intel_ring_emit(ring, RING_PSMI_CTL(signaller->mmio_base)); + intel_ring_emit(ring, _MASKED_BIT_DISABLE(GEN6_PSMI_SLEEP_MSG_DISABLE)); + } + } intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_ENABLE); - else - intel_ring_emit(ring, MI_NOOP); + } intel_ring_advance(ring); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index f06027ba3ee5..11738316394a 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -121,9 +121,6 @@ eb_lookup_vmas(struct eb_vmas *eb, goto err; } - WARN_ONCE(obj->base.dumb, - "GPU use of dumb buffer is illegal.\n"); - drm_gem_object_reference(&obj->base); list_add_tail(&obj->obj_exec_link, &objects); } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 981834b0f9b6..996c2931c499 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -281,10 +281,14 @@ void gen6_enable_rps_interrupts(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; spin_lock_irq(&dev_priv->irq_lock); + WARN_ON(dev_priv->rps.pm_iir); WARN_ON(I915_READ(gen6_pm_iir(dev_priv)) & dev_priv->pm_rps_events); dev_priv->rps.interrupts_enabled = true; + I915_WRITE(gen6_pm_ier(dev_priv), I915_READ(gen6_pm_ier(dev_priv)) | + dev_priv->pm_rps_events); gen6_enable_pm_irq(dev_priv, dev_priv->pm_rps_events); + spin_unlock_irq(&dev_priv->irq_lock); } @@ -3307,8 +3311,10 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev) GEN5_IRQ_INIT(GT, dev_priv->gt_irq_mask, gt_irqs); if (INTEL_INFO(dev)->gen >= 6) { - pm_irqs |= dev_priv->pm_rps_events; - + /* + * RPS interrupts will get enabled/disabled on demand when RPS + * itself is enabled/disabled. + */ if (HAS_VEBOX(dev)) pm_irqs |= PM_VEBOX_USER_INTERRUPT; @@ -3520,7 +3526,11 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv) dev_priv->pm_irq_mask = 0xffffffff; GEN8_IRQ_INIT_NDX(GT, 0, ~gt_interrupts[0], gt_interrupts[0]); GEN8_IRQ_INIT_NDX(GT, 1, ~gt_interrupts[1], gt_interrupts[1]); - GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_irq_mask, dev_priv->pm_rps_events); + /* + * RPS interrupts will get enabled/disabled on demand when RPS itself + * is enabled/disabled. + */ + GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_irq_mask, 0); GEN8_IRQ_INIT_NDX(GT, 3, ~gt_interrupts[3], gt_interrupts[3]); } @@ -3609,7 +3619,7 @@ static void vlv_display_irq_uninstall(struct drm_i915_private *dev_priv) vlv_display_irq_reset(dev_priv); - dev_priv->irq_mask = 0; + dev_priv->irq_mask = ~0; } static void valleyview_irq_uninstall(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index eefdc238f70b..172de3b3433b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -395,6 +395,7 @@ #define PIPE_CONTROL_STORE_DATA_INDEX (1<<21) #define PIPE_CONTROL_CS_STALL (1<<20) #define PIPE_CONTROL_TLB_INVALIDATE (1<<18) +#define PIPE_CONTROL_MEDIA_STATE_CLEAR (1<<16) #define PIPE_CONTROL_QW_WRITE (1<<14) #define PIPE_CONTROL_POST_SYNC_OP_MASK (3<<14) #define PIPE_CONTROL_DEPTH_STALL (1<<13) @@ -1128,6 +1129,7 @@ enum punit_power_well { #define GEN6_VERSYNC (RING_SYNC_1(VEBOX_RING_BASE)) #define GEN6_VEVSYNC (RING_SYNC_2(VEBOX_RING_BASE)) #define GEN6_NOSYNC 0 +#define RING_PSMI_CTL(base) ((base)+0x50) #define RING_MAX_IDLE(base) ((base)+0x54) #define RING_HWS_PGA(base) ((base)+0x80) #define RING_HWS_PGA_GEN6(base) ((base)+0x2080) @@ -1458,6 +1460,7 @@ enum punit_power_well { #define GEN6_BLITTER_FBC_NOTIFY (1<<3) #define GEN6_RC_SLEEP_PSMI_CONTROL 0x2050 +#define GEN6_PSMI_SLEEP_MSG_DISABLE (1 << 0) #define GEN8_RC_SEMA_IDLE_MSG_DISABLE (1 << 12) #define GEN8_FF_DOP_CLOCK_GATE_DISABLE (1<<10) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 1f4b56e273c8..964b28e3c630 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6191,6 +6191,20 @@ void intel_cleanup_gt_powersave(struct drm_device *dev) valleyview_cleanup_gt_powersave(dev); } +static void gen6_suspend_rps(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + flush_delayed_work(&dev_priv->rps.delayed_resume_work); + + /* + * TODO: disable RPS interrupts on GEN9+ too once RPS support + * is added for it. + */ + if (INTEL_INFO(dev)->gen < 9) + gen6_disable_rps_interrupts(dev); +} + /** * intel_suspend_gt_powersave - suspend PM work and helper threads * @dev: drm device @@ -6206,14 +6220,7 @@ void intel_suspend_gt_powersave(struct drm_device *dev) if (INTEL_INFO(dev)->gen < 6) return; - flush_delayed_work(&dev_priv->rps.delayed_resume_work); - - /* - * TODO: disable RPS interrupts on GEN9+ too once RPS support - * is added for it. - */ - if (INTEL_INFO(dev)->gen < 9) - gen6_disable_rps_interrupts(dev); + gen6_suspend_rps(dev); /* Force GPU to min freq during suspend */ gen6_rps_idle(dev_priv); @@ -6316,8 +6323,11 @@ void intel_reset_gt_powersave(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + if (INTEL_INFO(dev)->gen < 6) + return; + + gen6_suspend_rps(dev); dev_priv->rps.enabled = false; - intel_enable_gt_powersave(dev); } static void ibx_init_clock_gating(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 9f445e9a75d1..c7bc93d28d84 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -362,12 +362,15 @@ gen7_render_ring_flush(struct intel_engine_cs *ring, flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE; flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE; flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE; + flags |= PIPE_CONTROL_MEDIA_STATE_CLEAR; /* * TLB invalidate requires a post-sync write. */ flags |= PIPE_CONTROL_QW_WRITE; flags |= PIPE_CONTROL_GLOBAL_GTT_IVB; + flags |= PIPE_CONTROL_STALL_AT_SCOREBOARD; + /* Workaround: we must issue a pipe_control with CS-stall bit * set before a pipe_control command that has the state cache * invalidate bit set. */ diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index aa873048308b..94a5bee69fe7 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -386,9 +386,7 @@ void adreno_gpu_cleanup(struct adreno_gpu *gpu) msm_gem_put_iova(gpu->memptrs_bo, gpu->base.id); drm_gem_object_unreference(gpu->memptrs_bo); } - if (gpu->pm4) - release_firmware(gpu->pm4); - if (gpu->pfp) - release_firmware(gpu->pfp); + release_firmware(gpu->pm4); + release_firmware(gpu->pfp); msm_gpu_cleanup(&gpu->base); } diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c index fbebb0405d76..b4e70e0e3cfa 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c @@ -141,6 +141,15 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector) uint32_t hpd_ctrl; int i, ret; + for (i = 0; i < config->hpd_reg_cnt; i++) { + ret = regulator_enable(hdmi->hpd_regs[i]); + if (ret) { + dev_err(dev->dev, "failed to enable hpd regulator: %s (%d)\n", + config->hpd_reg_names[i], ret); + goto fail; + } + } + ret = gpio_config(hdmi, true); if (ret) { dev_err(dev->dev, "failed to configure GPIOs: %d\n", ret); @@ -164,15 +173,6 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector) } } - for (i = 0; i < config->hpd_reg_cnt; i++) { - ret = regulator_enable(hdmi->hpd_regs[i]); - if (ret) { - dev_err(dev->dev, "failed to enable hpd regulator: %s (%d)\n", - config->hpd_reg_names[i], ret); - goto fail; - } - } - hdmi_set_mode(hdmi, false); phy->funcs->reset(phy); hdmi_set_mode(hdmi, true); @@ -200,7 +200,7 @@ fail: return ret; } -static int hdp_disable(struct hdmi_connector *hdmi_connector) +static void hdp_disable(struct hdmi_connector *hdmi_connector) { struct hdmi *hdmi = hdmi_connector->hdmi; const struct hdmi_platform_config *config = hdmi->config; @@ -212,28 +212,19 @@ static int hdp_disable(struct hdmi_connector *hdmi_connector) hdmi_set_mode(hdmi, false); - for (i = 0; i < config->hpd_reg_cnt; i++) { - ret = regulator_disable(hdmi->hpd_regs[i]); - if (ret) { - dev_err(dev->dev, "failed to disable hpd regulator: %s (%d)\n", - config->hpd_reg_names[i], ret); - goto fail; - } - } - for (i = 0; i < config->hpd_clk_cnt; i++) clk_disable_unprepare(hdmi->hpd_clks[i]); ret = gpio_config(hdmi, false); - if (ret) { - dev_err(dev->dev, "failed to unconfigure GPIOs: %d\n", ret); - goto fail; - } - - return 0; + if (ret) + dev_warn(dev->dev, "failed to unconfigure GPIOs: %d\n", ret); -fail: - return ret; + for (i = 0; i < config->hpd_reg_cnt; i++) { + ret = regulator_disable(hdmi->hpd_regs[i]); + if (ret) + dev_warn(dev->dev, "failed to disable hpd regulator: %s (%d)\n", + config->hpd_reg_names[i], ret); + } } static void @@ -260,11 +251,11 @@ void hdmi_connector_irq(struct drm_connector *connector) (hpd_int_status & HDMI_HPD_INT_STATUS_INT)) { bool detected = !!(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED); - DBG("status=%04x, ctrl=%04x", hpd_int_status, hpd_int_ctrl); - - /* ack the irq: */ + /* ack & disable (temporarily) HPD events: */ hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, - hpd_int_ctrl | HDMI_HPD_INT_CTRL_INT_ACK); + HDMI_HPD_INT_CTRL_INT_ACK); + + DBG("status=%04x, ctrl=%04x", hpd_int_status, hpd_int_ctrl); /* detect disconnect if we are connected or visa versa: */ hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN; diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c index a7672e100d8b..3449213f1e76 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c @@ -331,17 +331,8 @@ static int mdp4_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); - struct drm_device *dev = crtc->dev; - DBG("%s: check", mdp4_crtc->name); - - if (mdp4_crtc->event) { - dev_err(dev->dev, "already pending flip!\n"); - return -EBUSY; - } - // TODO anything else to check? - return 0; } @@ -357,7 +348,7 @@ static void mdp4_crtc_atomic_flush(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; unsigned long flags; - DBG("%s: flush", mdp4_crtc->name); + DBG("%s: event: %p", mdp4_crtc->name, crtc->state->event); WARN_ON(mdp4_crtc->event); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index 0e9a2e3a82d7..f021f960a8a2 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -303,11 +303,6 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc, DBG("%s: check", mdp5_crtc->name); - if (mdp5_crtc->event) { - dev_err(dev->dev, "already pending flip!\n"); - return -EBUSY; - } - /* request a free CTL, if none is already allocated for this CRTC */ if (state->enable && !mdp5_crtc->ctl) { mdp5_crtc->ctl = mdp5_ctlm_request(mdp5_kms->ctlm, crtc); @@ -364,7 +359,7 @@ static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; unsigned long flags; - DBG("%s: flush", mdp5_crtc->name); + DBG("%s: event: %p", mdp5_crtc->name, crtc->state->event); WARN_ON(mdp5_crtc->event); @@ -460,10 +455,7 @@ void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf, /* now that we know what irq's we want: */ mdp5_crtc->err.irqmask = intf2err(intf); mdp5_crtc->vblank.irqmask = intf2vblank(intf); - - /* when called from modeset_init(), skip the rest until later: */ - if (!mdp5_kms) - return; + mdp_irq_update(&mdp5_kms->base); spin_lock_irqsave(&mdp5_kms->resource_lock, flags); intf_sel = mdp5_read(mdp5_kms, REG_MDP5_DISP_INTF_SEL); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index a11f1b80c488..9f01a4f21af2 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -216,17 +216,7 @@ static int modeset_init(struct mdp5_kms *mdp5_kms) goto fail; } - /* NOTE: the vsync and error irq's are actually associated with - * the INTF/encoder.. the easiest way to deal with this (ie. what - * we do now) is assume a fixed relationship between crtc's and - * encoders. I'm not sure if there is ever a need to more freely - * assign crtcs to encoders, but if there is then we need to take - * care of error and vblank irq's that the crtc has registered, - * and also update user-requested vblank_mask. - */ - encoder->possible_crtcs = BIT(0); - mdp5_crtc_set_intf(priv->crtcs[0], 3, INTF_HDMI); - + encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;; priv->encoders[priv->num_encoders++] = encoder; /* Construct bridge/connector for HDMI: */ diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.c b/drivers/gpu/drm/msm/mdp/mdp_kms.c index 03455b64a245..2a731722d840 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp_kms.c @@ -42,7 +42,10 @@ static void update_irq(struct mdp_kms *mdp_kms) mdp_kms->funcs->set_irqmask(mdp_kms, irqmask); } -static void update_irq_unlocked(struct mdp_kms *mdp_kms) +/* if an mdp_irq's irqmask has changed, such as when mdp5 crtc<->encoder + * link changes, this must be called to figure out the new global irqmask + */ +void mdp_irq_update(struct mdp_kms *mdp_kms) { unsigned long flags; spin_lock_irqsave(&list_lock, flags); @@ -122,7 +125,7 @@ void mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq) spin_unlock_irqrestore(&list_lock, flags); if (needs_update) - update_irq_unlocked(mdp_kms); + mdp_irq_update(mdp_kms); } void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq) @@ -141,5 +144,5 @@ void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq) spin_unlock_irqrestore(&list_lock, flags); if (needs_update) - update_irq_unlocked(mdp_kms); + mdp_irq_update(mdp_kms); } diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.h b/drivers/gpu/drm/msm/mdp/mdp_kms.h index 99557b5ad4fd..b268ce95d394 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp_kms.h @@ -75,7 +75,7 @@ void mdp_update_vblank_mask(struct mdp_kms *mdp_kms, uint32_t mask, bool enable) void mdp_irq_wait(struct mdp_kms *mdp_kms, uint32_t irqmask); void mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq); void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq); - +void mdp_irq_update(struct mdp_kms *mdp_kms); /* * pixel format helpers: diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index f0de412e13dc..191968256c58 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -23,10 +23,41 @@ struct msm_commit { struct drm_atomic_state *state; uint32_t fence; struct msm_fence_cb fence_cb; + uint32_t crtc_mask; }; static void fence_cb(struct msm_fence_cb *cb); +/* block until specified crtcs are no longer pending update, and + * atomically mark them as pending update + */ +static int start_atomic(struct msm_drm_private *priv, uint32_t crtc_mask) +{ + int ret; + + spin_lock(&priv->pending_crtcs_event.lock); + ret = wait_event_interruptible_locked(priv->pending_crtcs_event, + !(priv->pending_crtcs & crtc_mask)); + if (ret == 0) { + DBG("start: %08x", crtc_mask); + priv->pending_crtcs |= crtc_mask; + } + spin_unlock(&priv->pending_crtcs_event.lock); + + return ret; +} + +/* clear specified crtcs (no longer pending update) + */ +static void end_atomic(struct msm_drm_private *priv, uint32_t crtc_mask) +{ + spin_lock(&priv->pending_crtcs_event.lock); + DBG("end: %08x", crtc_mask); + priv->pending_crtcs &= ~crtc_mask; + wake_up_all_locked(&priv->pending_crtcs_event); + spin_unlock(&priv->pending_crtcs_event.lock); +} + static struct msm_commit *new_commit(struct drm_atomic_state *state) { struct msm_commit *c = kzalloc(sizeof(*c), GFP_KERNEL); @@ -58,12 +89,27 @@ static void complete_commit(struct msm_commit *c) drm_atomic_helper_commit_post_planes(dev, state); + /* NOTE: _wait_for_vblanks() only waits for vblank on + * enabled CRTCs. So we end up faulting when disabling + * due to (potentially) unref'ing the outgoing fb's + * before the vblank when the disable has latched. + * + * But if it did wait on disabled (or newly disabled) + * CRTCs, that would be racy (ie. we could have missed + * the irq. We need some way to poll for pipe shut + * down. Or just live with occasionally hitting the + * timeout in the CRTC disable path (which really should + * not be critical path) + */ + drm_atomic_helper_wait_for_vblanks(dev, state); drm_atomic_helper_cleanup_planes(dev, state); drm_atomic_state_free(state); + end_atomic(dev->dev_private, c->crtc_mask); + kfree(c); } @@ -97,8 +143,9 @@ static void add_fb(struct msm_commit *c, struct drm_framebuffer *fb) int msm_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, bool async) { - struct msm_commit *c; int nplanes = dev->mode_config.num_total_plane; + int ncrtcs = dev->mode_config.num_crtc; + struct msm_commit *c; int i, ret; ret = drm_atomic_helper_prepare_planes(dev, state); @@ -106,6 +153,18 @@ int msm_atomic_commit(struct drm_device *dev, return ret; c = new_commit(state); + if (!c) + return -ENOMEM; + + /* + * Figure out what crtcs we have: + */ + for (i = 0; i < ncrtcs; i++) { + struct drm_crtc *crtc = state->crtcs[i]; + if (!crtc) + continue; + c->crtc_mask |= (1 << drm_crtc_index(crtc)); + } /* * Figure out what fence to wait for: @@ -122,6 +181,14 @@ int msm_atomic_commit(struct drm_device *dev, } /* + * Wait for pending updates on any of the same crtc's and then + * mark our set of crtc's as busy: + */ + ret = start_atomic(dev->dev_private, c->crtc_mask); + if (ret) + return ret; + + /* * This is the point of no return - everything below never fails except * when the hw goes bonghits. Which means we can commit the new state on * the software side now. diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index c795217e1bfc..9a61546a0b05 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -193,6 +193,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags) priv->wq = alloc_ordered_workqueue("msm", 0); init_waitqueue_head(&priv->fence_event); + init_waitqueue_head(&priv->pending_crtcs_event); INIT_LIST_HEAD(&priv->inactive_list); INIT_LIST_HEAD(&priv->fence_cbs); diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 136303818436..b69ef2d5a26c 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -96,6 +96,10 @@ struct msm_drm_private { /* callbacks deferred until bo is inactive: */ struct list_head fence_cbs; + /* crtcs pending async atomic updates: */ + uint32_t pending_crtcs; + wait_queue_head_t pending_crtcs_event; + /* registered MMUs: */ unsigned int num_mmus; struct msm_mmu *mmus[NUM_DOMAINS]; diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index 94d55e526b4e..1f3af13ccede 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -190,8 +190,7 @@ fail_unlock: fail: if (ret) { - if (fbi) - framebuffer_release(fbi); + framebuffer_release(fbi); if (fb) { drm_framebuffer_unregister_private(fb); drm_framebuffer_remove(fb); diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 4a6f0e49d5b5..49dea4fb55ac 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -535,8 +535,7 @@ void msm_gem_free_object(struct drm_gem_object *obj) drm_free_large(msm_obj->pages); } else { - if (msm_obj->vaddr) - vunmap(msm_obj->vaddr); + vunmap(msm_obj->vaddr); put_pages(obj); } diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 5d93902a91ab..f8042433752b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -876,7 +876,6 @@ nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev, if (ret) return ret; - bo->gem.dumb = true; ret = drm_gem_handle_create(file_priv, &bo->gem, &args->handle); drm_gem_object_unreference_unlocked(&bo->gem); return ret; @@ -892,14 +891,6 @@ nouveau_display_dumb_map_offset(struct drm_file *file_priv, gem = drm_gem_object_lookup(dev, file_priv, handle); if (gem) { struct nouveau_bo *bo = nouveau_gem_object(gem); - - /* - * We don't allow dumb mmaps on objects created using another - * interface. - */ - WARN_ONCE(!(gem->dumb || gem->import_attach), - "Illegal dumb map of accelerated buffer.\n"); - *poffset = drm_vma_node_offset_addr(&bo->bo.vma_node); drm_gem_object_unreference_unlocked(gem); return 0; diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 28d51a22a4bf..42c34babc2e5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -444,9 +444,6 @@ validate_list(struct nouveau_channel *chan, struct nouveau_cli *cli, list_for_each_entry(nvbo, list, entry) { struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index]; - WARN_ONCE(nvbo->gem.dumb, - "GPU use of dumb buffer is illegal.\n"); - ret = nouveau_gem_set_domain(&nvbo->gem, b->read_domains, b->write_domains, b->valid_domains); diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index 753a6def61e7..3d1cfcb96b6b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -28,6 +28,7 @@ #include "nouveau_ttm.h" #include "nouveau_gem.h" +#include "drm_legacy.h" static int nouveau_vram_manager_init(struct ttm_mem_type_manager *man, unsigned long psize) { @@ -281,7 +282,7 @@ nouveau_ttm_mmap(struct file *filp, struct vm_area_struct *vma) struct nouveau_drm *drm = nouveau_drm(file_priv->minor->dev); if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) - return -EINVAL; + return drm_legacy_mmap(filp, vma); return ttm_bo_mmap(filp, vma, &drm->ttm.bdev); } diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index fe48f229043e..a46f73737994 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -394,10 +394,9 @@ int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, return r; } -static int radeon_mode_mmap(struct drm_file *filp, - struct drm_device *dev, - uint32_t handle, bool dumb, - uint64_t *offset_p) +int radeon_mode_dumb_mmap(struct drm_file *filp, + struct drm_device *dev, + uint32_t handle, uint64_t *offset_p) { struct drm_gem_object *gobj; struct radeon_bo *robj; @@ -406,14 +405,6 @@ static int radeon_mode_mmap(struct drm_file *filp, if (gobj == NULL) { return -ENOENT; } - - /* - * We don't allow dumb mmaps on objects created using another - * interface. - */ - WARN_ONCE(dumb && !(gobj->dumb || gobj->import_attach), - "Illegal dumb map of GPU buffer.\n"); - robj = gem_to_radeon_bo(gobj); if (radeon_ttm_tt_has_userptr(robj->tbo.ttm)) { drm_gem_object_unreference_unlocked(gobj); @@ -424,20 +415,12 @@ static int radeon_mode_mmap(struct drm_file *filp, return 0; } -int radeon_mode_dumb_mmap(struct drm_file *filp, - struct drm_device *dev, - uint32_t handle, uint64_t *offset_p) -{ - return radeon_mode_mmap(filp, dev, handle, true, offset_p); -} - int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { struct drm_radeon_gem_mmap *args = data; - return radeon_mode_mmap(filp, dev, args->handle, false, - &args->addr_ptr); + return radeon_mode_dumb_mmap(filp, dev, args->handle, &args->addr_ptr); } int radeon_gem_busy_ioctl(struct drm_device *dev, void *data, @@ -763,7 +746,6 @@ int radeon_mode_dumb_create(struct drm_file *file_priv, return -ENOMEM; r = drm_gem_handle_create(file_priv, gobj, &handle); - gobj->dumb = true; /* drop reference from allocate - handle holds it now */ drm_gem_object_unreference_unlocked(gobj); if (r) { diff --git a/drivers/gpu/drm/radeon/radeon_kfd.c b/drivers/gpu/drm/radeon/radeon_kfd.c index 065d02068ec3..242fd8b1b221 100644 --- a/drivers/gpu/drm/radeon/radeon_kfd.c +++ b/drivers/gpu/drm/radeon/radeon_kfd.c @@ -28,6 +28,8 @@ #include "cikd.h" #include "cik_reg.h" #include "radeon_kfd.h" +#include "radeon_ucode.h" +#include <linux/firmware.h> #define CIK_PIPE_PER_MEC (4) @@ -49,6 +51,7 @@ static uint64_t get_vmem_size(struct kgd_dev *kgd); static uint64_t get_gpu_clock_counter(struct kgd_dev *kgd); static uint32_t get_max_engine_clock_in_mhz(struct kgd_dev *kgd); +static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type); /* * Register access functions @@ -91,6 +94,7 @@ static const struct kfd2kgd_calls kfd2kgd = { .hqd_load = kgd_hqd_load, .hqd_is_occupies = kgd_hqd_is_occupies, .hqd_destroy = kgd_hqd_destroy, + .get_fw_version = get_fw_version }; static const struct kgd2kfd_calls *kgd2kfd; @@ -561,3 +565,52 @@ static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type, release_queue(kgd); return 0; } + +static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type) +{ + struct radeon_device *rdev = (struct radeon_device *) kgd; + const union radeon_firmware_header *hdr; + + BUG_ON(kgd == NULL || rdev->mec_fw == NULL); + + switch (type) { + case KGD_ENGINE_PFP: + hdr = (const union radeon_firmware_header *) rdev->pfp_fw->data; + break; + + case KGD_ENGINE_ME: + hdr = (const union radeon_firmware_header *) rdev->me_fw->data; + break; + + case KGD_ENGINE_CE: + hdr = (const union radeon_firmware_header *) rdev->ce_fw->data; + break; + + case KGD_ENGINE_MEC1: + hdr = (const union radeon_firmware_header *) rdev->mec_fw->data; + break; + + case KGD_ENGINE_MEC2: + hdr = (const union radeon_firmware_header *) + rdev->mec2_fw->data; + break; + + case KGD_ENGINE_RLC: + hdr = (const union radeon_firmware_header *) rdev->rlc_fw->data; + break; + + case KGD_ENGINE_SDMA: + hdr = (const union radeon_firmware_header *) + rdev->sdma_fw->data; + break; + + default: + return 0; + } + + if (hdr == NULL) + return 0; + + /* Only 12 bit in use*/ + return hdr->common.ucode_version; +} diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 7d68223eb469..86fc56434b28 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -529,9 +529,6 @@ int radeon_bo_list_validate(struct radeon_device *rdev, u32 current_domain = radeon_mem_type_to_domain(bo->tbo.mem.mem_type); - WARN_ONCE(bo->gem_base.dumb, - "GPU use of dumb buffer is illegal.\n"); - /* Check if this buffer will be moved and don't move it * if we have moved too many buffers for this IB already. * diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 3367960286a6..978993fa3a36 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -168,7 +168,7 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, const struct tegra_dc_window *window) { unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp; - unsigned long value; + unsigned long value, flags; bool yuv, planar; /* @@ -181,6 +181,8 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, else bpp = planar ? 1 : 2; + spin_lock_irqsave(&dc->lock, flags); + value = WINDOW_A_SELECT << index; tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); @@ -273,6 +275,7 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, case TEGRA_BO_TILING_MODE_BLOCK: DRM_ERROR("hardware doesn't support block linear mode\n"); + spin_unlock_irqrestore(&dc->lock, flags); return -EINVAL; } @@ -331,6 +334,8 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, tegra_dc_window_commit(dc, index); + spin_unlock_irqrestore(&dc->lock, flags); + return 0; } @@ -338,11 +343,14 @@ static int tegra_window_plane_disable(struct drm_plane *plane) { struct tegra_dc *dc = to_tegra_dc(plane->crtc); struct tegra_plane *p = to_tegra_plane(plane); + unsigned long flags; u32 value; if (!plane->crtc) return 0; + spin_lock_irqsave(&dc->lock, flags); + value = WINDOW_A_SELECT << p->index; tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); @@ -352,6 +360,8 @@ static int tegra_window_plane_disable(struct drm_plane *plane) tegra_dc_window_commit(dc, p->index); + spin_unlock_irqrestore(&dc->lock, flags); + return 0; } @@ -699,14 +709,16 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y, struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); unsigned int h_offset = 0, v_offset = 0; struct tegra_bo_tiling tiling; + unsigned long value, flags; unsigned int format, swap; - unsigned long value; int err; err = tegra_fb_get_tiling(fb, &tiling); if (err < 0) return err; + spin_lock_irqsave(&dc->lock, flags); + tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER); value = fb->offsets[0] + y * fb->pitches[0] + @@ -752,6 +764,7 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y, case TEGRA_BO_TILING_MODE_BLOCK: DRM_ERROR("hardware doesn't support block linear mode\n"); + spin_unlock_irqrestore(&dc->lock, flags); return -EINVAL; } @@ -778,6 +791,8 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y, tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL); tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); + spin_unlock_irqrestore(&dc->lock, flags); + return 0; } @@ -814,23 +829,32 @@ static void tegra_dc_finish_page_flip(struct tegra_dc *dc) unsigned long flags, base; struct tegra_bo *bo; - if (!dc->event) + spin_lock_irqsave(&drm->event_lock, flags); + + if (!dc->event) { + spin_unlock_irqrestore(&drm->event_lock, flags); return; + } bo = tegra_fb_get_plane(crtc->primary->fb, 0); + spin_lock_irqsave(&dc->lock, flags); + /* check if new start address has been latched */ + tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER); tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS); base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR); tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS); + spin_unlock_irqrestore(&dc->lock, flags); + if (base == bo->paddr + crtc->primary->fb->offsets[0]) { - spin_lock_irqsave(&drm->event_lock, flags); - drm_send_vblank_event(drm, dc->pipe, dc->event); - drm_vblank_put(drm, dc->pipe); + drm_crtc_send_vblank_event(crtc, dc->event); + drm_crtc_vblank_put(crtc); dc->event = NULL; - spin_unlock_irqrestore(&drm->event_lock, flags); } + + spin_unlock_irqrestore(&drm->event_lock, flags); } void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file) @@ -843,7 +867,7 @@ void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file) if (dc->event && dc->event->base.file_priv == file) { dc->event->base.destroy(&dc->event->base); - drm_vblank_put(drm, dc->pipe); + drm_crtc_vblank_put(crtc); dc->event = NULL; } @@ -853,16 +877,16 @@ void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file) static int tegra_dc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t page_flip_flags) { + unsigned int pipe = drm_crtc_index(crtc); struct tegra_dc *dc = to_tegra_dc(crtc); - struct drm_device *drm = crtc->dev; if (dc->event) return -EBUSY; if (event) { - event->pipe = dc->pipe; + event->pipe = pipe; dc->event = event; - drm_vblank_get(drm, dc->pipe); + drm_crtc_vblank_get(crtc); } tegra_dc_set_base(dc, 0, 0, fb); @@ -1127,7 +1151,7 @@ static irqreturn_t tegra_dc_irq(int irq, void *data) /* dev_dbg(dc->dev, "%s(): vertical blank\n", __func__); */ - drm_handle_vblank(dc->base.dev, dc->pipe); + drm_crtc_handle_vblank(&dc->base); tegra_dc_finish_page_flip(dc); } diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index e549afeece1f..d4f827593dfa 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -694,24 +694,28 @@ static const struct file_operations tegra_drm_fops = { .llseek = noop_llseek, }; -static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm, int pipe) +static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm, + unsigned int pipe) { struct drm_crtc *crtc; list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) { - struct tegra_dc *dc = to_tegra_dc(crtc); - - if (dc->pipe == pipe) + if (pipe == drm_crtc_index(crtc)) return crtc; } return NULL; } -static u32 tegra_drm_get_vblank_counter(struct drm_device *dev, int crtc) +static u32 tegra_drm_get_vblank_counter(struct drm_device *drm, int pipe) { + struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe); + + if (!crtc) + return 0; + /* TODO: implement real hardware counter using syncpoints */ - return drm_vblank_count(dev, crtc); + return drm_crtc_vblank_count(crtc); } static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe) diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index da32086cbeaf..8777b7f75791 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -216,32 +216,58 @@ static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo) } } -static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo, - size_t size) +static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo) { + struct scatterlist *s; + struct sg_table *sgt; + unsigned int i; + bo->pages = drm_gem_get_pages(&bo->gem); if (IS_ERR(bo->pages)) return PTR_ERR(bo->pages); - bo->num_pages = size >> PAGE_SHIFT; - - bo->sgt = drm_prime_pages_to_sg(bo->pages, bo->num_pages); - if (IS_ERR(bo->sgt)) { - drm_gem_put_pages(&bo->gem, bo->pages, false, false); - return PTR_ERR(bo->sgt); + bo->num_pages = bo->gem.size >> PAGE_SHIFT; + + sgt = drm_prime_pages_to_sg(bo->pages, bo->num_pages); + if (IS_ERR(sgt)) + goto put_pages; + + /* + * Fake up the SG table so that dma_map_sg() can be used to flush the + * pages associated with it. Note that this relies on the fact that + * the DMA API doesn't hook into IOMMU on Tegra, therefore mapping is + * only cache maintenance. + * + * TODO: Replace this by drm_clflash_sg() once it can be implemented + * without relying on symbols that are not exported. + */ + for_each_sg(sgt->sgl, s, sgt->nents, i) + sg_dma_address(s) = sg_phys(s); + + if (dma_map_sg(drm->dev, sgt->sgl, sgt->nents, DMA_TO_DEVICE) == 0) { + sgt = ERR_PTR(-ENOMEM); + goto release_sgt; } + bo->sgt = sgt; + return 0; + +release_sgt: + sg_free_table(sgt); + kfree(sgt); +put_pages: + drm_gem_put_pages(&bo->gem, bo->pages, false, false); + return PTR_ERR(sgt); } -static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo, - size_t size) +static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo) { struct tegra_drm *tegra = drm->dev_private; int err; if (tegra->domain) { - err = tegra_bo_get_pages(drm, bo, size); + err = tegra_bo_get_pages(drm, bo); if (err < 0) return err; @@ -251,6 +277,8 @@ static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo, return err; } } else { + size_t size = bo->gem.size; + bo->vaddr = dma_alloc_writecombine(drm->dev, size, &bo->paddr, GFP_KERNEL | __GFP_NOWARN); if (!bo->vaddr) { @@ -274,7 +302,7 @@ struct tegra_bo *tegra_bo_create(struct drm_device *drm, size_t size, if (IS_ERR(bo)) return bo; - err = tegra_bo_alloc(drm, bo, size); + err = tegra_bo_alloc(drm, bo); if (err < 0) goto release; diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 8afa28e4570e..18d4b2c8fe55 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -28,6 +28,13 @@ #include <linux/cdev.h> #include "input-compat.h" +enum evdev_clock_type { + EV_CLK_REAL = 0, + EV_CLK_MONO, + EV_CLK_BOOT, + EV_CLK_MAX +}; + struct evdev { int open; struct input_handle handle; @@ -49,12 +56,32 @@ struct evdev_client { struct fasync_struct *fasync; struct evdev *evdev; struct list_head node; - int clkid; + int clk_type; bool revoked; unsigned int bufsize; struct input_event buffer[]; }; +static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) +{ + switch (clkid) { + + case CLOCK_REALTIME: + client->clk_type = EV_CLK_REAL; + break; + case CLOCK_MONOTONIC: + client->clk_type = EV_CLK_MONO; + break; + case CLOCK_BOOTTIME: + client->clk_type = EV_CLK_BOOT; + break; + default: + return -EINVAL; + } + + return 0; +} + /* flush queued events of type @type, caller must hold client->buffer_lock */ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) { @@ -108,8 +135,11 @@ static void evdev_queue_syn_dropped(struct evdev_client *client) struct input_event ev; ktime_t time; - time = (client->clkid == CLOCK_MONOTONIC) ? - ktime_get() : ktime_get_real(); + time = client->clk_type == EV_CLK_REAL ? + ktime_get_real() : + client->clk_type == EV_CLK_MONO ? + ktime_get() : + ktime_get_boottime(); ev.time = ktime_to_timeval(time); ev.type = EV_SYN; @@ -159,7 +189,7 @@ static void __pass_event(struct evdev_client *client, static void evdev_pass_values(struct evdev_client *client, const struct input_value *vals, unsigned int count, - ktime_t mono, ktime_t real) + ktime_t *ev_time) { struct evdev *evdev = client->evdev; const struct input_value *v; @@ -169,8 +199,7 @@ static void evdev_pass_values(struct evdev_client *client, if (client->revoked) return; - event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ? - mono : real); + event.time = ktime_to_timeval(ev_time[client->clk_type]); /* Interrupts are disabled, just acquire the lock. */ spin_lock(&client->buffer_lock); @@ -198,21 +227,22 @@ static void evdev_events(struct input_handle *handle, { struct evdev *evdev = handle->private; struct evdev_client *client; - ktime_t time_mono, time_real; + ktime_t ev_time[EV_CLK_MAX]; - time_mono = ktime_get(); - time_real = ktime_mono_to_real(time_mono); + ev_time[EV_CLK_MONO] = ktime_get(); + ev_time[EV_CLK_REAL] = ktime_mono_to_real(ev_time[EV_CLK_MONO]); + ev_time[EV_CLK_BOOT] = ktime_mono_to_any(ev_time[EV_CLK_MONO], + TK_OFFS_BOOT); rcu_read_lock(); client = rcu_dereference(evdev->grab); if (client) - evdev_pass_values(client, vals, count, time_mono, time_real); + evdev_pass_values(client, vals, count, ev_time); else list_for_each_entry_rcu(client, &evdev->client_list, node) - evdev_pass_values(client, vals, count, - time_mono, time_real); + evdev_pass_values(client, vals, count, ev_time); rcu_read_unlock(); } @@ -877,10 +907,8 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, case EVIOCSCLOCKID: if (copy_from_user(&i, p, sizeof(unsigned int))) return -EFAULT; - if (i != CLOCK_MONOTONIC && i != CLOCK_REALTIME) - return -EINVAL; - client->clkid = i; - return 0; + + return evdev_set_clk_type(client, i); case EVIOCGKEYCODE: return evdev_handle_get_keycode(dev, p); diff --git a/drivers/input/input.c b/drivers/input/input.c index 04217c2e345c..213e3a1903ee 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1974,18 +1974,22 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev) events = mt_slots + 1; /* count SYN_MT_REPORT and SYN_REPORT */ - for (i = 0; i < ABS_CNT; i++) { - if (test_bit(i, dev->absbit)) { - if (input_is_mt_axis(i)) - events += mt_slots; - else - events++; + if (test_bit(EV_ABS, dev->evbit)) { + for (i = 0; i < ABS_CNT; i++) { + if (test_bit(i, dev->absbit)) { + if (input_is_mt_axis(i)) + events += mt_slots; + else + events++; + } } } - for (i = 0; i < REL_CNT; i++) - if (test_bit(i, dev->relbit)) - events++; + if (test_bit(EV_REL, dev->evbit)) { + for (i = 0; i < REL_CNT; i++) + if (test_bit(i, dev->relbit)) + events++; + } /* Make room for KEY and MSC events */ events += 7; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 96ee26c555e0..a5d9b3f3c871 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -559,6 +559,7 @@ config KEYBOARD_SH_KEYSC config KEYBOARD_STMPE tristate "STMPE keypad support" depends on MFD_STMPE + depends on OF select INPUT_MATRIXKMAP help Say Y here if you want to use the keypad controller on STMPE I/O diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index d4dd78a7d56b..883d6aed5b9a 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -35,9 +35,13 @@ struct gpio_button_data { const struct gpio_keys_button *button; struct input_dev *input; - struct timer_list timer; - struct work_struct work; - unsigned int timer_debounce; /* in msecs */ + + struct timer_list release_timer; + unsigned int release_delay; /* in msecs, for IRQ-only buttons */ + + struct delayed_work work; + unsigned int software_debounce; /* in msecs, for GPIO-driven buttons */ + unsigned int irq; spinlock_t lock; bool disabled; @@ -116,11 +120,14 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata) { if (!bdata->disabled) { /* - * Disable IRQ and possible debouncing timer. + * Disable IRQ and associated timer/work structure. */ disable_irq(bdata->irq); - if (bdata->timer_debounce) - del_timer_sync(&bdata->timer); + + if (gpio_is_valid(bdata->button->gpio)) + cancel_delayed_work_sync(&bdata->work); + else + del_timer_sync(&bdata->release_timer); bdata->disabled = true; } @@ -343,7 +350,7 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata) static void gpio_keys_gpio_work_func(struct work_struct *work) { struct gpio_button_data *bdata = - container_of(work, struct gpio_button_data, work); + container_of(work, struct gpio_button_data, work.work); gpio_keys_gpio_report_event(bdata); @@ -351,13 +358,6 @@ static void gpio_keys_gpio_work_func(struct work_struct *work) pm_relax(bdata->input->dev.parent); } -static void gpio_keys_gpio_timer(unsigned long _data) -{ - struct gpio_button_data *bdata = (struct gpio_button_data *)_data; - - schedule_work(&bdata->work); -} - static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id) { struct gpio_button_data *bdata = dev_id; @@ -366,11 +366,10 @@ static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id) if (bdata->button->wakeup) pm_stay_awake(bdata->input->dev.parent); - if (bdata->timer_debounce) - mod_timer(&bdata->timer, - jiffies + msecs_to_jiffies(bdata->timer_debounce)); - else - schedule_work(&bdata->work); + + mod_delayed_work(system_wq, + &bdata->work, + msecs_to_jiffies(bdata->software_debounce)); return IRQ_HANDLED; } @@ -408,7 +407,7 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id) input_event(input, EV_KEY, button->code, 1); input_sync(input); - if (!bdata->timer_debounce) { + if (!bdata->release_delay) { input_event(input, EV_KEY, button->code, 0); input_sync(input); goto out; @@ -417,9 +416,9 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id) bdata->key_pressed = true; } - if (bdata->timer_debounce) - mod_timer(&bdata->timer, - jiffies + msecs_to_jiffies(bdata->timer_debounce)); + if (bdata->release_delay) + mod_timer(&bdata->release_timer, + jiffies + msecs_to_jiffies(bdata->release_delay)); out: spin_unlock_irqrestore(&bdata->lock, flags); return IRQ_HANDLED; @@ -429,10 +428,10 @@ static void gpio_keys_quiesce_key(void *data) { struct gpio_button_data *bdata = data; - if (bdata->timer_debounce) - del_timer_sync(&bdata->timer); - - cancel_work_sync(&bdata->work); + if (gpio_is_valid(bdata->button->gpio)) + cancel_delayed_work_sync(&bdata->work); + else + del_timer_sync(&bdata->release_timer); } static int gpio_keys_setup_key(struct platform_device *pdev, @@ -466,23 +465,25 @@ static int gpio_keys_setup_key(struct platform_device *pdev, button->debounce_interval * 1000); /* use timer if gpiolib doesn't provide debounce */ if (error < 0) - bdata->timer_debounce = + bdata->software_debounce = button->debounce_interval; } - irq = gpio_to_irq(button->gpio); - if (irq < 0) { - error = irq; - dev_err(dev, - "Unable to get irq number for GPIO %d, error %d\n", - button->gpio, error); - return error; + if (button->irq) { + bdata->irq = button->irq; + } else { + irq = gpio_to_irq(button->gpio); + if (irq < 0) { + error = irq; + dev_err(dev, + "Unable to get irq number for GPIO %d, error %d\n", + button->gpio, error); + return error; + } + bdata->irq = irq; } - bdata->irq = irq; - INIT_WORK(&bdata->work, gpio_keys_gpio_work_func); - setup_timer(&bdata->timer, - gpio_keys_gpio_timer, (unsigned long)bdata); + INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func); isr = gpio_keys_gpio_isr; irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; @@ -499,8 +500,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev, return -EINVAL; } - bdata->timer_debounce = button->debounce_interval; - setup_timer(&bdata->timer, + bdata->release_delay = button->debounce_interval; + setup_timer(&bdata->release_timer, gpio_keys_irq_timer, (unsigned long)bdata); isr = gpio_keys_irq_isr; @@ -510,7 +511,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev, input_set_capability(input, button->type ?: EV_KEY, button->code); /* - * Install custom action to cancel debounce timer and + * Install custom action to cancel release timer and * workqueue item. */ error = devm_add_action(&pdev->dev, gpio_keys_quiesce_key, bdata); @@ -618,33 +619,30 @@ gpio_keys_get_devtree_pdata(struct device *dev) i = 0; for_each_child_of_node(node, pp) { - int gpio = -1; enum of_gpio_flags flags; button = &pdata->buttons[i++]; - if (!of_find_property(pp, "gpios", NULL)) { - button->irq = irq_of_parse_and_map(pp, 0); - if (button->irq == 0) { - i--; - pdata->nbuttons--; - dev_warn(dev, "Found button without gpios or irqs\n"); - continue; - } - } else { - gpio = of_get_gpio_flags(pp, 0, &flags); - if (gpio < 0) { - error = gpio; + button->gpio = of_get_gpio_flags(pp, 0, &flags); + if (button->gpio < 0) { + error = button->gpio; + if (error != -ENOENT) { if (error != -EPROBE_DEFER) dev_err(dev, "Failed to get gpio flags, error: %d\n", error); return ERR_PTR(error); } + } else { + button->active_low = flags & OF_GPIO_ACTIVE_LOW; } - button->gpio = gpio; - button->active_low = flags & OF_GPIO_ACTIVE_LOW; + button->irq = irq_of_parse_and_map(pp, 0); + + if (!gpio_is_valid(button->gpio) && !button->irq) { + dev_err(dev, "Found button without gpios or irqs\n"); + return ERR_PTR(-EINVAL); + } if (of_property_read_u32(pp, "linux,code", &button->code)) { dev_err(dev, "Button without keycode: 0x%x\n", @@ -659,6 +657,8 @@ gpio_keys_get_devtree_pdata(struct device *dev) button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL); + button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL); + if (of_property_read_u32(pp, "debounce-interval", &button->debounce_interval)) button->debounce_interval = 5; diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c index 610a8af795a1..5b152f25a8e1 100644 --- a/drivers/input/keyboard/hil_kbd.c +++ b/drivers/input/keyboard/hil_kbd.c @@ -473,7 +473,7 @@ static int hil_dev_connect(struct serio *serio, struct serio_driver *drv) if (error) goto bail1; - init_completion(&dev->cmd_done); + reinit_completion(&dev->cmd_done); serio_write(serio, 0); serio_write(serio, 0); serio_write(serio, HIL_PKT_CMD >> 8); @@ -482,7 +482,7 @@ static int hil_dev_connect(struct serio *serio, struct serio_driver *drv) if (error) goto bail1; - init_completion(&dev->cmd_done); + reinit_completion(&dev->cmd_done); serio_write(serio, 0); serio_write(serio, 0); serio_write(serio, HIL_PKT_CMD >> 8); @@ -491,7 +491,7 @@ static int hil_dev_connect(struct serio *serio, struct serio_driver *drv) if (error) goto bail1; - init_completion(&dev->cmd_done); + reinit_completion(&dev->cmd_done); serio_write(serio, 0); serio_write(serio, 0); serio_write(serio, HIL_PKT_CMD >> 8); diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c index ef5e67fb567e..fe6e3f22eed7 100644 --- a/drivers/input/keyboard/stmpe-keypad.c +++ b/drivers/input/keyboard/stmpe-keypad.c @@ -45,13 +45,14 @@ #define STMPE_KEYPAD_MAX_ROWS 8 #define STMPE_KEYPAD_MAX_COLS 8 #define STMPE_KEYPAD_ROW_SHIFT 3 -#define STMPE_KEYPAD_KEYMAP_SIZE \ +#define STMPE_KEYPAD_KEYMAP_MAX_SIZE \ (STMPE_KEYPAD_MAX_ROWS * STMPE_KEYPAD_MAX_COLS) /** * struct stmpe_keypad_variant - model-specific attributes * @auto_increment: whether the KPC_DATA_BYTE register address * auto-increments on multiple read + * @set_pullup: whether the pins need to have their pull-ups set * @num_data: number of data bytes * @num_normal_data: number of normal keys' data bytes * @max_cols: maximum number of columns supported @@ -61,6 +62,7 @@ */ struct stmpe_keypad_variant { bool auto_increment; + bool set_pullup; int num_data; int num_normal_data; int max_cols; @@ -81,6 +83,7 @@ static const struct stmpe_keypad_variant stmpe_keypad_variants[] = { }, [STMPE2401] = { .auto_increment = false, + .set_pullup = true, .num_data = 3, .num_normal_data = 2, .max_cols = 8, @@ -90,6 +93,7 @@ static const struct stmpe_keypad_variant stmpe_keypad_variants[] = { }, [STMPE2403] = { .auto_increment = true, + .set_pullup = true, .num_data = 5, .num_normal_data = 3, .max_cols = 8, @@ -99,16 +103,30 @@ static const struct stmpe_keypad_variant stmpe_keypad_variants[] = { }, }; +/** + * struct stmpe_keypad - STMPE keypad state container + * @stmpe: pointer to parent STMPE device + * @input: spawned input device + * @variant: STMPE variant + * @debounce_ms: debounce interval, in ms. Maximum is + * %STMPE_KEYPAD_MAX_DEBOUNCE. + * @scan_count: number of key scanning cycles to confirm key data. + * Maximum is %STMPE_KEYPAD_MAX_SCAN_COUNT. + * @no_autorepeat: disable key autorepeat + * @rows: bitmask for the rows + * @cols: bitmask for the columns + * @keymap: the keymap + */ struct stmpe_keypad { struct stmpe *stmpe; struct input_dev *input; const struct stmpe_keypad_variant *variant; - const struct stmpe_keypad_platform_data *plat; - + unsigned int debounce_ms; + unsigned int scan_count; + bool no_autorepeat; unsigned int rows; unsigned int cols; - - unsigned short keymap[STMPE_KEYPAD_KEYMAP_SIZE]; + unsigned short keymap[STMPE_KEYPAD_KEYMAP_MAX_SIZE]; }; static int stmpe_keypad_read_data(struct stmpe_keypad *keypad, u8 *data) @@ -171,7 +189,10 @@ static int stmpe_keypad_altfunc_init(struct stmpe_keypad *keypad) unsigned int col_gpios = variant->col_gpios; unsigned int row_gpios = variant->row_gpios; struct stmpe *stmpe = keypad->stmpe; + u8 pureg = stmpe->regs[STMPE_IDX_GPPUR_LSB]; unsigned int pins = 0; + unsigned int pu_pins = 0; + int ret; int i; /* @@ -188,8 +209,10 @@ static int stmpe_keypad_altfunc_init(struct stmpe_keypad *keypad) for (i = 0; i < variant->max_cols; i++) { int num = __ffs(col_gpios); - if (keypad->cols & (1 << i)) + if (keypad->cols & (1 << i)) { pins |= 1 << num; + pu_pins |= 1 << num; + } col_gpios &= ~(1 << num); } @@ -203,20 +226,43 @@ static int stmpe_keypad_altfunc_init(struct stmpe_keypad *keypad) row_gpios &= ~(1 << num); } - return stmpe_set_altfunc(stmpe, pins, STMPE_BLOCK_KEYPAD); + ret = stmpe_set_altfunc(stmpe, pins, STMPE_BLOCK_KEYPAD); + if (ret) + return ret; + + /* + * On STMPE24xx, set pin bias to pull-up on all keypad input + * pins (columns), this incidentally happen to be maximum 8 pins + * and placed at GPIO0-7 so only the LSB of the pull up register + * ever needs to be written. + */ + if (variant->set_pullup) { + u8 val; + + ret = stmpe_reg_read(stmpe, pureg); + if (ret) + return ret; + + /* Do not touch unused pins, may be used for GPIO */ + val = ret & ~pu_pins; + val |= pu_pins; + + ret = stmpe_reg_write(stmpe, pureg, val); + } + + return 0; } static int stmpe_keypad_chip_init(struct stmpe_keypad *keypad) { - const struct stmpe_keypad_platform_data *plat = keypad->plat; const struct stmpe_keypad_variant *variant = keypad->variant; struct stmpe *stmpe = keypad->stmpe; int ret; - if (plat->debounce_ms > STMPE_KEYPAD_MAX_DEBOUNCE) + if (keypad->debounce_ms > STMPE_KEYPAD_MAX_DEBOUNCE) return -EINVAL; - if (plat->scan_count > STMPE_KEYPAD_MAX_SCAN_COUNT) + if (keypad->scan_count > STMPE_KEYPAD_MAX_SCAN_COUNT) return -EINVAL; ret = stmpe_enable(stmpe, STMPE_BLOCK_KEYPAD); @@ -245,7 +291,7 @@ static int stmpe_keypad_chip_init(struct stmpe_keypad *keypad) ret = stmpe_set_bits(stmpe, STMPE_KPC_CTRL_MSB, STMPE_KPC_CTRL_MSB_SCAN_COUNT, - plat->scan_count << 4); + keypad->scan_count << 4); if (ret < 0) return ret; @@ -253,17 +299,18 @@ static int stmpe_keypad_chip_init(struct stmpe_keypad *keypad) STMPE_KPC_CTRL_LSB_SCAN | STMPE_KPC_CTRL_LSB_DEBOUNCE, STMPE_KPC_CTRL_LSB_SCAN | - (plat->debounce_ms << 1)); + (keypad->debounce_ms << 1)); } -static void stmpe_keypad_fill_used_pins(struct stmpe_keypad *keypad) +static void stmpe_keypad_fill_used_pins(struct stmpe_keypad *keypad, + u32 used_rows, u32 used_cols) { int row, col; - for (row = 0; row < STMPE_KEYPAD_MAX_ROWS; row++) { - for (col = 0; col < STMPE_KEYPAD_MAX_COLS; col++) { + for (row = 0; row < used_rows; row++) { + for (col = 0; col < used_cols; col++) { int code = MATRIX_SCAN_CODE(row, col, - STMPE_KEYPAD_ROW_SHIFT); + STMPE_KEYPAD_ROW_SHIFT); if (keypad->keymap[code] != KEY_RESERVED) { keypad->rows |= 1 << row; keypad->cols |= 1 << col; @@ -272,51 +319,17 @@ static void stmpe_keypad_fill_used_pins(struct stmpe_keypad *keypad) } } -#ifdef CONFIG_OF -static const struct stmpe_keypad_platform_data * -stmpe_keypad_of_probe(struct device *dev) -{ - struct device_node *np = dev->of_node; - struct stmpe_keypad_platform_data *plat; - - if (!np) - return ERR_PTR(-ENODEV); - - plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL); - if (!plat) - return ERR_PTR(-ENOMEM); - - of_property_read_u32(np, "debounce-interval", &plat->debounce_ms); - of_property_read_u32(np, "st,scan-count", &plat->scan_count); - - plat->no_autorepeat = of_property_read_bool(np, "st,no-autorepeat"); - - return plat; -} -#else -static inline const struct stmpe_keypad_platform_data * -stmpe_keypad_of_probe(struct device *dev) -{ - return ERR_PTR(-EINVAL); -} -#endif - static int stmpe_keypad_probe(struct platform_device *pdev) { struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); - const struct stmpe_keypad_platform_data *plat; + struct device_node *np = pdev->dev.of_node; struct stmpe_keypad *keypad; struct input_dev *input; + u32 rows; + u32 cols; int error; int irq; - plat = stmpe->pdata->keypad; - if (!plat) { - plat = stmpe_keypad_of_probe(&pdev->dev); - if (IS_ERR(plat)) - return PTR_ERR(plat); - } - irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; @@ -326,6 +339,13 @@ static int stmpe_keypad_probe(struct platform_device *pdev) if (!keypad) return -ENOMEM; + keypad->stmpe = stmpe; + keypad->variant = &stmpe_keypad_variants[stmpe->partnum]; + + of_property_read_u32(np, "debounce-interval", &keypad->debounce_ms); + of_property_read_u32(np, "st,scan-count", &keypad->scan_count); + keypad->no_autorepeat = of_property_read_bool(np, "st,no-autorepeat"); + input = devm_input_allocate_device(&pdev->dev); if (!input) return -ENOMEM; @@ -334,23 +354,22 @@ static int stmpe_keypad_probe(struct platform_device *pdev) input->id.bustype = BUS_I2C; input->dev.parent = &pdev->dev; - error = matrix_keypad_build_keymap(plat->keymap_data, NULL, - STMPE_KEYPAD_MAX_ROWS, - STMPE_KEYPAD_MAX_COLS, + error = matrix_keypad_parse_of_params(&pdev->dev, &rows, &cols); + if (error) + return error; + + error = matrix_keypad_build_keymap(NULL, NULL, rows, cols, keypad->keymap, input); if (error) return error; input_set_capability(input, EV_MSC, MSC_SCAN); - if (!plat->no_autorepeat) + if (!keypad->no_autorepeat) __set_bit(EV_REP, input->evbit); - stmpe_keypad_fill_used_pins(keypad); + stmpe_keypad_fill_used_pins(keypad, rows, cols); - keypad->stmpe = stmpe; - keypad->plat = plat; keypad->input = input; - keypad->variant = &stmpe_keypad_variants[stmpe->partnum]; error = stmpe_keypad_chip_init(keypad); if (error < 0) diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index d125a019383f..d88d73d83552 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -881,6 +881,34 @@ static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt, unsigned char *pkt, unsigned char pkt_id) { + /* + * packet-fmt b7 b6 b5 b4 b3 b2 b1 b0 + * Byte0 TWO & MULTI L 1 R M 1 Y0-2 Y0-1 Y0-0 + * Byte0 NEW L 1 X1-5 1 1 Y0-2 Y0-1 Y0-0 + * Byte1 Y0-10 Y0-9 Y0-8 Y0-7 Y0-6 Y0-5 Y0-4 Y0-3 + * Byte2 X0-11 1 X0-10 X0-9 X0-8 X0-7 X0-6 X0-5 + * Byte3 X1-11 1 X0-4 X0-3 1 X0-2 X0-1 X0-0 + * Byte4 TWO X1-10 TWO X1-9 X1-8 X1-7 X1-6 X1-5 X1-4 + * Byte4 MULTI X1-10 TWO X1-9 X1-8 X1-7 X1-6 Y1-5 1 + * Byte4 NEW X1-10 TWO X1-9 X1-8 X1-7 X1-6 0 0 + * Byte5 TWO & NEW Y1-10 0 Y1-9 Y1-8 Y1-7 Y1-6 Y1-5 Y1-4 + * Byte5 MULTI Y1-10 0 Y1-9 Y1-8 Y1-7 Y1-6 F-1 F-0 + * L: Left button + * R / M: Non-clickpads: Right / Middle button + * Clickpads: When > 2 fingers are down, and some fingers + * are in the button area, then the 2 coordinates reported + * are for fingers outside the button area and these report + * extra fingers being present in the right / left button + * area. Note these fingers are not added to the F field! + * so if a TWO packet is received and R = 1 then there are + * 3 fingers down, etc. + * TWO: 1: Two touches present, byte 0/4/5 are in TWO fmt + * 0: If byte 4 bit 0 is 1, then byte 0/4/5 are in MULTI fmt + * otherwise byte 0 bit 4 must be set and byte 0/4/5 are + * in NEW fmt + * F: Number of fingers - 3, 0 means 3 fingers, 1 means 4 ... + */ + mt[0].x = ((pkt[2] & 0x80) << 4); mt[0].x |= ((pkt[2] & 0x3F) << 5); mt[0].x |= ((pkt[3] & 0x30) >> 1); @@ -919,18 +947,21 @@ static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt, static int alps_get_mt_count(struct input_mt_pos *mt) { - int i; + int i, fingers = 0; - for (i = 0; i < MAX_TOUCHES && mt[i].x != 0 && mt[i].y != 0; i++) - /* empty */; + for (i = 0; i < MAX_TOUCHES; i++) { + if (mt[i].x != 0 || mt[i].y != 0) + fingers++; + } - return i; + return fingers; } static int alps_decode_packet_v7(struct alps_fields *f, unsigned char *p, struct psmouse *psmouse) { + struct alps_data *priv = psmouse->private; unsigned char pkt_id; pkt_id = alps_get_packet_id_v7(p); @@ -938,19 +969,52 @@ static int alps_decode_packet_v7(struct alps_fields *f, return 0; if (pkt_id == V7_PACKET_ID_UNKNOWN) return -1; + /* + * NEW packets are send to indicate a discontinuity in the finger + * coordinate reporting. Specifically a finger may have moved from + * slot 0 to 1 or vice versa. INPUT_MT_TRACK takes care of this for + * us. + * + * NEW packets have 3 problems: + * 1) They do not contain middle / right button info (on non clickpads) + * this can be worked around by preserving the old button state + * 2) They do not contain an accurate fingercount, and they are + * typically send when the number of fingers changes. We cannot use + * the old finger count as that may mismatch with the amount of + * touch coordinates we've available in the NEW packet + * 3) Their x data for the second touch is inaccurate leading to + * a possible jump of the x coordinate by 16 units when the first + * non NEW packet comes in + * Since problems 2 & 3 cannot be worked around, just ignore them. + */ + if (pkt_id == V7_PACKET_ID_NEW) + return 1; alps_get_finger_coordinate_v7(f->mt, p, pkt_id); - if (pkt_id == V7_PACKET_ID_TWO || pkt_id == V7_PACKET_ID_MULTI) { - f->left = (p[0] & 0x80) >> 7; + if (pkt_id == V7_PACKET_ID_TWO) + f->fingers = alps_get_mt_count(f->mt); + else /* pkt_id == V7_PACKET_ID_MULTI */ + f->fingers = 3 + (p[5] & 0x03); + + f->left = (p[0] & 0x80) >> 7; + if (priv->flags & ALPS_BUTTONPAD) { + if (p[0] & 0x20) + f->fingers++; + if (p[0] & 0x10) + f->fingers++; + } else { f->right = (p[0] & 0x20) >> 5; f->middle = (p[0] & 0x10) >> 4; } - if (pkt_id == V7_PACKET_ID_TWO) - f->fingers = alps_get_mt_count(f->mt); - else if (pkt_id == V7_PACKET_ID_MULTI) - f->fingers = 3 + (p[5] & 0x03); + /* Sometimes a single touch is reported in mt[1] rather then mt[0] */ + if (f->fingers == 1 && f->mt[0].x == 0 && f->mt[0].y == 0) { + f->mt[0].x = f->mt[1].x; + f->mt[0].y = f->mt[1].y; + f->mt[1].x = 0; + f->mt[1].y = 0; + } return 0; } diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c index 30c8b6998808..354d47ecd66a 100644 --- a/drivers/input/mouse/trackpoint.c +++ b/drivers/input/mouse/trackpoint.c @@ -227,6 +227,7 @@ TRACKPOINT_INT_ATTR(thresh, TP_THRESH, TP_DEF_THRESH); TRACKPOINT_INT_ATTR(upthresh, TP_UP_THRESH, TP_DEF_UP_THRESH); TRACKPOINT_INT_ATTR(ztime, TP_Z_TIME, TP_DEF_Z_TIME); TRACKPOINT_INT_ATTR(jenks, TP_JENKS_CURV, TP_DEF_JENKS_CURV); +TRACKPOINT_INT_ATTR(drift_time, TP_DRIFT_TIME, TP_DEF_DRIFT_TIME); TRACKPOINT_BIT_ATTR(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON, 0, TP_DEF_PTSON); @@ -246,6 +247,7 @@ static struct attribute *trackpoint_attrs[] = { &psmouse_attr_upthresh.dattr.attr, &psmouse_attr_ztime.dattr.attr, &psmouse_attr_jenks.dattr.attr, + &psmouse_attr_drift_time.dattr.attr, &psmouse_attr_press_to_select.dattr.attr, &psmouse_attr_skipback.dattr.attr, &psmouse_attr_ext_dev.dattr.attr, @@ -312,6 +314,7 @@ static int trackpoint_sync(struct psmouse *psmouse, bool in_power_on_state) TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, upthresh); TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, ztime); TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, jenks); + TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, drift_time); /* toggles */ TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, press_to_select); @@ -332,6 +335,7 @@ static void trackpoint_defaults(struct trackpoint_data *tp) TRACKPOINT_SET_POWER_ON_DEFAULT(tp, upthresh); TRACKPOINT_SET_POWER_ON_DEFAULT(tp, ztime); TRACKPOINT_SET_POWER_ON_DEFAULT(tp, jenks); + TRACKPOINT_SET_POWER_ON_DEFAULT(tp, drift_time); TRACKPOINT_SET_POWER_ON_DEFAULT(tp, inertia); /* toggles */ diff --git a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h index ecd0547964a5..5617ed3a7d7a 100644 --- a/drivers/input/mouse/trackpoint.h +++ b/drivers/input/mouse/trackpoint.h @@ -70,6 +70,9 @@ #define TP_UP_THRESH 0x5A /* Used to generate a 'click' on Z-axis */ #define TP_Z_TIME 0x5E /* How sharp of a press */ #define TP_JENKS_CURV 0x5D /* Minimum curvature for double click */ +#define TP_DRIFT_TIME 0x5F /* How long a 'hands off' condition */ + /* must last (x*107ms) for drift */ + /* correction to occur */ /* * Toggling Flag bits @@ -120,6 +123,7 @@ #define TP_DEF_UP_THRESH 0xFF #define TP_DEF_Z_TIME 0x26 #define TP_DEF_JENKS_CURV 0x87 +#define TP_DEF_DRIFT_TIME 0x05 /* Toggles */ #define TP_DEF_MB 0x00 @@ -137,6 +141,7 @@ struct trackpoint_data unsigned char draghys, mindrag; unsigned char thresh, upthresh; unsigned char ztime, jenks; + unsigned char drift_time; /* toggles */ unsigned char press_to_select; diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index bb070206223c..95ee92a91bd2 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -99,13 +99,9 @@ #define MXT_T6_STATUS_COMSERR (1 << 2) /* MXT_GEN_POWER_T7 field */ -struct t7_config { - u8 idle; - u8 active; -} __packed; - -#define MXT_POWER_CFG_RUN 0 -#define MXT_POWER_CFG_DEEPSLEEP 1 +#define MXT_POWER_IDLEACQINT 0 +#define MXT_POWER_ACTVACQINT 1 +#define MXT_POWER_ACTV2IDLETO 2 /* MXT_GEN_ACQUIRE_T8 field */ #define MXT_ACQUIRE_CHRGTIME 0 @@ -117,6 +113,7 @@ struct t7_config { #define MXT_ACQUIRE_ATCHCALSTHR 7 /* MXT_TOUCH_MULTI_T9 field */ +#define MXT_TOUCH_CTRL 0 #define MXT_T9_ORIENT 9 #define MXT_T9_RANGE 18 @@ -256,7 +253,6 @@ struct mxt_data { bool update_input; u8 last_message_count; u8 num_touchids; - struct t7_config t7_cfg; /* Cached parameters from object table */ u16 T5_address; @@ -672,6 +668,20 @@ static void mxt_proc_t6_messages(struct mxt_data *data, u8 *msg) data->t6_status = status; } +static int mxt_write_object(struct mxt_data *data, + u8 type, u8 offset, u8 val) +{ + struct mxt_object *object; + u16 reg; + + object = mxt_get_object(data, type); + if (!object || offset >= mxt_obj_size(object)) + return -EINVAL; + + reg = object->start_address; + return mxt_write_reg(data->client, reg + offset, val); +} + static void mxt_input_button(struct mxt_data *data, u8 *message) { struct input_dev *input = data->input_dev; @@ -1742,60 +1752,6 @@ err_free_object_table: return error; } -static int mxt_set_t7_power_cfg(struct mxt_data *data, u8 sleep) -{ - struct device *dev = &data->client->dev; - int error; - struct t7_config *new_config; - struct t7_config deepsleep = { .active = 0, .idle = 0 }; - - if (sleep == MXT_POWER_CFG_DEEPSLEEP) - new_config = &deepsleep; - else - new_config = &data->t7_cfg; - - error = __mxt_write_reg(data->client, data->T7_address, - sizeof(data->t7_cfg), new_config); - if (error) - return error; - - dev_dbg(dev, "Set T7 ACTV:%d IDLE:%d\n", - new_config->active, new_config->idle); - - return 0; -} - -static int mxt_init_t7_power_cfg(struct mxt_data *data) -{ - struct device *dev = &data->client->dev; - int error; - bool retry = false; - -recheck: - error = __mxt_read_reg(data->client, data->T7_address, - sizeof(data->t7_cfg), &data->t7_cfg); - if (error) - return error; - - if (data->t7_cfg.active == 0 || data->t7_cfg.idle == 0) { - if (!retry) { - dev_dbg(dev, "T7 cfg zero, resetting\n"); - mxt_soft_reset(data); - retry = true; - goto recheck; - } else { - dev_dbg(dev, "T7 cfg zero after reset, overriding\n"); - data->t7_cfg.active = 20; - data->t7_cfg.idle = 100; - return mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN); - } - } - - dev_dbg(dev, "Initialized power cfg: ACTV %d, IDLE %d\n", - data->t7_cfg.active, data->t7_cfg.idle); - return 0; -} - static int mxt_configure_objects(struct mxt_data *data, const struct firmware *cfg) { @@ -1809,12 +1765,6 @@ static int mxt_configure_objects(struct mxt_data *data, dev_warn(dev, "Error %d updating config\n", error); } - error = mxt_init_t7_power_cfg(data); - if (error) { - dev_err(dev, "Failed to initialize power cfg\n"); - return error; - } - error = mxt_initialize_t9_input_device(data); if (error) return error; @@ -2093,15 +2043,16 @@ static const struct attribute_group mxt_attr_group = { static void mxt_start(struct mxt_data *data) { - mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN); - - /* Recalibrate since chip has been in deep sleep */ - mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false); + /* Touch enable */ + mxt_write_object(data, + MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0x83); } static void mxt_stop(struct mxt_data *data) { - mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP); + /* Touch disable */ + mxt_write_object(data, + MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0); } static int mxt_input_open(struct input_dev *dev) @@ -2266,6 +2217,8 @@ static int __maybe_unused mxt_resume(struct device *dev) struct mxt_data *data = i2c_get_clientdata(client); struct input_dev *input_dev = data->input_dev; + mxt_soft_reset(data); + mutex_lock(&input_dev->mutex); if (input_dev->users) diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 3793fcc7e5db..d4c24fb7704f 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -850,9 +850,11 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, } #define EDT_ATTR_CHECKSET(name, reg) \ +do { \ if (pdata->name >= edt_ft5x06_attr_##name.limit_low && \ pdata->name <= edt_ft5x06_attr_##name.limit_high) \ - edt_ft5x06_register_write(tsdata, reg, pdata->name) + edt_ft5x06_register_write(tsdata, reg, pdata->name); \ +} while (0) #define EDT_GET_PROP(name, reg) { \ u32 val; \ diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 8735543eacdb..493478989dbd 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -1127,6 +1127,24 @@ static void schedule_external_copy(struct thin_c *tc, dm_block_t virt_block, schedule_zero(tc, virt_block, data_dest, cell, bio); } +static void set_pool_mode(struct pool *pool, enum pool_mode new_mode); + +static void check_for_space(struct pool *pool) +{ + int r; + dm_block_t nr_free; + + if (get_pool_mode(pool) != PM_OUT_OF_DATA_SPACE) + return; + + r = dm_pool_get_free_block_count(pool->pmd, &nr_free); + if (r) + return; + + if (nr_free) + set_pool_mode(pool, PM_WRITE); +} + /* * A non-zero return indicates read_only or fail_io mode. * Many callers don't care about the return value. @@ -1141,6 +1159,8 @@ static int commit(struct pool *pool) r = dm_pool_commit_metadata(pool->pmd); if (r) metadata_operation_failed(pool, "dm_pool_commit_metadata", r); + else + check_for_space(pool); return r; } @@ -1159,8 +1179,6 @@ static void check_low_water_mark(struct pool *pool, dm_block_t free_blocks) } } -static void set_pool_mode(struct pool *pool, enum pool_mode new_mode); - static int alloc_data_block(struct thin_c *tc, dm_block_t *result) { int r; @@ -2155,7 +2173,7 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode) pool->process_cell = process_cell_read_only; pool->process_discard_cell = process_discard_cell; pool->process_prepared_mapping = process_prepared_mapping; - pool->process_prepared_discard = process_prepared_discard_passdown; + pool->process_prepared_discard = process_prepared_discard; if (!pool->pf.error_if_no_space && no_space_timeout) queue_delayed_work(pool->wq, &pool->no_space_timeout, no_space_timeout); @@ -3814,6 +3832,8 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv) r = -EINVAL; goto bad; } + atomic_set(&tc->refcount, 1); + init_completion(&tc->can_destroy); list_add_tail_rcu(&tc->list, &tc->pool->active_thins); spin_unlock_irqrestore(&tc->pool->lock, flags); /* @@ -3826,9 +3846,6 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv) dm_put(pool_md); - atomic_set(&tc->refcount, 1); - init_completion(&tc->can_destroy); - return 0; bad: diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 4c06585bf165..b98cd9d84435 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -899,7 +899,7 @@ static void disable_write_same(struct mapped_device *md) static void clone_endio(struct bio *bio, int error) { - int r = 0; + int r = error; struct dm_target_io *tio = container_of(bio, struct dm_target_io, clone); struct dm_io *io = tio->io; struct mapped_device *md = tio->io->md; diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index e2f9df1c0c36..2d7fae94c861 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -519,6 +519,7 @@ static const u8 stmpe1601_regs[] = { [STMPE_IDX_GPDR_LSB] = STMPE1601_REG_GPIO_SET_DIR_LSB, [STMPE_IDX_GPRER_LSB] = STMPE1601_REG_GPIO_RE_LSB, [STMPE_IDX_GPFER_LSB] = STMPE1601_REG_GPIO_FE_LSB, + [STMPE_IDX_GPPUR_LSB] = STMPE1601_REG_GPIO_PU_LSB, [STMPE_IDX_GPAFR_U_MSB] = STMPE1601_REG_GPIO_AF_U_MSB, [STMPE_IDX_IEGPIOR_LSB] = STMPE1601_REG_INT_EN_GPIO_MASK_LSB, [STMPE_IDX_ISGPIOR_MSB] = STMPE1601_REG_INT_STA_GPIO_MSB, @@ -667,6 +668,7 @@ static const u8 stmpe1801_regs[] = { [STMPE_IDX_GPDR_LSB] = STMPE1801_REG_GPIO_SET_DIR_LOW, [STMPE_IDX_GPRER_LSB] = STMPE1801_REG_GPIO_RE_LOW, [STMPE_IDX_GPFER_LSB] = STMPE1801_REG_GPIO_FE_LOW, + [STMPE_IDX_GPPUR_LSB] = STMPE1801_REG_GPIO_PULL_UP_LOW, [STMPE_IDX_IEGPIOR_LSB] = STMPE1801_REG_INT_EN_GPIO_MASK_LOW, [STMPE_IDX_ISGPIOR_LSB] = STMPE1801_REG_INT_STA_GPIO_LOW, }; @@ -750,6 +752,8 @@ static const u8 stmpe24xx_regs[] = { [STMPE_IDX_GPDR_LSB] = STMPE24XX_REG_GPDR_LSB, [STMPE_IDX_GPRER_LSB] = STMPE24XX_REG_GPRER_LSB, [STMPE_IDX_GPFER_LSB] = STMPE24XX_REG_GPFER_LSB, + [STMPE_IDX_GPPUR_LSB] = STMPE24XX_REG_GPPUR_LSB, + [STMPE_IDX_GPPDR_LSB] = STMPE24XX_REG_GPPDR_LSB, [STMPE_IDX_GPAFR_U_MSB] = STMPE24XX_REG_GPAFR_U_MSB, [STMPE_IDX_IEGPIOR_LSB] = STMPE24XX_REG_IEGPIOR_LSB, [STMPE_IDX_ISGPIOR_MSB] = STMPE24XX_REG_ISGPIOR_MSB, diff --git a/drivers/mfd/stmpe.h b/drivers/mfd/stmpe.h index bee0abf82040..84adb46b3e2f 100644 --- a/drivers/mfd/stmpe.h +++ b/drivers/mfd/stmpe.h @@ -188,6 +188,7 @@ int stmpe_remove(struct stmpe *stmpe); #define STMPE1601_REG_GPIO_ED_MSB 0x8A #define STMPE1601_REG_GPIO_RE_LSB 0x8D #define STMPE1601_REG_GPIO_FE_LSB 0x8F +#define STMPE1601_REG_GPIO_PU_LSB 0x91 #define STMPE1601_REG_GPIO_AF_U_MSB 0x92 #define STMPE1601_SYS_CTRL_ENABLE_GPIO (1 << 3) @@ -276,6 +277,8 @@ int stmpe_remove(struct stmpe *stmpe); #define STMPE24XX_REG_GPEDR_MSB 0x8C #define STMPE24XX_REG_GPRER_LSB 0x91 #define STMPE24XX_REG_GPFER_LSB 0x94 +#define STMPE24XX_REG_GPPUR_LSB 0x97 +#define STMPE24XX_REG_GPPDR_LSB 0x9a #define STMPE24XX_REG_GPAFR_U_MSB 0x9B #define STMPE24XX_SYS_CTRL_ENABLE_GPIO (1 << 3) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 02ad79229f65..7466ce098e60 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -886,7 +886,7 @@ static int mmc_select_bus_width(struct mmc_card *card) unsigned idx, bus_width = 0; int err = 0; - if (!mmc_can_ext_csd(card) && + if (!mmc_can_ext_csd(card) || !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) return 0; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 184c434ae305..0dceba1a2ba1 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1648,7 +1648,7 @@ static int __bond_release_one(struct net_device *bond_dev, /* slave is not a slave or master is not master of this slave */ if (!(slave_dev->flags & IFF_SLAVE) || !netdev_has_upper_dev(slave_dev, bond_dev)) { - netdev_err(bond_dev, "cannot release %s\n", + netdev_dbg(bond_dev, "cannot release %s\n", slave_dev->name); return -EINVAL; } diff --git a/drivers/net/caif/caif_virtio.c b/drivers/net/caif/caif_virtio.c index a5fefb9059c5..b306210b02b7 100644 --- a/drivers/net/caif/caif_virtio.c +++ b/drivers/net/caif/caif_virtio.c @@ -257,7 +257,6 @@ static int cfv_rx_poll(struct napi_struct *napi, int quota) struct vringh_kiov *riov = &cfv->ctx.riov; unsigned int skb_len; -again: do { skb = NULL; @@ -322,7 +321,6 @@ exit: napi_schedule_prep(napi)) { vringh_notify_disable_kern(cfv->vr_rx); __napi_schedule(napi); - goto again; } break; diff --git a/drivers/net/ethernet/8390/ne2k-pci.c b/drivers/net/ethernet/8390/ne2k-pci.c index 89c8d9fc97de..57e97910c728 100644 --- a/drivers/net/ethernet/8390/ne2k-pci.c +++ b/drivers/net/ethernet/8390/ne2k-pci.c @@ -246,13 +246,13 @@ static int ne2k_pci_init_one(struct pci_dev *pdev, if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_IO) == 0)) { dev_err(&pdev->dev, "no I/O resource at PCI BAR #0\n"); - return -ENODEV; + goto err_out; } if (request_region (ioaddr, NE_IO_EXTENT, DRV_NAME) == NULL) { dev_err(&pdev->dev, "I/O resource 0x%x @ 0x%lx busy\n", NE_IO_EXTENT, ioaddr); - return -EBUSY; + goto err_out; } reg0 = inb(ioaddr); @@ -392,6 +392,8 @@ err_out_free_netdev: free_netdev (dev); err_out_free_res: release_region (ioaddr, NE_IO_EXTENT); +err_out: + pci_disable_device(pdev); return -ENODEV; } diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index df76050d0a9d..eadcb053807e 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -156,18 +156,6 @@ source "drivers/net/ethernet/realtek/Kconfig" source "drivers/net/ethernet/renesas/Kconfig" source "drivers/net/ethernet/rdc/Kconfig" source "drivers/net/ethernet/rocker/Kconfig" - -config S6GMAC - tristate "S6105 GMAC ethernet support" - depends on XTENSA_VARIANT_S6000 - select PHYLIB - ---help--- - This driver supports the on chip ethernet device on the - S6105 xtensa processor. - - To compile this driver as a module, choose M here. The module - will be called s6gmac. - source "drivers/net/ethernet/samsung/Kconfig" source "drivers/net/ethernet/seeq/Kconfig" source "drivers/net/ethernet/silan/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index bf56f8b36e90..1367afcd0a8b 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -66,7 +66,6 @@ obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/ obj-$(CONFIG_SH_ETH) += renesas/ obj-$(CONFIG_NET_VENDOR_RDC) += rdc/ obj-$(CONFIG_NET_VENDOR_ROCKER) += rocker/ -obj-$(CONFIG_S6GMAC) += s6gmac.o obj-$(CONFIG_NET_VENDOR_SAMSUNG) += samsung/ obj-$(CONFIG_NET_VENDOR_SEEQ) += seeq/ obj-$(CONFIG_NET_VENDOR_SILAN) += silan/ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 9f5e38769a29..72eef9fc883e 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -12553,9 +12553,11 @@ static int bnx2x_get_phys_port_id(struct net_device *netdev, return 0; } -static bool bnx2x_gso_check(struct sk_buff *skb, struct net_device *dev) +static netdev_features_t bnx2x_features_check(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features) { - return vxlan_gso_check(skb); + return vxlan_features_check(skb, features); } static const struct net_device_ops bnx2x_netdev_ops = { @@ -12589,7 +12591,7 @@ static const struct net_device_ops bnx2x_netdev_ops = { #endif .ndo_get_phys_port_id = bnx2x_get_phys_port_id, .ndo_set_vf_link_state = bnx2x_set_vf_link_state, - .ndo_gso_check = bnx2x_gso_check, + .ndo_features_check = bnx2x_features_check, }; static int bnx2x_set_coherency_mask(struct bnx2x *bp) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index bb48a610b72a..553dcd8a9df2 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -17800,23 +17800,6 @@ static int tg3_init_one(struct pci_dev *pdev, goto err_out_apeunmap; } - /* - * Reset chip in case UNDI or EFI driver did not shutdown - * DMA self test will enable WDMAC and we'll see (spurious) - * pending DMA on the PCI bus at that point. - */ - if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) || - (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { - tw32(MEMARB_MODE, MEMARB_MODE_ENABLE); - tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); - } - - err = tg3_test_dma(tp); - if (err) { - dev_err(&pdev->dev, "DMA engine test failed, aborting\n"); - goto err_out_apeunmap; - } - intmbx = MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW; rcvmbx = MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW; sndmbx = MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW; @@ -17861,6 +17844,23 @@ static int tg3_init_one(struct pci_dev *pdev, sndmbx += 0xc; } + /* + * Reset chip in case UNDI or EFI driver did not shutdown + * DMA self test will enable WDMAC and we'll see (spurious) + * pending DMA on the PCI bus at that point. + */ + if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) || + (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { + tw32(MEMARB_MODE, MEMARB_MODE_ENABLE); + tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); + } + + err = tg3_test_dma(tp); + if (err) { + dev_err(&pdev->dev, "DMA engine test failed, aborting\n"); + goto err_out_apeunmap; + } + tg3_init_coal(tp); pci_set_drvdata(pdev, dev); diff --git a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c index 7d6aa8c87df8..619083a860a4 100644 --- a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c +++ b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c @@ -172,7 +172,7 @@ bnad_get_debug_drvinfo(struct bnad *bnad, void *buffer, u32 len) /* Retrieve flash partition info */ fcomp.comp_status = 0; - init_completion(&fcomp.comp); + reinit_completion(&fcomp.comp); spin_lock_irqsave(&bnad->bna_lock, flags); ret = bfa_nw_flash_get_attr(&bnad->bna.flash, &drvinfo->flash_attr, bnad_cb_completion, &fcomp); diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h b/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h index d00a751f0588..6049f70e110c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h +++ b/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h @@ -96,6 +96,9 @@ struct port_info { s16 xact_addr_filt; /* index of our MAC address filter */ u16 rss_size; /* size of VI's RSS table slice */ u8 pidx; /* index into adapter port[] */ + s8 mdio_addr; + u8 port_type; /* firmware port type */ + u8 mod_type; /* firmware module type */ u8 port_id; /* physical port ID */ u8 nqsets; /* # of "Queue Sets" */ u8 first_qset; /* index of first "Queue Set" */ @@ -522,6 +525,7 @@ static inline struct adapter *netdev2adap(const struct net_device *dev) * is "contracted" to provide for the common code. */ void t4vf_os_link_changed(struct adapter *, int, int); +void t4vf_os_portmod_changed(struct adapter *, int); /* * SGE function prototype declarations. diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c index aa74ec34a467..2215d432a059 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c @@ -44,6 +44,7 @@ #include <linux/etherdevice.h> #include <linux/debugfs.h> #include <linux/ethtool.h> +#include <linux/mdio.h> #include "t4vf_common.h" #include "t4vf_defs.h" @@ -210,6 +211,38 @@ void t4vf_os_link_changed(struct adapter *adapter, int pidx, int link_ok) } /* + * THe port module type has changed on the indicated "port" (Virtual + * Interface). + */ +void t4vf_os_portmod_changed(struct adapter *adapter, int pidx) +{ + static const char * const mod_str[] = { + NULL, "LR", "SR", "ER", "passive DA", "active DA", "LRM" + }; + const struct net_device *dev = adapter->port[pidx]; + const struct port_info *pi = netdev_priv(dev); + + if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) + dev_info(adapter->pdev_dev, "%s: port module unplugged\n", + dev->name); + else if (pi->mod_type < ARRAY_SIZE(mod_str)) + dev_info(adapter->pdev_dev, "%s: %s port module inserted\n", + dev->name, mod_str[pi->mod_type]); + else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED) + dev_info(adapter->pdev_dev, "%s: unsupported optical port " + "module inserted\n", dev->name); + else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN) + dev_info(adapter->pdev_dev, "%s: unknown port module inserted," + "forcing TWINAX\n", dev->name); + else if (pi->mod_type == FW_PORT_MOD_TYPE_ERROR) + dev_info(adapter->pdev_dev, "%s: transceiver module error\n", + dev->name); + else + dev_info(adapter->pdev_dev, "%s: unknown module type %d " + "inserted\n", dev->name, pi->mod_type); +} + +/* * Net device operations. * ====================== */ @@ -1193,24 +1226,103 @@ static void cxgb4vf_poll_controller(struct net_device *dev) * state of the port to which we're linked. */ -/* - * Return current port link settings. - */ -static int cxgb4vf_get_settings(struct net_device *dev, - struct ethtool_cmd *cmd) -{ - const struct port_info *pi = netdev_priv(dev); +static unsigned int t4vf_from_fw_linkcaps(enum fw_port_type type, + unsigned int caps) +{ + unsigned int v = 0; + + if (type == FW_PORT_TYPE_BT_SGMII || type == FW_PORT_TYPE_BT_XFI || + type == FW_PORT_TYPE_BT_XAUI) { + v |= SUPPORTED_TP; + if (caps & FW_PORT_CAP_SPEED_100M) + v |= SUPPORTED_100baseT_Full; + if (caps & FW_PORT_CAP_SPEED_1G) + v |= SUPPORTED_1000baseT_Full; + if (caps & FW_PORT_CAP_SPEED_10G) + v |= SUPPORTED_10000baseT_Full; + } else if (type == FW_PORT_TYPE_KX4 || type == FW_PORT_TYPE_KX) { + v |= SUPPORTED_Backplane; + if (caps & FW_PORT_CAP_SPEED_1G) + v |= SUPPORTED_1000baseKX_Full; + if (caps & FW_PORT_CAP_SPEED_10G) + v |= SUPPORTED_10000baseKX4_Full; + } else if (type == FW_PORT_TYPE_KR) + v |= SUPPORTED_Backplane | SUPPORTED_10000baseKR_Full; + else if (type == FW_PORT_TYPE_BP_AP) + v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC | + SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full; + else if (type == FW_PORT_TYPE_BP4_AP) + v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC | + SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full | + SUPPORTED_10000baseKX4_Full; + else if (type == FW_PORT_TYPE_FIBER_XFI || + type == FW_PORT_TYPE_FIBER_XAUI || + type == FW_PORT_TYPE_SFP || + type == FW_PORT_TYPE_QSFP_10G || + type == FW_PORT_TYPE_QSA) { + v |= SUPPORTED_FIBRE; + if (caps & FW_PORT_CAP_SPEED_1G) + v |= SUPPORTED_1000baseT_Full; + if (caps & FW_PORT_CAP_SPEED_10G) + v |= SUPPORTED_10000baseT_Full; + } else if (type == FW_PORT_TYPE_BP40_BA || + type == FW_PORT_TYPE_QSFP) { + v |= SUPPORTED_40000baseSR4_Full; + v |= SUPPORTED_FIBRE; + } + + if (caps & FW_PORT_CAP_ANEG) + v |= SUPPORTED_Autoneg; + return v; +} + +static int cxgb4vf_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + const struct port_info *p = netdev_priv(dev); + + if (p->port_type == FW_PORT_TYPE_BT_SGMII || + p->port_type == FW_PORT_TYPE_BT_XFI || + p->port_type == FW_PORT_TYPE_BT_XAUI) + cmd->port = PORT_TP; + else if (p->port_type == FW_PORT_TYPE_FIBER_XFI || + p->port_type == FW_PORT_TYPE_FIBER_XAUI) + cmd->port = PORT_FIBRE; + else if (p->port_type == FW_PORT_TYPE_SFP || + p->port_type == FW_PORT_TYPE_QSFP_10G || + p->port_type == FW_PORT_TYPE_QSA || + p->port_type == FW_PORT_TYPE_QSFP) { + if (p->mod_type == FW_PORT_MOD_TYPE_LR || + p->mod_type == FW_PORT_MOD_TYPE_SR || + p->mod_type == FW_PORT_MOD_TYPE_ER || + p->mod_type == FW_PORT_MOD_TYPE_LRM) + cmd->port = PORT_FIBRE; + else if (p->mod_type == FW_PORT_MOD_TYPE_TWINAX_PASSIVE || + p->mod_type == FW_PORT_MOD_TYPE_TWINAX_ACTIVE) + cmd->port = PORT_DA; + else + cmd->port = PORT_OTHER; + } else + cmd->port = PORT_OTHER; - cmd->supported = pi->link_cfg.supported; - cmd->advertising = pi->link_cfg.advertising; + if (p->mdio_addr >= 0) { + cmd->phy_address = p->mdio_addr; + cmd->transceiver = XCVR_EXTERNAL; + cmd->mdio_support = p->port_type == FW_PORT_TYPE_BT_SGMII ? + MDIO_SUPPORTS_C22 : MDIO_SUPPORTS_C45; + } else { + cmd->phy_address = 0; /* not really, but no better option */ + cmd->transceiver = XCVR_INTERNAL; + cmd->mdio_support = 0; + } + + cmd->supported = t4vf_from_fw_linkcaps(p->port_type, + p->link_cfg.supported); + cmd->advertising = t4vf_from_fw_linkcaps(p->port_type, + p->link_cfg.advertising); ethtool_cmd_speed_set(cmd, - netif_carrier_ok(dev) ? pi->link_cfg.speed : -1); + netif_carrier_ok(dev) ? p->link_cfg.speed : 0); cmd->duplex = DUPLEX_FULL; - - cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; - cmd->phy_address = pi->port_id; - cmd->transceiver = XCVR_EXTERNAL; - cmd->autoneg = pi->link_cfg.autoneg; + cmd->autoneg = p->link_cfg.autoneg; cmd->maxtxpkt = 0; cmd->maxrxpkt = 0; return 0; diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h index 8d3237f5e364..b9debb4f29a3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h @@ -230,7 +230,7 @@ struct adapter_params { static inline bool is_10g_port(const struct link_config *lc) { - return (lc->supported & SUPPORTED_10000baseT_Full) != 0; + return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0; } static inline bool is_x_10g_port(const struct link_config *lc) diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c index 02e8833b7797..21dc9a20308c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c @@ -245,6 +245,10 @@ static int hash_mac_addr(const u8 *addr) return a & 0x3f; } +#define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\ + FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G | \ + FW_PORT_CAP_SPEED_100G | FW_PORT_CAP_ANEG) + /** * init_link_config - initialize a link's SW state * @lc: structure holding the link state @@ -259,8 +263,8 @@ static void init_link_config(struct link_config *lc, unsigned int caps) lc->requested_speed = 0; lc->speed = 0; lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; - if (lc->supported & SUPPORTED_Autoneg) { - lc->advertising = lc->supported; + if (lc->supported & FW_PORT_CAP_ANEG) { + lc->advertising = lc->supported & ADVERT_MASK; lc->autoneg = AUTONEG_ENABLE; lc->requested_fc |= PAUSE_AUTONEG; } else { @@ -280,7 +284,6 @@ int t4vf_port_init(struct adapter *adapter, int pidx) struct fw_vi_cmd vi_cmd, vi_rpl; struct fw_port_cmd port_cmd, port_rpl; int v; - u32 word; /* * Execute a VI Read command to get our Virtual Interface information @@ -319,19 +322,11 @@ int t4vf_port_init(struct adapter *adapter, int pidx) if (v) return v; - v = 0; - word = be16_to_cpu(port_rpl.u.info.pcap); - if (word & FW_PORT_CAP_SPEED_100M) - v |= SUPPORTED_100baseT_Full; - if (word & FW_PORT_CAP_SPEED_1G) - v |= SUPPORTED_1000baseT_Full; - if (word & FW_PORT_CAP_SPEED_10G) - v |= SUPPORTED_10000baseT_Full; - if (word & FW_PORT_CAP_SPEED_40G) - v |= SUPPORTED_40000baseSR4_Full; - if (word & FW_PORT_CAP_ANEG) - v |= SUPPORTED_Autoneg; - init_link_config(&pi->link_cfg, v); + v = be32_to_cpu(port_rpl.u.info.lstatus_to_modtype); + pi->port_type = FW_PORT_CMD_PTYPE_G(v); + pi->mod_type = FW_PORT_MOD_TYPE_NA; + + init_link_config(&pi->link_cfg, be16_to_cpu(port_rpl.u.info.pcap)); return 0; } @@ -1491,7 +1486,7 @@ int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl) */ const struct fw_port_cmd *port_cmd = (const struct fw_port_cmd *)rpl; - u32 word; + u32 stat, mod; int action, port_id, link_ok, speed, fc, pidx; /* @@ -1509,21 +1504,21 @@ int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl) port_id = FW_PORT_CMD_PORTID_G( be32_to_cpu(port_cmd->op_to_portid)); - word = be32_to_cpu(port_cmd->u.info.lstatus_to_modtype); - link_ok = (word & FW_PORT_CMD_LSTATUS_F) != 0; + stat = be32_to_cpu(port_cmd->u.info.lstatus_to_modtype); + link_ok = (stat & FW_PORT_CMD_LSTATUS_F) != 0; speed = 0; fc = 0; - if (word & FW_PORT_CMD_RXPAUSE_F) + if (stat & FW_PORT_CMD_RXPAUSE_F) fc |= PAUSE_RX; - if (word & FW_PORT_CMD_TXPAUSE_F) + if (stat & FW_PORT_CMD_TXPAUSE_F) fc |= PAUSE_TX; - if (word & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M)) + if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M)) speed = 100; - else if (word & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G)) + else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G)) speed = 1000; - else if (word & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G)) + else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G)) speed = 10000; - else if (word & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G)) + else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G)) speed = 40000; /* @@ -1540,12 +1535,21 @@ int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl) continue; lc = &pi->link_cfg; + + mod = FW_PORT_CMD_MODTYPE_G(stat); + if (mod != pi->mod_type) { + pi->mod_type = mod; + t4vf_os_portmod_changed(adapter, pidx); + } + if (link_ok != lc->link_ok || speed != lc->speed || fc != lc->fc) { /* something changed */ lc->link_ok = link_ok; lc->speed = speed; lc->fc = fc; + lc->supported = + be16_to_cpu(port_cmd->u.info.pcap); t4vf_os_link_changed(adapter, pidx, link_ok); } } diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 868d0f605d60..705f334ebb85 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -1060,10 +1060,14 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3); } - if ((netdev->features & NETIF_F_RXCSUM) && !csum_not_calc) { - skb->csum = htons(checksum); - skb->ip_summed = CHECKSUM_COMPLETE; - } + /* Hardware does not provide whole packet checksum. It only + * provides pseudo checksum. Since hw validates the packet + * checksum but not provide us the checksum value. use + * CHECSUM_UNNECESSARY. + */ + if ((netdev->features & NETIF_F_RXCSUM) && tcp_udp_csum_ok && + ipv4_csum_ok) + skb->ip_summed = CHECKSUM_UNNECESSARY; if (vlan_stripped) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci); diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 196073110e32..41a0a5498da7 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -4459,9 +4459,11 @@ done: adapter->vxlan_port_count--; } -static bool be_gso_check(struct sk_buff *skb, struct net_device *dev) +static netdev_features_t be_features_check(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features) { - return vxlan_gso_check(skb); + return vxlan_features_check(skb, features); } #endif @@ -4492,7 +4494,7 @@ static const struct net_device_ops be_netdev_ops = { #ifdef CONFIG_BE2NET_VXLAN .ndo_add_vxlan_port = be_add_vxlan_port, .ndo_del_vxlan_port = be_del_vxlan_port, - .ndo_gso_check = be_gso_check, + .ndo_features_check = be_features_check, #endif }; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 190cbd931f6b..d0d6dc1b8e46 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2365,9 +2365,11 @@ static void mlx4_en_del_vxlan_port(struct net_device *dev, queue_work(priv->mdev->workqueue, &priv->vxlan_del_task); } -static bool mlx4_en_gso_check(struct sk_buff *skb, struct net_device *dev) +static netdev_features_t mlx4_en_features_check(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features) { - return vxlan_gso_check(skb); + return vxlan_features_check(skb, features); } #endif @@ -2400,7 +2402,7 @@ static const struct net_device_ops mlx4_netdev_ops = { #ifdef CONFIG_MLX4_EN_VXLAN .ndo_add_vxlan_port = mlx4_en_add_vxlan_port, .ndo_del_vxlan_port = mlx4_en_del_vxlan_port, - .ndo_gso_check = mlx4_en_gso_check, + .ndo_features_check = mlx4_en_features_check, #endif }; @@ -2434,7 +2436,7 @@ static const struct net_device_ops mlx4_netdev_ops_master = { #ifdef CONFIG_MLX4_EN_VXLAN .ndo_add_vxlan_port = mlx4_en_add_vxlan_port, .ndo_del_vxlan_port = mlx4_en_del_vxlan_port, - .ndo_gso_check = mlx4_en_gso_check, + .ndo_features_check = mlx4_en_features_check, #endif }; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index a308d41e4de0..e3357bf523df 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -962,7 +962,17 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) tx_desc->ctrl.owner_opcode = op_own; if (send_doorbell) { wmb(); - iowrite32(ring->doorbell_qpn, + /* Since there is no iowrite*_native() that writes the + * value as is, without byteswapping - using the one + * the doesn't do byteswapping in the relevant arch + * endianness. + */ +#if defined(__LITTLE_ENDIAN) + iowrite32( +#else + iowrite32be( +#endif + ring->doorbell_qpn, ring->bf.uar->map + MLX4_SEND_DOORBELL); } else { ring->xmit_more++; diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c index f1ebed6c63b1..2fa6ae026e4f 100644 --- a/drivers/net/ethernet/micrel/ksz884x.c +++ b/drivers/net/ethernet/micrel/ksz884x.c @@ -2303,12 +2303,6 @@ static inline int port_chk_force_flow_ctrl(struct ksz_hw *hw, int p) /* Spanning Tree */ -static inline void port_cfg_dis_learn(struct ksz_hw *hw, int p, int set) -{ - port_cfg(hw, p, - KS8842_PORT_CTRL_2_OFFSET, PORT_LEARN_DISABLE, set); -} - static inline void port_cfg_rx(struct ksz_hw *hw, int p, int set) { port_cfg(hw, p, diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 1aa25b13ace1..9929b97cfb36 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -505,9 +505,11 @@ static void qlcnic_del_vxlan_port(struct net_device *netdev, adapter->flags |= QLCNIC_DEL_VXLAN_PORT; } -static bool qlcnic_gso_check(struct sk_buff *skb, struct net_device *dev) +static netdev_features_t qlcnic_features_check(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features) { - return vxlan_gso_check(skb); + return vxlan_features_check(skb, features); } #endif @@ -532,7 +534,7 @@ static const struct net_device_ops qlcnic_netdev_ops = { #ifdef CONFIG_QLCNIC_VXLAN .ndo_add_vxlan_port = qlcnic_add_vxlan_port, .ndo_del_vxlan_port = qlcnic_del_vxlan_port, - .ndo_gso_check = qlcnic_gso_check, + .ndo_features_check = qlcnic_features_check, #endif #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = qlcnic_poll_controller, diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c index 6d0b9dfac313..78bb4ceb1cdd 100644 --- a/drivers/net/ethernet/realtek/8139too.c +++ b/drivers/net/ethernet/realtek/8139too.c @@ -787,10 +787,10 @@ static struct net_device *rtl8139_init_board(struct pci_dev *pdev) if (rc) goto err_out; + disable_dev_on_err = 1; rc = pci_request_regions (pdev, DRV_NAME); if (rc) goto err_out; - disable_dev_on_err = 1; pci_set_master (pdev); @@ -1110,6 +1110,7 @@ static int rtl8139_init_one(struct pci_dev *pdev, return 0; err_out: + netif_napi_del(&tp->napi); __rtl8139_cleanup_dev (dev); pci_disable_device (pdev); return i; @@ -1124,6 +1125,7 @@ static void rtl8139_remove_one(struct pci_dev *pdev) assert (dev != NULL); cancel_delayed_work_sync(&tp->thread); + netif_napi_del(&tp->napi); unregister_netdev (dev); diff --git a/drivers/net/ethernet/s6gmac.c b/drivers/net/ethernet/s6gmac.c deleted file mode 100644 index f537cbea20e5..000000000000 --- a/drivers/net/ethernet/s6gmac.c +++ /dev/null @@ -1,1058 +0,0 @@ -/* - * Ethernet driver for S6105 on chip network device - * (c)2008 emlix GmbH http://www.emlix.com - * Authors: Oskar Schirmer <oskar@scara.com> - * Daniel Gloeckner <dg@emlix.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/types.h> -#include <linux/delay.h> -#include <linux/spinlock.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/if.h> -#include <linux/stddef.h> -#include <linux/mii.h> -#include <linux/phy.h> -#include <linux/platform_device.h> -#include <variant/hardware.h> -#include <variant/dmac.h> - -#define DRV_NAME "s6gmac" -#define DRV_PRMT DRV_NAME ": " - - -/* register declarations */ - -#define S6_GMAC_MACCONF1 0x000 -#define S6_GMAC_MACCONF1_TXENA 0 -#define S6_GMAC_MACCONF1_SYNCTX 1 -#define S6_GMAC_MACCONF1_RXENA 2 -#define S6_GMAC_MACCONF1_SYNCRX 3 -#define S6_GMAC_MACCONF1_TXFLOWCTRL 4 -#define S6_GMAC_MACCONF1_RXFLOWCTRL 5 -#define S6_GMAC_MACCONF1_LOOPBACK 8 -#define S6_GMAC_MACCONF1_RESTXFUNC 16 -#define S6_GMAC_MACCONF1_RESRXFUNC 17 -#define S6_GMAC_MACCONF1_RESTXMACCTRL 18 -#define S6_GMAC_MACCONF1_RESRXMACCTRL 19 -#define S6_GMAC_MACCONF1_SIMULRES 30 -#define S6_GMAC_MACCONF1_SOFTRES 31 -#define S6_GMAC_MACCONF2 0x004 -#define S6_GMAC_MACCONF2_FULL 0 -#define S6_GMAC_MACCONF2_CRCENA 1 -#define S6_GMAC_MACCONF2_PADCRCENA 2 -#define S6_GMAC_MACCONF2_LENGTHFCHK 4 -#define S6_GMAC_MACCONF2_HUGEFRAMENA 5 -#define S6_GMAC_MACCONF2_IFMODE 8 -#define S6_GMAC_MACCONF2_IFMODE_NIBBLE 1 -#define S6_GMAC_MACCONF2_IFMODE_BYTE 2 -#define S6_GMAC_MACCONF2_IFMODE_MASK 3 -#define S6_GMAC_MACCONF2_PREAMBLELEN 12 -#define S6_GMAC_MACCONF2_PREAMBLELEN_MASK 0x0F -#define S6_GMAC_MACIPGIFG 0x008 -#define S6_GMAC_MACIPGIFG_B2BINTERPGAP 0 -#define S6_GMAC_MACIPGIFG_B2BINTERPGAP_MASK 0x7F -#define S6_GMAC_MACIPGIFG_MINIFGENFORCE 8 -#define S6_GMAC_MACIPGIFG_B2BINTERPGAP2 16 -#define S6_GMAC_MACIPGIFG_B2BINTERPGAP1 24 -#define S6_GMAC_MACHALFDUPLEX 0x00C -#define S6_GMAC_MACHALFDUPLEX_COLLISWIN 0 -#define S6_GMAC_MACHALFDUPLEX_COLLISWIN_MASK 0x3F -#define S6_GMAC_MACHALFDUPLEX_RETXMAX 12 -#define S6_GMAC_MACHALFDUPLEX_RETXMAX_MASK 0x0F -#define S6_GMAC_MACHALFDUPLEX_EXCESSDEF 16 -#define S6_GMAC_MACHALFDUPLEX_NOBACKOFF 17 -#define S6_GMAC_MACHALFDUPLEX_BPNOBCKOF 18 -#define S6_GMAC_MACHALFDUPLEX_ALTBEBENA 19 -#define S6_GMAC_MACHALFDUPLEX_ALTBEBTRN 20 -#define S6_GMAC_MACHALFDUPLEX_ALTBEBTR_MASK 0x0F -#define S6_GMAC_MACMAXFRAMELEN 0x010 -#define S6_GMAC_MACMIICONF 0x020 -#define S6_GMAC_MACMIICONF_CSEL 0 -#define S6_GMAC_MACMIICONF_CSEL_DIV10 0 -#define S6_GMAC_MACMIICONF_CSEL_DIV12 1 -#define S6_GMAC_MACMIICONF_CSEL_DIV14 2 -#define S6_GMAC_MACMIICONF_CSEL_DIV18 3 -#define S6_GMAC_MACMIICONF_CSEL_DIV24 4 -#define S6_GMAC_MACMIICONF_CSEL_DIV34 5 -#define S6_GMAC_MACMIICONF_CSEL_DIV68 6 -#define S6_GMAC_MACMIICONF_CSEL_DIV168 7 -#define S6_GMAC_MACMIICONF_CSEL_MASK 7 -#define S6_GMAC_MACMIICONF_PREAMBLESUPR 4 -#define S6_GMAC_MACMIICONF_SCANAUTOINCR 5 -#define S6_GMAC_MACMIICMD 0x024 -#define S6_GMAC_MACMIICMD_READ 0 -#define S6_GMAC_MACMIICMD_SCAN 1 -#define S6_GMAC_MACMIIADDR 0x028 -#define S6_GMAC_MACMIIADDR_REG 0 -#define S6_GMAC_MACMIIADDR_REG_MASK 0x1F -#define S6_GMAC_MACMIIADDR_PHY 8 -#define S6_GMAC_MACMIIADDR_PHY_MASK 0x1F -#define S6_GMAC_MACMIICTRL 0x02C -#define S6_GMAC_MACMIISTAT 0x030 -#define S6_GMAC_MACMIIINDI 0x034 -#define S6_GMAC_MACMIIINDI_BUSY 0 -#define S6_GMAC_MACMIIINDI_SCAN 1 -#define S6_GMAC_MACMIIINDI_INVAL 2 -#define S6_GMAC_MACINTERFSTAT 0x03C -#define S6_GMAC_MACINTERFSTAT_LINKFAIL 3 -#define S6_GMAC_MACINTERFSTAT_EXCESSDEF 9 -#define S6_GMAC_MACSTATADDR1 0x040 -#define S6_GMAC_MACSTATADDR2 0x044 - -#define S6_GMAC_FIFOCONF0 0x048 -#define S6_GMAC_FIFOCONF0_HSTRSTWT 0 -#define S6_GMAC_FIFOCONF0_HSTRSTSR 1 -#define S6_GMAC_FIFOCONF0_HSTRSTFR 2 -#define S6_GMAC_FIFOCONF0_HSTRSTST 3 -#define S6_GMAC_FIFOCONF0_HSTRSTFT 4 -#define S6_GMAC_FIFOCONF0_WTMENREQ 8 -#define S6_GMAC_FIFOCONF0_SRFENREQ 9 -#define S6_GMAC_FIFOCONF0_FRFENREQ 10 -#define S6_GMAC_FIFOCONF0_STFENREQ 11 -#define S6_GMAC_FIFOCONF0_FTFENREQ 12 -#define S6_GMAC_FIFOCONF0_WTMENRPLY 16 -#define S6_GMAC_FIFOCONF0_SRFENRPLY 17 -#define S6_GMAC_FIFOCONF0_FRFENRPLY 18 -#define S6_GMAC_FIFOCONF0_STFENRPLY 19 -#define S6_GMAC_FIFOCONF0_FTFENRPLY 20 -#define S6_GMAC_FIFOCONF1 0x04C -#define S6_GMAC_FIFOCONF2 0x050 -#define S6_GMAC_FIFOCONF2_CFGLWM 0 -#define S6_GMAC_FIFOCONF2_CFGHWM 16 -#define S6_GMAC_FIFOCONF3 0x054 -#define S6_GMAC_FIFOCONF3_CFGFTTH 0 -#define S6_GMAC_FIFOCONF3_CFGHWMFT 16 -#define S6_GMAC_FIFOCONF4 0x058 -#define S6_GMAC_FIFOCONF_RSV_PREVDROP 0 -#define S6_GMAC_FIFOCONF_RSV_RUNT 1 -#define S6_GMAC_FIFOCONF_RSV_FALSECAR 2 -#define S6_GMAC_FIFOCONF_RSV_CODEERR 3 -#define S6_GMAC_FIFOCONF_RSV_CRCERR 4 -#define S6_GMAC_FIFOCONF_RSV_LENGTHERR 5 -#define S6_GMAC_FIFOCONF_RSV_LENRANGE 6 -#define S6_GMAC_FIFOCONF_RSV_OK 7 -#define S6_GMAC_FIFOCONF_RSV_MULTICAST 8 -#define S6_GMAC_FIFOCONF_RSV_BROADCAST 9 -#define S6_GMAC_FIFOCONF_RSV_DRIBBLE 10 -#define S6_GMAC_FIFOCONF_RSV_CTRLFRAME 11 -#define S6_GMAC_FIFOCONF_RSV_PAUSECTRL 12 -#define S6_GMAC_FIFOCONF_RSV_UNOPCODE 13 -#define S6_GMAC_FIFOCONF_RSV_VLANTAG 14 -#define S6_GMAC_FIFOCONF_RSV_LONGEVENT 15 -#define S6_GMAC_FIFOCONF_RSV_TRUNCATED 16 -#define S6_GMAC_FIFOCONF_RSV_MASK 0x3FFFF -#define S6_GMAC_FIFOCONF5 0x05C -#define S6_GMAC_FIFOCONF5_DROPLT64 18 -#define S6_GMAC_FIFOCONF5_CFGBYTM 19 -#define S6_GMAC_FIFOCONF5_RXDROPSIZE 20 -#define S6_GMAC_FIFOCONF5_RXDROPSIZE_MASK 0xF - -#define S6_GMAC_STAT_REGS 0x080 -#define S6_GMAC_STAT_SIZE_MIN 12 -#define S6_GMAC_STATTR64 0x080 -#define S6_GMAC_STATTR64_SIZE 18 -#define S6_GMAC_STATTR127 0x084 -#define S6_GMAC_STATTR127_SIZE 18 -#define S6_GMAC_STATTR255 0x088 -#define S6_GMAC_STATTR255_SIZE 18 -#define S6_GMAC_STATTR511 0x08C -#define S6_GMAC_STATTR511_SIZE 18 -#define S6_GMAC_STATTR1K 0x090 -#define S6_GMAC_STATTR1K_SIZE 18 -#define S6_GMAC_STATTRMAX 0x094 -#define S6_GMAC_STATTRMAX_SIZE 18 -#define S6_GMAC_STATTRMGV 0x098 -#define S6_GMAC_STATTRMGV_SIZE 18 -#define S6_GMAC_STATRBYT 0x09C -#define S6_GMAC_STATRBYT_SIZE 24 -#define S6_GMAC_STATRPKT 0x0A0 -#define S6_GMAC_STATRPKT_SIZE 18 -#define S6_GMAC_STATRFCS 0x0A4 -#define S6_GMAC_STATRFCS_SIZE 12 -#define S6_GMAC_STATRMCA 0x0A8 -#define S6_GMAC_STATRMCA_SIZE 18 -#define S6_GMAC_STATRBCA 0x0AC -#define S6_GMAC_STATRBCA_SIZE 22 -#define S6_GMAC_STATRXCF 0x0B0 -#define S6_GMAC_STATRXCF_SIZE 18 -#define S6_GMAC_STATRXPF 0x0B4 -#define S6_GMAC_STATRXPF_SIZE 12 -#define S6_GMAC_STATRXUO 0x0B8 -#define S6_GMAC_STATRXUO_SIZE 12 -#define S6_GMAC_STATRALN 0x0BC -#define S6_GMAC_STATRALN_SIZE 12 -#define S6_GMAC_STATRFLR 0x0C0 -#define S6_GMAC_STATRFLR_SIZE 16 -#define S6_GMAC_STATRCDE 0x0C4 -#define S6_GMAC_STATRCDE_SIZE 12 -#define S6_GMAC_STATRCSE 0x0C8 -#define S6_GMAC_STATRCSE_SIZE 12 -#define S6_GMAC_STATRUND 0x0CC -#define S6_GMAC_STATRUND_SIZE 12 -#define S6_GMAC_STATROVR 0x0D0 -#define S6_GMAC_STATROVR_SIZE 12 -#define S6_GMAC_STATRFRG 0x0D4 -#define S6_GMAC_STATRFRG_SIZE 12 -#define S6_GMAC_STATRJBR 0x0D8 -#define S6_GMAC_STATRJBR_SIZE 12 -#define S6_GMAC_STATRDRP 0x0DC -#define S6_GMAC_STATRDRP_SIZE 12 -#define S6_GMAC_STATTBYT 0x0E0 -#define S6_GMAC_STATTBYT_SIZE 24 -#define S6_GMAC_STATTPKT 0x0E4 -#define S6_GMAC_STATTPKT_SIZE 18 -#define S6_GMAC_STATTMCA 0x0E8 -#define S6_GMAC_STATTMCA_SIZE 18 -#define S6_GMAC_STATTBCA 0x0EC -#define S6_GMAC_STATTBCA_SIZE 18 -#define S6_GMAC_STATTXPF 0x0F0 -#define S6_GMAC_STATTXPF_SIZE 12 -#define S6_GMAC_STATTDFR 0x0F4 -#define S6_GMAC_STATTDFR_SIZE 12 -#define S6_GMAC_STATTEDF 0x0F8 -#define S6_GMAC_STATTEDF_SIZE 12 -#define S6_GMAC_STATTSCL 0x0FC -#define S6_GMAC_STATTSCL_SIZE 12 -#define S6_GMAC_STATTMCL 0x100 -#define S6_GMAC_STATTMCL_SIZE 12 -#define S6_GMAC_STATTLCL 0x104 -#define S6_GMAC_STATTLCL_SIZE 12 -#define S6_GMAC_STATTXCL 0x108 -#define S6_GMAC_STATTXCL_SIZE 12 -#define S6_GMAC_STATTNCL 0x10C -#define S6_GMAC_STATTNCL_SIZE 13 -#define S6_GMAC_STATTPFH 0x110 -#define S6_GMAC_STATTPFH_SIZE 12 -#define S6_GMAC_STATTDRP 0x114 -#define S6_GMAC_STATTDRP_SIZE 12 -#define S6_GMAC_STATTJBR 0x118 -#define S6_GMAC_STATTJBR_SIZE 12 -#define S6_GMAC_STATTFCS 0x11C -#define S6_GMAC_STATTFCS_SIZE 12 -#define S6_GMAC_STATTXCF 0x120 -#define S6_GMAC_STATTXCF_SIZE 12 -#define S6_GMAC_STATTOVR 0x124 -#define S6_GMAC_STATTOVR_SIZE 12 -#define S6_GMAC_STATTUND 0x128 -#define S6_GMAC_STATTUND_SIZE 12 -#define S6_GMAC_STATTFRG 0x12C -#define S6_GMAC_STATTFRG_SIZE 12 -#define S6_GMAC_STATCARRY(n) (0x130 + 4*(n)) -#define S6_GMAC_STATCARRYMSK(n) (0x138 + 4*(n)) -#define S6_GMAC_STATCARRY1_RDRP 0 -#define S6_GMAC_STATCARRY1_RJBR 1 -#define S6_GMAC_STATCARRY1_RFRG 2 -#define S6_GMAC_STATCARRY1_ROVR 3 -#define S6_GMAC_STATCARRY1_RUND 4 -#define S6_GMAC_STATCARRY1_RCSE 5 -#define S6_GMAC_STATCARRY1_RCDE 6 -#define S6_GMAC_STATCARRY1_RFLR 7 -#define S6_GMAC_STATCARRY1_RALN 8 -#define S6_GMAC_STATCARRY1_RXUO 9 -#define S6_GMAC_STATCARRY1_RXPF 10 -#define S6_GMAC_STATCARRY1_RXCF 11 -#define S6_GMAC_STATCARRY1_RBCA 12 -#define S6_GMAC_STATCARRY1_RMCA 13 -#define S6_GMAC_STATCARRY1_RFCS 14 -#define S6_GMAC_STATCARRY1_RPKT 15 -#define S6_GMAC_STATCARRY1_RBYT 16 -#define S6_GMAC_STATCARRY1_TRMGV 25 -#define S6_GMAC_STATCARRY1_TRMAX 26 -#define S6_GMAC_STATCARRY1_TR1K 27 -#define S6_GMAC_STATCARRY1_TR511 28 -#define S6_GMAC_STATCARRY1_TR255 29 -#define S6_GMAC_STATCARRY1_TR127 30 -#define S6_GMAC_STATCARRY1_TR64 31 -#define S6_GMAC_STATCARRY2_TDRP 0 -#define S6_GMAC_STATCARRY2_TPFH 1 -#define S6_GMAC_STATCARRY2_TNCL 2 -#define S6_GMAC_STATCARRY2_TXCL 3 -#define S6_GMAC_STATCARRY2_TLCL 4 -#define S6_GMAC_STATCARRY2_TMCL 5 -#define S6_GMAC_STATCARRY2_TSCL 6 -#define S6_GMAC_STATCARRY2_TEDF 7 -#define S6_GMAC_STATCARRY2_TDFR 8 -#define S6_GMAC_STATCARRY2_TXPF 9 -#define S6_GMAC_STATCARRY2_TBCA 10 -#define S6_GMAC_STATCARRY2_TMCA 11 -#define S6_GMAC_STATCARRY2_TPKT 12 -#define S6_GMAC_STATCARRY2_TBYT 13 -#define S6_GMAC_STATCARRY2_TFRG 14 -#define S6_GMAC_STATCARRY2_TUND 15 -#define S6_GMAC_STATCARRY2_TOVR 16 -#define S6_GMAC_STATCARRY2_TXCF 17 -#define S6_GMAC_STATCARRY2_TFCS 18 -#define S6_GMAC_STATCARRY2_TJBR 19 - -#define S6_GMAC_HOST_PBLKCTRL 0x140 -#define S6_GMAC_HOST_PBLKCTRL_TXENA 0 -#define S6_GMAC_HOST_PBLKCTRL_RXENA 1 -#define S6_GMAC_HOST_PBLKCTRL_TXSRES 2 -#define S6_GMAC_HOST_PBLKCTRL_RXSRES 3 -#define S6_GMAC_HOST_PBLKCTRL_TXBSIZ 8 -#define S6_GMAC_HOST_PBLKCTRL_RXBSIZ 12 -#define S6_GMAC_HOST_PBLKCTRL_SIZ_16 4 -#define S6_GMAC_HOST_PBLKCTRL_SIZ_32 5 -#define S6_GMAC_HOST_PBLKCTRL_SIZ_64 6 -#define S6_GMAC_HOST_PBLKCTRL_SIZ_128 7 -#define S6_GMAC_HOST_PBLKCTRL_SIZ_MASK 0xF -#define S6_GMAC_HOST_PBLKCTRL_STATENA 16 -#define S6_GMAC_HOST_PBLKCTRL_STATAUTOZ 17 -#define S6_GMAC_HOST_PBLKCTRL_STATCLEAR 18 -#define S6_GMAC_HOST_PBLKCTRL_RGMII 19 -#define S6_GMAC_HOST_INTMASK 0x144 -#define S6_GMAC_HOST_INTSTAT 0x148 -#define S6_GMAC_HOST_INT_TXBURSTOVER 3 -#define S6_GMAC_HOST_INT_TXPREWOVER 4 -#define S6_GMAC_HOST_INT_RXBURSTUNDER 5 -#define S6_GMAC_HOST_INT_RXPOSTRFULL 6 -#define S6_GMAC_HOST_INT_RXPOSTRUNDER 7 -#define S6_GMAC_HOST_RXFIFOHWM 0x14C -#define S6_GMAC_HOST_CTRLFRAMXP 0x150 -#define S6_GMAC_HOST_DSTADDRLO(n) (0x160 + 8*(n)) -#define S6_GMAC_HOST_DSTADDRHI(n) (0x164 + 8*(n)) -#define S6_GMAC_HOST_DSTMASKLO(n) (0x180 + 8*(n)) -#define S6_GMAC_HOST_DSTMASKHI(n) (0x184 + 8*(n)) - -#define S6_GMAC_BURST_PREWR 0x1B0 -#define S6_GMAC_BURST_PREWR_LEN 0 -#define S6_GMAC_BURST_PREWR_LEN_MASK ((1 << 20) - 1) -#define S6_GMAC_BURST_PREWR_CFE 20 -#define S6_GMAC_BURST_PREWR_PPE 21 -#define S6_GMAC_BURST_PREWR_FCS 22 -#define S6_GMAC_BURST_PREWR_PAD 23 -#define S6_GMAC_BURST_POSTRD 0x1D0 -#define S6_GMAC_BURST_POSTRD_LEN 0 -#define S6_GMAC_BURST_POSTRD_LEN_MASK ((1 << 20) - 1) -#define S6_GMAC_BURST_POSTRD_DROP 20 - - -/* data handling */ - -#define S6_NUM_TX_SKB 8 /* must be larger than TX fifo size */ -#define S6_NUM_RX_SKB 16 -#define S6_MAX_FRLEN 1536 - -struct s6gmac { - u32 reg; - u32 tx_dma; - u32 rx_dma; - u32 io; - u8 tx_chan; - u8 rx_chan; - spinlock_t lock; - u8 tx_skb_i, tx_skb_o; - u8 rx_skb_i, rx_skb_o; - struct sk_buff *tx_skb[S6_NUM_TX_SKB]; - struct sk_buff *rx_skb[S6_NUM_RX_SKB]; - unsigned long carry[sizeof(struct net_device_stats) / sizeof(long)]; - unsigned long stats[sizeof(struct net_device_stats) / sizeof(long)]; - struct phy_device *phydev; - struct { - struct mii_bus *bus; - int irq[PHY_MAX_ADDR]; - } mii; - struct { - unsigned int mbit; - u8 giga; - u8 isup; - u8 full; - } link; -}; - -static void s6gmac_rx_fillfifo(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - struct sk_buff *skb; - while ((((u8)(pd->rx_skb_i - pd->rx_skb_o)) < S6_NUM_RX_SKB) && - (!s6dmac_fifo_full(pd->rx_dma, pd->rx_chan)) && - (skb = netdev_alloc_skb(dev, S6_MAX_FRLEN + 2))) { - pd->rx_skb[(pd->rx_skb_i++) % S6_NUM_RX_SKB] = skb; - s6dmac_put_fifo_cache(pd->rx_dma, pd->rx_chan, - pd->io, (u32)skb->data, S6_MAX_FRLEN); - } -} - -static void s6gmac_rx_interrupt(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - u32 pfx; - struct sk_buff *skb; - while (((u8)(pd->rx_skb_i - pd->rx_skb_o)) > - s6dmac_pending_count(pd->rx_dma, pd->rx_chan)) { - skb = pd->rx_skb[(pd->rx_skb_o++) % S6_NUM_RX_SKB]; - pfx = readl(pd->reg + S6_GMAC_BURST_POSTRD); - if (pfx & (1 << S6_GMAC_BURST_POSTRD_DROP)) { - dev_kfree_skb_irq(skb); - } else { - skb_put(skb, (pfx >> S6_GMAC_BURST_POSTRD_LEN) - & S6_GMAC_BURST_POSTRD_LEN_MASK); - skb->protocol = eth_type_trans(skb, dev); - skb->ip_summed = CHECKSUM_UNNECESSARY; - netif_rx(skb); - } - } -} - -static void s6gmac_tx_interrupt(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - while (((u8)(pd->tx_skb_i - pd->tx_skb_o)) > - s6dmac_pending_count(pd->tx_dma, pd->tx_chan)) { - dev_kfree_skb_irq(pd->tx_skb[(pd->tx_skb_o++) % S6_NUM_TX_SKB]); - } - if (!s6dmac_fifo_full(pd->tx_dma, pd->tx_chan)) - netif_wake_queue(dev); -} - -struct s6gmac_statinf { - unsigned reg_size : 4; /* 0: unused */ - unsigned reg_off : 6; - unsigned net_index : 6; -}; - -#define S6_STATS_B (8 * sizeof(u32)) -#define S6_STATS_C(b, r, f) [b] = { \ - BUILD_BUG_ON_ZERO(r##_SIZE < S6_GMAC_STAT_SIZE_MIN) + \ - BUILD_BUG_ON_ZERO((r##_SIZE - (S6_GMAC_STAT_SIZE_MIN - 1)) \ - >= (1<<4)) + \ - r##_SIZE - (S6_GMAC_STAT_SIZE_MIN - 1), \ - BUILD_BUG_ON_ZERO(((unsigned)((r - S6_GMAC_STAT_REGS) / sizeof(u32))) \ - >= ((1<<6)-1)) + \ - (r - S6_GMAC_STAT_REGS) / sizeof(u32), \ - BUILD_BUG_ON_ZERO((offsetof(struct net_device_stats, f)) \ - % sizeof(unsigned long)) + \ - BUILD_BUG_ON_ZERO((((unsigned)(offsetof(struct net_device_stats, f)) \ - / sizeof(unsigned long)) >= (1<<6))) + \ - BUILD_BUG_ON_ZERO((sizeof(((struct net_device_stats *)0)->f) \ - != sizeof(unsigned long))) + \ - (offsetof(struct net_device_stats, f)) / sizeof(unsigned long)}, - -static const struct s6gmac_statinf statinf[2][S6_STATS_B] = { { - S6_STATS_C(S6_GMAC_STATCARRY1_RBYT, S6_GMAC_STATRBYT, rx_bytes) - S6_STATS_C(S6_GMAC_STATCARRY1_RPKT, S6_GMAC_STATRPKT, rx_packets) - S6_STATS_C(S6_GMAC_STATCARRY1_RFCS, S6_GMAC_STATRFCS, rx_crc_errors) - S6_STATS_C(S6_GMAC_STATCARRY1_RMCA, S6_GMAC_STATRMCA, multicast) - S6_STATS_C(S6_GMAC_STATCARRY1_RALN, S6_GMAC_STATRALN, rx_frame_errors) - S6_STATS_C(S6_GMAC_STATCARRY1_RFLR, S6_GMAC_STATRFLR, rx_length_errors) - S6_STATS_C(S6_GMAC_STATCARRY1_RCDE, S6_GMAC_STATRCDE, rx_missed_errors) - S6_STATS_C(S6_GMAC_STATCARRY1_RUND, S6_GMAC_STATRUND, rx_length_errors) - S6_STATS_C(S6_GMAC_STATCARRY1_ROVR, S6_GMAC_STATROVR, rx_length_errors) - S6_STATS_C(S6_GMAC_STATCARRY1_RFRG, S6_GMAC_STATRFRG, rx_crc_errors) - S6_STATS_C(S6_GMAC_STATCARRY1_RJBR, S6_GMAC_STATRJBR, rx_crc_errors) - S6_STATS_C(S6_GMAC_STATCARRY1_RDRP, S6_GMAC_STATRDRP, rx_dropped) -}, { - S6_STATS_C(S6_GMAC_STATCARRY2_TBYT, S6_GMAC_STATTBYT, tx_bytes) - S6_STATS_C(S6_GMAC_STATCARRY2_TPKT, S6_GMAC_STATTPKT, tx_packets) - S6_STATS_C(S6_GMAC_STATCARRY2_TEDF, S6_GMAC_STATTEDF, tx_aborted_errors) - S6_STATS_C(S6_GMAC_STATCARRY2_TXCL, S6_GMAC_STATTXCL, tx_aborted_errors) - S6_STATS_C(S6_GMAC_STATCARRY2_TNCL, S6_GMAC_STATTNCL, collisions) - S6_STATS_C(S6_GMAC_STATCARRY2_TDRP, S6_GMAC_STATTDRP, tx_dropped) - S6_STATS_C(S6_GMAC_STATCARRY2_TJBR, S6_GMAC_STATTJBR, tx_errors) - S6_STATS_C(S6_GMAC_STATCARRY2_TFCS, S6_GMAC_STATTFCS, tx_errors) - S6_STATS_C(S6_GMAC_STATCARRY2_TOVR, S6_GMAC_STATTOVR, tx_errors) - S6_STATS_C(S6_GMAC_STATCARRY2_TUND, S6_GMAC_STATTUND, tx_errors) - S6_STATS_C(S6_GMAC_STATCARRY2_TFRG, S6_GMAC_STATTFRG, tx_errors) -} }; - -static void s6gmac_stats_collect(struct s6gmac *pd, - const struct s6gmac_statinf *inf) -{ - int b; - for (b = 0; b < S6_STATS_B; b++) { - if (inf[b].reg_size) { - pd->stats[inf[b].net_index] += - readl(pd->reg + S6_GMAC_STAT_REGS - + sizeof(u32) * inf[b].reg_off); - } - } -} - -static void s6gmac_stats_carry(struct s6gmac *pd, - const struct s6gmac_statinf *inf, u32 mask) -{ - int b; - while (mask) { - b = fls(mask) - 1; - mask &= ~(1 << b); - pd->carry[inf[b].net_index] += (1 << inf[b].reg_size); - } -} - -static inline u32 s6gmac_stats_pending(struct s6gmac *pd, int carry) -{ - int r = readl(pd->reg + S6_GMAC_STATCARRY(carry)) & - ~readl(pd->reg + S6_GMAC_STATCARRYMSK(carry)); - return r; -} - -static inline void s6gmac_stats_interrupt(struct s6gmac *pd, int carry) -{ - u32 mask; - mask = s6gmac_stats_pending(pd, carry); - if (mask) { - writel(mask, pd->reg + S6_GMAC_STATCARRY(carry)); - s6gmac_stats_carry(pd, &statinf[carry][0], mask); - } -} - -static irqreturn_t s6gmac_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = (struct net_device *)dev_id; - struct s6gmac *pd = netdev_priv(dev); - if (!dev) - return IRQ_NONE; - spin_lock(&pd->lock); - if (s6dmac_termcnt_irq(pd->rx_dma, pd->rx_chan)) - s6gmac_rx_interrupt(dev); - s6gmac_rx_fillfifo(dev); - if (s6dmac_termcnt_irq(pd->tx_dma, pd->tx_chan)) - s6gmac_tx_interrupt(dev); - s6gmac_stats_interrupt(pd, 0); - s6gmac_stats_interrupt(pd, 1); - spin_unlock(&pd->lock); - return IRQ_HANDLED; -} - -static inline void s6gmac_set_dstaddr(struct s6gmac *pd, int n, - u32 addrlo, u32 addrhi, u32 masklo, u32 maskhi) -{ - writel(addrlo, pd->reg + S6_GMAC_HOST_DSTADDRLO(n)); - writel(addrhi, pd->reg + S6_GMAC_HOST_DSTADDRHI(n)); - writel(masklo, pd->reg + S6_GMAC_HOST_DSTMASKLO(n)); - writel(maskhi, pd->reg + S6_GMAC_HOST_DSTMASKHI(n)); -} - -static inline void s6gmac_stop_device(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - writel(0, pd->reg + S6_GMAC_MACCONF1); -} - -static inline void s6gmac_init_device(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - int is_rgmii = !!(pd->phydev->supported - & (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)); -#if 0 - writel(1 << S6_GMAC_MACCONF1_SYNCTX | - 1 << S6_GMAC_MACCONF1_SYNCRX | - 1 << S6_GMAC_MACCONF1_TXFLOWCTRL | - 1 << S6_GMAC_MACCONF1_RXFLOWCTRL | - 1 << S6_GMAC_MACCONF1_RESTXFUNC | - 1 << S6_GMAC_MACCONF1_RESRXFUNC | - 1 << S6_GMAC_MACCONF1_RESTXMACCTRL | - 1 << S6_GMAC_MACCONF1_RESRXMACCTRL, - pd->reg + S6_GMAC_MACCONF1); -#endif - writel(1 << S6_GMAC_MACCONF1_SOFTRES, pd->reg + S6_GMAC_MACCONF1); - udelay(1000); - writel(1 << S6_GMAC_MACCONF1_TXENA | 1 << S6_GMAC_MACCONF1_RXENA, - pd->reg + S6_GMAC_MACCONF1); - writel(1 << S6_GMAC_HOST_PBLKCTRL_TXSRES | - 1 << S6_GMAC_HOST_PBLKCTRL_RXSRES, - pd->reg + S6_GMAC_HOST_PBLKCTRL); - writel(S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_TXBSIZ | - S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_RXBSIZ | - 1 << S6_GMAC_HOST_PBLKCTRL_STATENA | - 1 << S6_GMAC_HOST_PBLKCTRL_STATCLEAR | - is_rgmii << S6_GMAC_HOST_PBLKCTRL_RGMII, - pd->reg + S6_GMAC_HOST_PBLKCTRL); - writel(1 << S6_GMAC_MACCONF1_TXENA | - 1 << S6_GMAC_MACCONF1_RXENA | - (dev->flags & IFF_LOOPBACK ? 1 : 0) - << S6_GMAC_MACCONF1_LOOPBACK, - pd->reg + S6_GMAC_MACCONF1); - writel(dev->mtu && (dev->mtu < (S6_MAX_FRLEN - ETH_HLEN-ETH_FCS_LEN)) ? - dev->mtu+ETH_HLEN+ETH_FCS_LEN : S6_MAX_FRLEN, - pd->reg + S6_GMAC_MACMAXFRAMELEN); - writel((pd->link.full ? 1 : 0) << S6_GMAC_MACCONF2_FULL | - 1 << S6_GMAC_MACCONF2_PADCRCENA | - 1 << S6_GMAC_MACCONF2_LENGTHFCHK | - (pd->link.giga ? - S6_GMAC_MACCONF2_IFMODE_BYTE : - S6_GMAC_MACCONF2_IFMODE_NIBBLE) - << S6_GMAC_MACCONF2_IFMODE | - 7 << S6_GMAC_MACCONF2_PREAMBLELEN, - pd->reg + S6_GMAC_MACCONF2); - writel(0, pd->reg + S6_GMAC_MACSTATADDR1); - writel(0, pd->reg + S6_GMAC_MACSTATADDR2); - writel(1 << S6_GMAC_FIFOCONF0_WTMENREQ | - 1 << S6_GMAC_FIFOCONF0_SRFENREQ | - 1 << S6_GMAC_FIFOCONF0_FRFENREQ | - 1 << S6_GMAC_FIFOCONF0_STFENREQ | - 1 << S6_GMAC_FIFOCONF0_FTFENREQ, - pd->reg + S6_GMAC_FIFOCONF0); - writel(128 << S6_GMAC_FIFOCONF3_CFGFTTH | - 128 << S6_GMAC_FIFOCONF3_CFGHWMFT, - pd->reg + S6_GMAC_FIFOCONF3); - writel((S6_GMAC_FIFOCONF_RSV_MASK & ~( - 1 << S6_GMAC_FIFOCONF_RSV_RUNT | - 1 << S6_GMAC_FIFOCONF_RSV_CRCERR | - 1 << S6_GMAC_FIFOCONF_RSV_OK | - 1 << S6_GMAC_FIFOCONF_RSV_DRIBBLE | - 1 << S6_GMAC_FIFOCONF_RSV_CTRLFRAME | - 1 << S6_GMAC_FIFOCONF_RSV_PAUSECTRL | - 1 << S6_GMAC_FIFOCONF_RSV_UNOPCODE | - 1 << S6_GMAC_FIFOCONF_RSV_TRUNCATED)) | - 1 << S6_GMAC_FIFOCONF5_DROPLT64 | - pd->link.giga << S6_GMAC_FIFOCONF5_CFGBYTM | - 1 << S6_GMAC_FIFOCONF5_RXDROPSIZE, - pd->reg + S6_GMAC_FIFOCONF5); - writel(1 << S6_GMAC_FIFOCONF_RSV_RUNT | - 1 << S6_GMAC_FIFOCONF_RSV_CRCERR | - 1 << S6_GMAC_FIFOCONF_RSV_DRIBBLE | - 1 << S6_GMAC_FIFOCONF_RSV_CTRLFRAME | - 1 << S6_GMAC_FIFOCONF_RSV_PAUSECTRL | - 1 << S6_GMAC_FIFOCONF_RSV_UNOPCODE | - 1 << S6_GMAC_FIFOCONF_RSV_TRUNCATED, - pd->reg + S6_GMAC_FIFOCONF4); - s6gmac_set_dstaddr(pd, 0, - 0xFFFFFFFF, 0x0000FFFF, 0xFFFFFFFF, 0x0000FFFF); - s6gmac_set_dstaddr(pd, 1, - dev->dev_addr[5] | - dev->dev_addr[4] << 8 | - dev->dev_addr[3] << 16 | - dev->dev_addr[2] << 24, - dev->dev_addr[1] | - dev->dev_addr[0] << 8, - 0xFFFFFFFF, 0x0000FFFF); - s6gmac_set_dstaddr(pd, 2, - 0x00000000, 0x00000100, 0x00000000, 0x00000100); - s6gmac_set_dstaddr(pd, 3, - 0x00000000, 0x00000000, 0x00000000, 0x00000000); - writel(1 << S6_GMAC_HOST_PBLKCTRL_TXENA | - 1 << S6_GMAC_HOST_PBLKCTRL_RXENA | - S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_TXBSIZ | - S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_RXBSIZ | - 1 << S6_GMAC_HOST_PBLKCTRL_STATENA | - 1 << S6_GMAC_HOST_PBLKCTRL_STATCLEAR | - is_rgmii << S6_GMAC_HOST_PBLKCTRL_RGMII, - pd->reg + S6_GMAC_HOST_PBLKCTRL); -} - -static void s6mii_enable(struct s6gmac *pd) -{ - writel(readl(pd->reg + S6_GMAC_MACCONF1) & - ~(1 << S6_GMAC_MACCONF1_SOFTRES), - pd->reg + S6_GMAC_MACCONF1); - writel((readl(pd->reg + S6_GMAC_MACMIICONF) - & ~(S6_GMAC_MACMIICONF_CSEL_MASK << S6_GMAC_MACMIICONF_CSEL)) - | (S6_GMAC_MACMIICONF_CSEL_DIV168 << S6_GMAC_MACMIICONF_CSEL), - pd->reg + S6_GMAC_MACMIICONF); -} - -static int s6mii_busy(struct s6gmac *pd, int tmo) -{ - while (readl(pd->reg + S6_GMAC_MACMIIINDI)) { - if (--tmo == 0) - return -ETIME; - udelay(64); - } - return 0; -} - -static int s6mii_read(struct mii_bus *bus, int phy_addr, int regnum) -{ - struct s6gmac *pd = bus->priv; - s6mii_enable(pd); - if (s6mii_busy(pd, 256)) - return -ETIME; - writel(phy_addr << S6_GMAC_MACMIIADDR_PHY | - regnum << S6_GMAC_MACMIIADDR_REG, - pd->reg + S6_GMAC_MACMIIADDR); - writel(1 << S6_GMAC_MACMIICMD_READ, pd->reg + S6_GMAC_MACMIICMD); - writel(0, pd->reg + S6_GMAC_MACMIICMD); - if (s6mii_busy(pd, 256)) - return -ETIME; - return (u16)readl(pd->reg + S6_GMAC_MACMIISTAT); -} - -static int s6mii_write(struct mii_bus *bus, int phy_addr, int regnum, u16 value) -{ - struct s6gmac *pd = bus->priv; - s6mii_enable(pd); - if (s6mii_busy(pd, 256)) - return -ETIME; - writel(phy_addr << S6_GMAC_MACMIIADDR_PHY | - regnum << S6_GMAC_MACMIIADDR_REG, - pd->reg + S6_GMAC_MACMIIADDR); - writel(value, pd->reg + S6_GMAC_MACMIICTRL); - if (s6mii_busy(pd, 256)) - return -ETIME; - return 0; -} - -static int s6mii_reset(struct mii_bus *bus) -{ - struct s6gmac *pd = bus->priv; - s6mii_enable(pd); - if (s6mii_busy(pd, PHY_INIT_TIMEOUT)) - return -ETIME; - return 0; -} - -static void s6gmac_set_rgmii_txclock(struct s6gmac *pd) -{ - u32 pllsel = readl(S6_REG_GREG1 + S6_GREG1_PLLSEL); - pllsel &= ~(S6_GREG1_PLLSEL_GMAC_MASK << S6_GREG1_PLLSEL_GMAC); - switch (pd->link.mbit) { - case 10: - pllsel |= S6_GREG1_PLLSEL_GMAC_2500KHZ << S6_GREG1_PLLSEL_GMAC; - break; - case 100: - pllsel |= S6_GREG1_PLLSEL_GMAC_25MHZ << S6_GREG1_PLLSEL_GMAC; - break; - case 1000: - pllsel |= S6_GREG1_PLLSEL_GMAC_125MHZ << S6_GREG1_PLLSEL_GMAC; - break; - default: - return; - } - writel(pllsel, S6_REG_GREG1 + S6_GREG1_PLLSEL); -} - -static inline void s6gmac_linkisup(struct net_device *dev, int isup) -{ - struct s6gmac *pd = netdev_priv(dev); - struct phy_device *phydev = pd->phydev; - - pd->link.full = phydev->duplex; - pd->link.giga = (phydev->speed == 1000); - if (pd->link.mbit != phydev->speed) { - pd->link.mbit = phydev->speed; - s6gmac_set_rgmii_txclock(pd); - } - pd->link.isup = isup; - if (isup) - netif_carrier_on(dev); - phy_print_status(phydev); -} - -static void s6gmac_adjust_link(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - struct phy_device *phydev = pd->phydev; - if (pd->link.isup && - (!phydev->link || - (pd->link.mbit != phydev->speed) || - (pd->link.full != phydev->duplex))) { - pd->link.isup = 0; - netif_tx_disable(dev); - if (!phydev->link) { - netif_carrier_off(dev); - phy_print_status(phydev); - } - } - if (!pd->link.isup && phydev->link) { - if (pd->link.full != phydev->duplex) { - u32 maccfg = readl(pd->reg + S6_GMAC_MACCONF2); - if (phydev->duplex) - maccfg |= 1 << S6_GMAC_MACCONF2_FULL; - else - maccfg &= ~(1 << S6_GMAC_MACCONF2_FULL); - writel(maccfg, pd->reg + S6_GMAC_MACCONF2); - } - - if (pd->link.giga != (phydev->speed == 1000)) { - u32 fifocfg = readl(pd->reg + S6_GMAC_FIFOCONF5); - u32 maccfg = readl(pd->reg + S6_GMAC_MACCONF2); - maccfg &= ~(S6_GMAC_MACCONF2_IFMODE_MASK - << S6_GMAC_MACCONF2_IFMODE); - if (phydev->speed == 1000) { - fifocfg |= 1 << S6_GMAC_FIFOCONF5_CFGBYTM; - maccfg |= S6_GMAC_MACCONF2_IFMODE_BYTE - << S6_GMAC_MACCONF2_IFMODE; - } else { - fifocfg &= ~(1 << S6_GMAC_FIFOCONF5_CFGBYTM); - maccfg |= S6_GMAC_MACCONF2_IFMODE_NIBBLE - << S6_GMAC_MACCONF2_IFMODE; - } - writel(fifocfg, pd->reg + S6_GMAC_FIFOCONF5); - writel(maccfg, pd->reg + S6_GMAC_MACCONF2); - } - - if (!s6dmac_fifo_full(pd->tx_dma, pd->tx_chan)) - netif_wake_queue(dev); - s6gmac_linkisup(dev, 1); - } -} - -static inline int s6gmac_phy_start(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - int i = 0; - struct phy_device *p = NULL; - while ((i < PHY_MAX_ADDR) && (!(p = pd->mii.bus->phy_map[i]))) - i++; - p = phy_connect(dev, dev_name(&p->dev), &s6gmac_adjust_link, - PHY_INTERFACE_MODE_RGMII); - if (IS_ERR(p)) { - printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); - return PTR_ERR(p); - } - p->supported &= PHY_GBIT_FEATURES; - p->advertising = p->supported; - pd->phydev = p; - return 0; -} - -static inline void s6gmac_init_stats(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - u32 mask; - mask = 1 << S6_GMAC_STATCARRY1_RDRP | - 1 << S6_GMAC_STATCARRY1_RJBR | - 1 << S6_GMAC_STATCARRY1_RFRG | - 1 << S6_GMAC_STATCARRY1_ROVR | - 1 << S6_GMAC_STATCARRY1_RUND | - 1 << S6_GMAC_STATCARRY1_RCDE | - 1 << S6_GMAC_STATCARRY1_RFLR | - 1 << S6_GMAC_STATCARRY1_RALN | - 1 << S6_GMAC_STATCARRY1_RMCA | - 1 << S6_GMAC_STATCARRY1_RFCS | - 1 << S6_GMAC_STATCARRY1_RPKT | - 1 << S6_GMAC_STATCARRY1_RBYT; - writel(mask, pd->reg + S6_GMAC_STATCARRY(0)); - writel(~mask, pd->reg + S6_GMAC_STATCARRYMSK(0)); - mask = 1 << S6_GMAC_STATCARRY2_TDRP | - 1 << S6_GMAC_STATCARRY2_TNCL | - 1 << S6_GMAC_STATCARRY2_TXCL | - 1 << S6_GMAC_STATCARRY2_TEDF | - 1 << S6_GMAC_STATCARRY2_TPKT | - 1 << S6_GMAC_STATCARRY2_TBYT | - 1 << S6_GMAC_STATCARRY2_TFRG | - 1 << S6_GMAC_STATCARRY2_TUND | - 1 << S6_GMAC_STATCARRY2_TOVR | - 1 << S6_GMAC_STATCARRY2_TFCS | - 1 << S6_GMAC_STATCARRY2_TJBR; - writel(mask, pd->reg + S6_GMAC_STATCARRY(1)); - writel(~mask, pd->reg + S6_GMAC_STATCARRYMSK(1)); -} - -static inline void s6gmac_init_dmac(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - s6dmac_disable_chan(pd->tx_dma, pd->tx_chan); - s6dmac_disable_chan(pd->rx_dma, pd->rx_chan); - s6dmac_disable_error_irqs(pd->tx_dma, 1 << S6_HIFDMA_GMACTX); - s6dmac_disable_error_irqs(pd->rx_dma, 1 << S6_HIFDMA_GMACRX); -} - -static int s6gmac_tx(struct sk_buff *skb, struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&pd->lock, flags); - writel(skb->len << S6_GMAC_BURST_PREWR_LEN | - 0 << S6_GMAC_BURST_PREWR_CFE | - 1 << S6_GMAC_BURST_PREWR_PPE | - 1 << S6_GMAC_BURST_PREWR_FCS | - ((skb->len < ETH_ZLEN) ? 1 : 0) << S6_GMAC_BURST_PREWR_PAD, - pd->reg + S6_GMAC_BURST_PREWR); - s6dmac_put_fifo_cache(pd->tx_dma, pd->tx_chan, - (u32)skb->data, pd->io, skb->len); - if (s6dmac_fifo_full(pd->tx_dma, pd->tx_chan)) - netif_stop_queue(dev); - if (((u8)(pd->tx_skb_i - pd->tx_skb_o)) >= S6_NUM_TX_SKB) { - printk(KERN_ERR "GMAC BUG: skb tx ring overflow [%x, %x]\n", - pd->tx_skb_o, pd->tx_skb_i); - BUG(); - } - pd->tx_skb[(pd->tx_skb_i++) % S6_NUM_TX_SKB] = skb; - spin_unlock_irqrestore(&pd->lock, flags); - return 0; -} - -static void s6gmac_tx_timeout(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - unsigned long flags; - spin_lock_irqsave(&pd->lock, flags); - s6gmac_tx_interrupt(dev); - spin_unlock_irqrestore(&pd->lock, flags); -} - -static int s6gmac_open(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - unsigned long flags; - phy_read_status(pd->phydev); - spin_lock_irqsave(&pd->lock, flags); - pd->link.mbit = 0; - s6gmac_linkisup(dev, pd->phydev->link); - s6gmac_init_device(dev); - s6gmac_init_stats(dev); - s6gmac_init_dmac(dev); - s6gmac_rx_fillfifo(dev); - s6dmac_enable_chan(pd->rx_dma, pd->rx_chan, - 2, 1, 0, 1, 0, 0, 0, 7, -1, 2, 0, 1); - s6dmac_enable_chan(pd->tx_dma, pd->tx_chan, - 2, 0, 1, 0, 0, 0, 0, 7, -1, 2, 0, 1); - writel(0 << S6_GMAC_HOST_INT_TXBURSTOVER | - 0 << S6_GMAC_HOST_INT_TXPREWOVER | - 0 << S6_GMAC_HOST_INT_RXBURSTUNDER | - 0 << S6_GMAC_HOST_INT_RXPOSTRFULL | - 0 << S6_GMAC_HOST_INT_RXPOSTRUNDER, - pd->reg + S6_GMAC_HOST_INTMASK); - spin_unlock_irqrestore(&pd->lock, flags); - phy_start(pd->phydev); - netif_start_queue(dev); - return 0; -} - -static int s6gmac_stop(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - unsigned long flags; - netif_stop_queue(dev); - phy_stop(pd->phydev); - spin_lock_irqsave(&pd->lock, flags); - s6gmac_init_dmac(dev); - s6gmac_stop_device(dev); - while (pd->tx_skb_i != pd->tx_skb_o) - dev_kfree_skb(pd->tx_skb[(pd->tx_skb_o++) % S6_NUM_TX_SKB]); - while (pd->rx_skb_i != pd->rx_skb_o) - dev_kfree_skb(pd->rx_skb[(pd->rx_skb_o++) % S6_NUM_RX_SKB]); - spin_unlock_irqrestore(&pd->lock, flags); - return 0; -} - -static struct net_device_stats *s6gmac_stats(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - struct net_device_stats *st = (struct net_device_stats *)&pd->stats; - int i; - do { - unsigned long flags; - spin_lock_irqsave(&pd->lock, flags); - for (i = 0; i < ARRAY_SIZE(pd->stats); i++) - pd->stats[i] = - pd->carry[i] << (S6_GMAC_STAT_SIZE_MIN - 1); - s6gmac_stats_collect(pd, &statinf[0][0]); - s6gmac_stats_collect(pd, &statinf[1][0]); - i = s6gmac_stats_pending(pd, 0) | - s6gmac_stats_pending(pd, 1); - spin_unlock_irqrestore(&pd->lock, flags); - } while (i); - st->rx_errors = st->rx_crc_errors + - st->rx_frame_errors + - st->rx_length_errors + - st->rx_missed_errors; - st->tx_errors += st->tx_aborted_errors; - return st; -} - -static int s6gmac_probe(struct platform_device *pdev) -{ - struct net_device *dev; - struct s6gmac *pd; - int res; - unsigned long i; - struct mii_bus *mb; - - dev = alloc_etherdev(sizeof(*pd)); - if (!dev) - return -ENOMEM; - - dev->open = s6gmac_open; - dev->stop = s6gmac_stop; - dev->hard_start_xmit = s6gmac_tx; - dev->tx_timeout = s6gmac_tx_timeout; - dev->watchdog_timeo = HZ; - dev->get_stats = s6gmac_stats; - dev->irq = platform_get_irq(pdev, 0); - pd = netdev_priv(dev); - memset(pd, 0, sizeof(*pd)); - spin_lock_init(&pd->lock); - pd->reg = platform_get_resource(pdev, IORESOURCE_MEM, 0)->start; - i = platform_get_resource(pdev, IORESOURCE_DMA, 0)->start; - pd->tx_dma = DMA_MASK_DMAC(i); - pd->tx_chan = DMA_INDEX_CHNL(i); - i = platform_get_resource(pdev, IORESOURCE_DMA, 1)->start; - pd->rx_dma = DMA_MASK_DMAC(i); - pd->rx_chan = DMA_INDEX_CHNL(i); - pd->io = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; - res = request_irq(dev->irq, s6gmac_interrupt, 0, dev->name, dev); - if (res) { - printk(KERN_ERR DRV_PRMT "irq request failed: %d\n", dev->irq); - goto errirq; - } - res = register_netdev(dev); - if (res) { - printk(KERN_ERR DRV_PRMT "error registering device %s\n", - dev->name); - goto errdev; - } - mb = mdiobus_alloc(); - if (!mb) { - printk(KERN_ERR DRV_PRMT "error allocating mii bus\n"); - res = -ENOMEM; - goto errmii; - } - mb->name = "s6gmac_mii"; - mb->read = s6mii_read; - mb->write = s6mii_write; - mb->reset = s6mii_reset; - mb->priv = pd; - snprintf(mb->id, MII_BUS_ID_SIZE, "%s-%x", pdev->name, pdev->id); - mb->phy_mask = ~(1 << 0); - mb->irq = &pd->mii.irq[0]; - for (i = 0; i < PHY_MAX_ADDR; i++) { - int n = platform_get_irq(pdev, i + 1); - if (n < 0) - n = PHY_POLL; - pd->mii.irq[i] = n; - } - mdiobus_register(mb); - pd->mii.bus = mb; - res = s6gmac_phy_start(dev); - if (res) - return res; - platform_set_drvdata(pdev, dev); - return 0; -errmii: - unregister_netdev(dev); -errdev: - free_irq(dev->irq, dev); -errirq: - free_netdev(dev); - return res; -} - -static int s6gmac_remove(struct platform_device *pdev) -{ - struct net_device *dev = platform_get_drvdata(pdev); - if (dev) { - struct s6gmac *pd = netdev_priv(dev); - mdiobus_unregister(pd->mii.bus); - unregister_netdev(dev); - free_irq(dev->irq, dev); - free_netdev(dev); - } - return 0; -} - -static struct platform_driver s6gmac_driver = { - .probe = s6gmac_probe, - .remove = s6gmac_remove, - .driver = { - .name = "s6gmac", - }, -}; - -module_platform_driver(s6gmac_driver); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("S6105 on chip Ethernet driver"); -MODULE_AUTHOR("Oskar Schirmer <oskar@scara.com>"); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 118a427d1942..8c6b7c1651e5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1671,7 +1671,7 @@ static void stmmac_init_tx_coalesce(struct stmmac_priv *priv) * 0 on success and an appropriate (-)ve integer as defined in errno.h * file on failure. */ -static int stmmac_hw_setup(struct net_device *dev) +static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) { struct stmmac_priv *priv = netdev_priv(dev); int ret; @@ -1708,9 +1708,11 @@ static int stmmac_hw_setup(struct net_device *dev) stmmac_mmc_setup(priv); - ret = stmmac_init_ptp(priv); - if (ret && ret != -EOPNOTSUPP) - pr_warn("%s: failed PTP initialisation\n", __func__); + if (init_ptp) { + ret = stmmac_init_ptp(priv); + if (ret && ret != -EOPNOTSUPP) + pr_warn("%s: failed PTP initialisation\n", __func__); + } #ifdef CONFIG_DEBUG_FS ret = stmmac_init_fs(dev); @@ -1787,7 +1789,7 @@ static int stmmac_open(struct net_device *dev) goto init_error; } - ret = stmmac_hw_setup(dev); + ret = stmmac_hw_setup(dev, true); if (ret < 0) { pr_err("%s: Hw setup failed\n", __func__); goto init_error; @@ -3036,7 +3038,7 @@ int stmmac_resume(struct net_device *ndev) netif_device_attach(ndev); init_dma_desc_rings(ndev, GFP_ATOMIC); - stmmac_hw_setup(ndev); + stmmac_hw_setup(ndev, false); stmmac_init_tx_coalesce(priv); napi_enable(&priv->napi); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 4032b170fe24..3039de2465ba 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -430,7 +430,6 @@ static struct platform_driver stmmac_pltfr_driver = { .remove = stmmac_pltfr_remove, .driver = { .name = STMMAC_RESOURCE_NAME, - .owner = THIS_MODULE, .pm = &stmmac_pltfr_pm_ops, .of_match_table = of_match_ptr(stmmac_dt_ids), }, diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c index 45c408ef67d0..d2835bf7b4fb 100644 --- a/drivers/net/ethernet/sun/sunvnet.c +++ b/drivers/net/ethernet/sun/sunvnet.c @@ -1201,6 +1201,7 @@ static int vnet_handle_offloads(struct vnet_port *port, struct sk_buff *skb) segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO); if (IS_ERR(segs)) { dev->stats.tx_dropped++; + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h index 44b8d2bad8c3..4c9b4fa1d3c1 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet.h +++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h @@ -388,7 +388,6 @@ struct axidma_bd { * @dma_err_tasklet: Tasklet structure to process Axi DMA errors * @tx_irq: Axidma TX IRQ number * @rx_irq: Axidma RX IRQ number - * @temac_type: axienet type to identify between soft and hard temac * @phy_type: Phy type to identify between MII/GMII/RGMII/SGMII/1000 Base-X * @options: AxiEthernet option word * @last_link: Phy link state in which the PHY was negotiated earlier @@ -431,7 +430,6 @@ struct axienet_local { int tx_irq; int rx_irq; - u32 temac_type; u32 phy_type; u32 options; /* Current options word */ diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 4ea2d4e6f1d1..c18a0c637c44 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -1555,10 +1555,6 @@ static int axienet_of_probe(struct platform_device *op) if ((be32_to_cpup(p)) >= 0x4000) lp->jumbo_support = 1; } - p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,temac-type", - NULL); - if (p) - lp->temac_type = be32_to_cpup(p); p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,phy-type", NULL); if (p) lp->phy_type = be32_to_cpup(p); diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 2f48f790c9b4..384ca4f4de4a 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -590,6 +590,7 @@ struct nvsp_message { #define NETVSC_RECEIVE_BUFFER_ID 0xcafe +#define NETVSC_SEND_BUFFER_ID 0 #define NETVSC_PACKET_SIZE 4096 diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index dd867e6cabd6..9f49c0129a78 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -161,8 +161,8 @@ static int netvsc_destroy_buf(struct netvsc_device *net_device) /* Deal with the send buffer we may have setup. * If we got a send section size, it means we received a - * SendsendBufferComplete msg (ie sent - * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need + * NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE msg (ie sent + * NVSP_MSG1_TYPE_SEND_SEND_BUF msg) therefore, we need * to send a revoke msg here */ if (net_device->send_section_size) { @@ -172,7 +172,8 @@ static int netvsc_destroy_buf(struct netvsc_device *net_device) revoke_packet->hdr.msg_type = NVSP_MSG1_TYPE_REVOKE_SEND_BUF; - revoke_packet->msg.v1_msg.revoke_recv_buf.id = 0; + revoke_packet->msg.v1_msg.revoke_send_buf.id = + NETVSC_SEND_BUFFER_ID; ret = vmbus_sendpacket(net_device->dev->channel, revoke_packet, @@ -204,7 +205,7 @@ static int netvsc_destroy_buf(struct netvsc_device *net_device) net_device->send_buf_gpadl_handle = 0; } if (net_device->send_buf) { - /* Free up the receive buffer */ + /* Free up the send buffer */ vfree(net_device->send_buf); net_device->send_buf = NULL; } @@ -339,9 +340,9 @@ static int netvsc_init_buf(struct hv_device *device) init_packet = &net_device->channel_init_pkt; memset(init_packet, 0, sizeof(struct nvsp_message)); init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_SEND_BUF; - init_packet->msg.v1_msg.send_recv_buf.gpadl_handle = + init_packet->msg.v1_msg.send_send_buf.gpadl_handle = net_device->send_buf_gpadl_handle; - init_packet->msg.v1_msg.send_recv_buf.id = 0; + init_packet->msg.v1_msg.send_send_buf.id = NETVSC_SEND_BUFFER_ID; /* Send the gpadl notification request */ ret = vmbus_sendpacket(device->channel, init_packet, @@ -364,7 +365,7 @@ static int netvsc_init_buf(struct hv_device *device) netdev_err(ndev, "Unable to complete send buffer " "initialization with NetVsp - status %d\n", init_packet->msg.v1_msg. - send_recv_buf_complete.status); + send_send_buf_complete.status); ret = -EINVAL; goto cleanup; } diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index c530de1e63f5..3ad8ca76196d 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -88,6 +88,7 @@ struct kszphy_priv { static const struct kszphy_type ksz8021_type = { .led_mode_reg = MII_KSZPHY_CTRL_2, + .has_broadcast_disable = true, .has_rmii_ref_clk_sel = true, }; @@ -258,19 +259,6 @@ static int kszphy_config_init(struct phy_device *phydev) return 0; } -static int ksz8021_config_init(struct phy_device *phydev) -{ - int rc; - - rc = kszphy_config_init(phydev); - if (rc) - return rc; - - rc = kszphy_broadcast_disable(phydev); - - return rc < 0 ? rc : 0; -} - static int ksz9021_load_values_from_of(struct phy_device *phydev, struct device_node *of_node, u16 reg, char *field1, char *field2, @@ -584,7 +572,7 @@ static struct phy_driver ksphy_driver[] = { .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .driver_data = &ksz8021_type, .probe = kszphy_probe, - .config_init = ksz8021_config_init, + .config_init = kszphy_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, @@ -601,7 +589,7 @@ static struct phy_driver ksphy_driver[] = { .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .driver_data = &ksz8021_type, .probe = kszphy_probe, - .config_init = ksz8021_config_init, + .config_init = kszphy_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index b8bd7191572d..5ca97713bfb3 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -760,7 +760,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget) container_of(napi, struct receive_queue, napi); unsigned int r, received = 0; -again: received += virtnet_receive(rq, budget - received); /* Out of packets? */ @@ -771,7 +770,6 @@ again: napi_schedule_prep(napi)) { virtqueue_disable_cb(rq->vq); __napi_schedule(napi); - goto again; } } diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 49d9f2291998..7fbd89fbe107 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1579,8 +1579,10 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, bool udp_sum = !udp_get_no_check6_tx(vs->sock->sk); skb = udp_tunnel_handle_offloads(skb, udp_sum); - if (IS_ERR(skb)) - return -EINVAL; + if (IS_ERR(skb)) { + err = -EINVAL; + goto err; + } skb_scrub_packet(skb, xnet); @@ -1590,12 +1592,16 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, /* Need space for new headers (invalidates iph ptr) */ err = skb_cow_head(skb, min_headroom); - if (unlikely(err)) - return err; + if (unlikely(err)) { + kfree_skb(skb); + goto err; + } skb = vlan_hwaccel_push_inside(skb); - if (WARN_ON(!skb)) - return -ENOMEM; + if (WARN_ON(!skb)) { + err = -ENOMEM; + goto err; + } vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); vxh->vx_flags = htonl(VXLAN_FLAGS); @@ -1606,6 +1612,9 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, udp_tunnel6_xmit_skb(vs->sock, dst, skb, dev, saddr, daddr, prio, ttl, src_port, dst_port); return 0; +err: + dst_release(dst); + return err; } #endif @@ -1621,7 +1630,7 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, skb = udp_tunnel_handle_offloads(skb, udp_sum); if (IS_ERR(skb)) - return -EINVAL; + return PTR_ERR(skb); min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len + VXLAN_HLEN + sizeof(struct iphdr) @@ -1629,8 +1638,10 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, /* Need space for new headers (invalidates iph ptr) */ err = skb_cow_head(skb, min_headroom); - if (unlikely(err)) + if (unlikely(err)) { + kfree_skb(skb); return err; + } skb = vlan_hwaccel_push_inside(skb); if (WARN_ON(!skb)) @@ -1776,9 +1787,12 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, tos, ttl, df, src_port, dst_port, htonl(vni << 8), !net_eq(vxlan->net, dev_net(vxlan->dev))); - - if (err < 0) + if (err < 0) { + /* skb is already freed. */ + skb = NULL; goto rt_tx_error; + } + iptunnel_xmit_stats(err, &dev->stats, dev->tstats); #if IS_ENABLED(CONFIG_IPV6) } else { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 3c06e9365949..9880dae2a569 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -1070,7 +1070,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, */ if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) && ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) || - (sdiodev->pdata->oob_irq_supported))) + (sdiodev->pdata && sdiodev->pdata->oob_irq_supported))) bus_if->wowl_supported = true; #endif @@ -1167,7 +1167,7 @@ static int brcmf_ops_sdio_resume(struct device *dev) struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; brcmf_dbg(SDIO, "Enter\n"); - if (sdiodev->pdata->oob_irq_supported) + if (sdiodev->pdata && sdiodev->pdata->oob_irq_supported) disable_irq_wake(sdiodev->pdata->oob_irq_nr); brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS); atomic_set(&sdiodev->suspend, false); diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig index 91c0cb3c368e..21de4fe6cf2d 100644 --- a/drivers/net/wireless/ipw2x00/Kconfig +++ b/drivers/net/wireless/ipw2x00/Kconfig @@ -65,7 +65,8 @@ config IPW2100_DEBUG config IPW2200 tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" - depends on PCI && CFG80211 && CFG80211_WEXT + depends on PCI && CFG80211 + select CFG80211_WEXT select WIRELESS_EXT select WEXT_SPY select WEXT_PRIV diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 38de1513e4de..850b85a47806 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1323,10 +1323,10 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) try_again: /* try next, if any */ - kfree(pieces); release_firmware(ucode_raw); if (iwl_request_firmware(drv, false)) goto out_unbind; + kfree(pieces); return; out_free_fw: diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 9564ae173d06..1f7f15eb86da 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -310,6 +310,7 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) #define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000) #define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT 28 +#define FH_MEM_TB_MAX_LENGTH (0x00020000) /* TFDB Area - TFDs buffer table */ #define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 31a5b3f4266c..e880f9d4717b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1004,8 +1004,13 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm) { lockdep_assert_held(&mvm->mutex); - /* disallow low power states when the FW is down */ - iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); + /* + * Disallow low power states when the FW is down by taking + * the UCODE_DOWN ref. in case of ongoing hw restart the + * ref is already taken, so don't take it again. + */ + if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) + iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); /* async_handlers_wk is now blocked */ @@ -1023,6 +1028,12 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm) /* the fw is stopped, the aux sta is dead: clean up driver state */ iwl_mvm_del_aux_sta(mvm); + /* + * Clear IN_HW_RESTART flag when stopping the hw (as restart_complete() + * won't be called in this case). + */ + clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); + mvm->ucode_loaded = false; } diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 3ee8e3848876..2f0c4b170344 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -367,7 +367,11 @@ static const struct pci_device_id iwl_hw_card_ids[] = { /* 3165 Series */ {IWL_PCI_DEVICE(0x3165, 0x4010, iwl3165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3165, 0x4012, iwl3165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3165, 0x4110, iwl3165_2ac_cfg)}, {IWL_PCI_DEVICE(0x3165, 0x4210, iwl3165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3165, 0x4410, iwl3165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3165, 0x4510, iwl3165_2ac_cfg)}, /* 7265 Series */ {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)}, diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 5d79a1f44b8e..523fe0c88dcb 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -614,7 +614,7 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num, { u8 *v_addr; dma_addr_t p_addr; - u32 offset, chunk_sz = section->len; + u32 offset, chunk_sz = min_t(u32, FH_MEM_TB_MAX_LENGTH, section->len); int ret = 0; IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n", @@ -1012,16 +1012,21 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) /* Stop the device, and put it in low power state */ iwl_pcie_apm_stop(trans); - /* Upon stop, the APM issues an interrupt if HW RF kill is set. - * Clean again the interrupt here + /* stop and reset the on-board processor */ + iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + udelay(20); + + /* + * Upon stop, the APM issues an interrupt if HW RF kill is set. + * This is a bug in certain verions of the hardware. + * Certain devices also keep sending HW RF kill interrupt all + * the time, unless the interrupt is ACKed even if the interrupt + * should be masked. Re-ACK all the interrupts here. */ spin_lock(&trans_pcie->irq_lock); iwl_disable_interrupts(trans); spin_unlock(&trans_pcie->irq_lock); - /* stop and reset the on-board processor */ - iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - udelay(20); /* clear all status bits */ clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c index c71443c4f265..97b5e4ee1ca4 100644 --- a/drivers/powercap/intel_rapl.c +++ b/drivers/powercap/intel_rapl.c @@ -1041,6 +1041,7 @@ static const struct x86_cpu_id rapl_ids[] = { RAPL_CPU(0x45, rapl_defaults_core),/* Haswell ULT */ RAPL_CPU(0x4C, rapl_defaults_atom),/* Braswell */ RAPL_CPU(0x4A, rapl_defaults_atom),/* Tangier */ + RAPL_CPU(0x56, rapl_defaults_core),/* Future Xeon */ RAPL_CPU(0x5A, rapl_defaults_atom),/* Annidale */ {} }; diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index c1444c3d84c2..2809ae0d6bcd 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -570,7 +570,7 @@ static struct regulator_ops s2mps14_reg_ops = { .enable_mask = S2MPS14_ENABLE_MASK \ } -#define regulator_desc_s2mps14_buck(num, min, step) { \ +#define regulator_desc_s2mps14_buck(num, min, step, min_sel) { \ .name = "BUCK"#num, \ .id = S2MPS14_BUCK##num, \ .ops = &s2mps14_reg_ops, \ @@ -579,7 +579,7 @@ static struct regulator_ops s2mps14_reg_ops = { .min_uV = min, \ .uV_step = step, \ .n_voltages = S2MPS14_BUCK_N_VOLTAGES, \ - .linear_min_sel = S2MPS14_BUCK1235_START_SEL, \ + .linear_min_sel = min_sel, \ .ramp_delay = S2MPS14_BUCK_RAMP_DELAY, \ .vsel_reg = S2MPS14_REG_B1CTRL2 + (num - 1) * 2, \ .vsel_mask = S2MPS14_BUCK_VSEL_MASK, \ @@ -613,11 +613,16 @@ static const struct regulator_desc s2mps14_regulators[] = { regulator_desc_s2mps14_ldo(23, MIN_800_MV, STEP_25_MV), regulator_desc_s2mps14_ldo(24, MIN_1800_MV, STEP_25_MV), regulator_desc_s2mps14_ldo(25, MIN_1800_MV, STEP_25_MV), - regulator_desc_s2mps14_buck(1, MIN_600_MV, STEP_6_25_MV), - regulator_desc_s2mps14_buck(2, MIN_600_MV, STEP_6_25_MV), - regulator_desc_s2mps14_buck(3, MIN_600_MV, STEP_6_25_MV), - regulator_desc_s2mps14_buck(4, MIN_1400_MV, STEP_12_5_MV), - regulator_desc_s2mps14_buck(5, MIN_600_MV, STEP_6_25_MV), + regulator_desc_s2mps14_buck(1, MIN_600_MV, STEP_6_25_MV, + S2MPS14_BUCK1235_START_SEL), + regulator_desc_s2mps14_buck(2, MIN_600_MV, STEP_6_25_MV, + S2MPS14_BUCK1235_START_SEL), + regulator_desc_s2mps14_buck(3, MIN_600_MV, STEP_6_25_MV, + S2MPS14_BUCK1235_START_SEL), + regulator_desc_s2mps14_buck(4, MIN_1400_MV, STEP_12_5_MV, + S2MPS14_BUCK4_START_SEL), + regulator_desc_s2mps14_buck(5, MIN_600_MV, STEP_6_25_MV, + S2MPS14_BUCK1235_START_SEL), }; static int s2mps14_pmic_enable_ext_control(struct s2mps11_info *s2mps11, diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index 3b73b96619e2..26270c351624 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h @@ -39,7 +39,7 @@ #define DRV_NAME "fnic" #define DRV_DESCRIPTION "Cisco FCoE HBA Driver" -#define DRV_VERSION "1.6.0.16" +#define DRV_VERSION "1.6.0.17" #define PFX DRV_NAME ": " #define DFX DRV_NAME "%d: " diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 2097de42a147..155b286f1a9d 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -1892,6 +1892,21 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) goto fnic_abort_cmd_end; } + /* IO out of order */ + + if (!(CMD_FLAGS(sc) & (FNIC_IO_ABORTED | FNIC_IO_DONE))) { + spin_unlock_irqrestore(io_lock, flags); + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + "Issuing Host reset due to out of order IO\n"); + + if (fnic_host_reset(sc) == FAILED) { + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + "fnic_host_reset failed.\n"); + } + ret = FAILED; + goto fnic_abort_cmd_end; + } + CMD_STATE(sc) = FNIC_IOREQ_ABTS_COMPLETE; /* diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index e42fff6e8c10..8afb01604d51 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1041,7 +1041,7 @@ retry: } /* signal not to enter either branch of the if () below */ timeleft = 0; - rtn = NEEDS_RETRY; + rtn = FAILED; } else { timeleft = wait_for_completion_timeout(&done, timeout); rtn = SUCCESS; @@ -1081,7 +1081,7 @@ retry: rtn = FAILED; break; } - } else if (!rtn) { + } else if (rtn != FAILED) { scsi_abort_eh_cmnd(scmd); rtn = FAILED; } diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index fedab3c21ddf..399516925d80 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2623,8 +2623,9 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) sd_config_discard(sdkp, SD_LBP_WS16); } else { /* LBP VPD page tells us what to use */ - - if (sdkp->lbpws) + if (sdkp->lbpu && sdkp->max_unmap_blocks && !sdkp->lbprz) + sd_config_discard(sdkp, SD_LBP_UNMAP); + else if (sdkp->lbpws) sd_config_discard(sdkp, SD_LBP_WS16); else if (sdkp->lbpws10) sd_config_discard(sdkp, SD_LBP_WS10); diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c index b410499cddca..aad6683db81b 100644 --- a/drivers/spi/spi-img-spfi.c +++ b/drivers/spi/spi-img-spfi.c @@ -341,7 +341,7 @@ static int img_spfi_start_dma(struct spi_master *master, default: rxconf.src_addr = spfi->phys + SPFI_RX_8BIT_VALID_DATA; rxconf.src_addr_width = 1; - rxconf.src_maxburst = 1; + rxconf.src_maxburst = 4; } dmaengine_slave_config(spfi->rx_ch, &rxconf); @@ -368,7 +368,7 @@ static int img_spfi_start_dma(struct spi_master *master, default: txconf.dst_addr = spfi->phys + SPFI_TX_8BIT_VALID_DATA; txconf.dst_addr_width = 1; - txconf.dst_maxburst = 1; + txconf.dst_maxburst = 4; break; } dmaengine_slave_config(spfi->tx_ch, &txconf); @@ -390,14 +390,14 @@ static int img_spfi_start_dma(struct spi_master *master, dma_async_issue_pending(spfi->rx_ch); } + spfi_start(spfi); + if (xfer->tx_buf) { spfi->tx_dma_busy = true; dmaengine_submit(txdesc); dma_async_issue_pending(spfi->tx_ch); } - spfi_start(spfi); - return 1; stop_dma: diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 239be7cbe5a8..96a5fc0878d8 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -480,6 +480,8 @@ static int sh_msiof_spi_setup(struct spi_device *spi) struct device_node *np = spi->master->dev.of_node; struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master); + pm_runtime_get_sync(&p->pdev->dev); + if (!np) { /* * Use spi->controller_data for CS (same strategy as spi_gpio), @@ -498,6 +500,9 @@ static int sh_msiof_spi_setup(struct spi_device *spi) if (spi->cs_gpio >= 0) gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); + + pm_runtime_put_sync(&p->pdev->dev); + return 0; } diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c index 1bf891bd321a..4f361b77c749 100644 --- a/drivers/staging/lustre/lustre/llite/namei.c +++ b/drivers/staging/lustre/lustre/llite/namei.c @@ -264,7 +264,7 @@ int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc, if ((bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_PERM)) && inode->i_sb->s_root != NULL && - is_root_inode(inode)) + !is_root_inode(inode)) ll_invalidate_aliases(inode); iput(inode); diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index ad09e51ffae4..f65f0d109fc8 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -4,6 +4,8 @@ * Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com) * Copyright (C) 2012 Amit Daniel <amit.kachhap@linaro.org> * + * Copyright (C) 2014 Viresh Kumar <viresh.kumar@linaro.org> + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,6 +30,20 @@ #include <linux/cpu.h> #include <linux/cpu_cooling.h> +/* + * Cooling state <-> CPUFreq frequency + * + * Cooling states are translated to frequencies throughout this driver and this + * is the relation between them. + * + * Highest cooling state corresponds to lowest possible frequency. + * + * i.e. + * level 0 --> 1st Max Freq + * level 1 --> 2nd Max Freq + * ... + */ + /** * struct cpufreq_cooling_device - data for cooling device with cpufreq * @id: unique integer value corresponding to each cpufreq_cooling_device @@ -38,25 +54,27 @@ * cooling devices. * @cpufreq_val: integer value representing the absolute value of the clipped * frequency. + * @max_level: maximum cooling level. One less than total number of valid + * cpufreq frequencies. * @allowed_cpus: all the cpus involved for this cpufreq_cooling_device. + * @node: list_head to link all cpufreq_cooling_device together. * - * This structure is required for keeping information of each - * cpufreq_cooling_device registered. In order to prevent corruption of this a - * mutex lock cooling_cpufreq_lock is used. + * This structure is required for keeping information of each registered + * cpufreq_cooling_device. */ struct cpufreq_cooling_device { int id; struct thermal_cooling_device *cool_dev; unsigned int cpufreq_state; unsigned int cpufreq_val; + unsigned int max_level; + unsigned int *freq_table; /* In descending order */ struct cpumask allowed_cpus; struct list_head node; }; static DEFINE_IDR(cpufreq_idr); static DEFINE_MUTEX(cooling_cpufreq_lock); -static unsigned int cpufreq_dev_count; - static LIST_HEAD(cpufreq_dev_list); /** @@ -98,120 +116,30 @@ static void release_idr(struct idr *idr, int id) /* Below code defines functions to be used for cpufreq as cooling device */ /** - * is_cpufreq_valid - function to check frequency transitioning capability. - * @cpu: cpu for which check is needed. + * get_level: Find the level for a particular frequency + * @cpufreq_dev: cpufreq_dev for which the property is required + * @freq: Frequency * - * This function will check the current state of the system if - * it is capable of changing the frequency for a given @cpu. - * - * Return: 0 if the system is not currently capable of changing - * the frequency of given cpu. !0 in case the frequency is changeable. + * Return: level on success, THERMAL_CSTATE_INVALID on error. */ -static int is_cpufreq_valid(int cpu) +static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_dev, + unsigned int freq) { - struct cpufreq_policy policy; - - return !cpufreq_get_policy(&policy, cpu); -} - -enum cpufreq_cooling_property { - GET_LEVEL, - GET_FREQ, - GET_MAXL, -}; - -/** - * get_property - fetch a property of interest for a give cpu. - * @cpu: cpu for which the property is required - * @input: query parameter - * @output: query return - * @property: type of query (frequency, level, max level) - * - * This is the common function to - * 1. get maximum cpu cooling states - * 2. translate frequency to cooling state - * 3. translate cooling state to frequency - * Note that the code may be not in good shape - * but it is written in this way in order to: - * a) reduce duplicate code as most of the code can be shared. - * b) make sure the logic is consistent when translating between - * cooling states and frequencies. - * - * Return: 0 on success, -EINVAL when invalid parameters are passed. - */ -static int get_property(unsigned int cpu, unsigned long input, - unsigned int *output, - enum cpufreq_cooling_property property) -{ - int i; - unsigned long max_level = 0, level = 0; - unsigned int freq = CPUFREQ_ENTRY_INVALID; - int descend = -1; - struct cpufreq_frequency_table *pos, *table = - cpufreq_frequency_get_table(cpu); - - if (!output) - return -EINVAL; - - if (!table) - return -EINVAL; - - cpufreq_for_each_valid_entry(pos, table) { - /* ignore duplicate entry */ - if (freq == pos->frequency) - continue; - - /* get the frequency order */ - if (freq != CPUFREQ_ENTRY_INVALID && descend == -1) - descend = freq > pos->frequency; - - freq = pos->frequency; - max_level++; - } - - /* No valid cpu frequency entry */ - if (max_level == 0) - return -EINVAL; + unsigned long level; - /* max_level is an index, not a counter */ - max_level--; + for (level = 0; level <= cpufreq_dev->max_level; level++) { + if (freq == cpufreq_dev->freq_table[level]) + return level; - /* get max level */ - if (property == GET_MAXL) { - *output = (unsigned int)max_level; - return 0; + if (freq > cpufreq_dev->freq_table[level]) + break; } - if (property == GET_FREQ) - level = descend ? input : (max_level - input); - - i = 0; - cpufreq_for_each_valid_entry(pos, table) { - /* ignore duplicate entry */ - if (freq == pos->frequency) - continue; - - /* now we have a valid frequency entry */ - freq = pos->frequency; - - if (property == GET_LEVEL && (unsigned int)input == freq) { - /* get level by frequency */ - *output = descend ? i : (max_level - i); - return 0; - } - if (property == GET_FREQ && level == i) { - /* get frequency by level */ - *output = freq; - return 0; - } - i++; - } - - return -EINVAL; + return THERMAL_CSTATE_INVALID; } /** - * cpufreq_cooling_get_level - for a give cpu, return the cooling level. + * cpufreq_cooling_get_level - for a given cpu, return the cooling level. * @cpu: cpu for which the level is required * @freq: the frequency of interest * @@ -223,77 +151,21 @@ static int get_property(unsigned int cpu, unsigned long input, */ unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq) { - unsigned int val; - - if (get_property(cpu, (unsigned long)freq, &val, GET_LEVEL)) - return THERMAL_CSTATE_INVALID; - - return (unsigned long)val; -} -EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level); - -/** - * get_cpu_frequency - get the absolute value of frequency from level. - * @cpu: cpu for which frequency is fetched. - * @level: cooling level - * - * This function matches cooling level with frequency. Based on a cooling level - * of frequency, equals cooling state of cpu cooling device, it will return - * the corresponding frequency. - * e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc - * - * Return: 0 on error, the corresponding frequency otherwise. - */ -static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level) -{ - int ret = 0; - unsigned int freq; - - ret = get_property(cpu, level, &freq, GET_FREQ); - if (ret) - return 0; - - return freq; -} - -/** - * cpufreq_apply_cooling - function to apply frequency clipping. - * @cpufreq_device: cpufreq_cooling_device pointer containing frequency - * clipping data. - * @cooling_state: value of the cooling state. - * - * Function used to make sure the cpufreq layer is aware of current thermal - * limits. The limits are applied by updating the cpufreq policy. - * - * Return: 0 on success, an error code otherwise (-EINVAL in case wrong - * cooling state). - */ -static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device, - unsigned long cooling_state) -{ - unsigned int cpuid, clip_freq; - struct cpumask *mask = &cpufreq_device->allowed_cpus; - unsigned int cpu = cpumask_any(mask); - - - /* Check if the old cooling action is same as new cooling action */ - if (cpufreq_device->cpufreq_state == cooling_state) - return 0; - - clip_freq = get_cpu_frequency(cpu, cooling_state); - if (!clip_freq) - return -EINVAL; - - cpufreq_device->cpufreq_state = cooling_state; - cpufreq_device->cpufreq_val = clip_freq; + struct cpufreq_cooling_device *cpufreq_dev; - for_each_cpu(cpuid, mask) { - if (is_cpufreq_valid(cpuid)) - cpufreq_update_policy(cpuid); + mutex_lock(&cooling_cpufreq_lock); + list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) { + if (cpumask_test_cpu(cpu, &cpufreq_dev->allowed_cpus)) { + mutex_unlock(&cooling_cpufreq_lock); + return get_level(cpufreq_dev, freq); + } } + mutex_unlock(&cooling_cpufreq_lock); - return 0; + pr_err("%s: cpu:%d not part of any cooling device\n", __func__, cpu); + return THERMAL_CSTATE_INVALID; } +EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level); /** * cpufreq_thermal_notifier - notifier callback for cpufreq policy change. @@ -323,11 +195,6 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, &cpufreq_dev->allowed_cpus)) continue; - if (!cpufreq_dev->cpufreq_val) - cpufreq_dev->cpufreq_val = get_cpu_frequency( - cpumask_any(&cpufreq_dev->allowed_cpus), - cpufreq_dev->cpufreq_state); - max_freq = cpufreq_dev->cpufreq_val; if (policy->max != max_freq) @@ -354,19 +221,9 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state) { struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; - struct cpumask *mask = &cpufreq_device->allowed_cpus; - unsigned int cpu; - unsigned int count = 0; - int ret; - - cpu = cpumask_any(mask); - - ret = get_property(cpu, 0, &count, GET_MAXL); - if (count > 0) - *state = count; - - return ret; + *state = cpufreq_device->max_level; + return 0; } /** @@ -403,8 +260,24 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) { struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; + unsigned int cpu = cpumask_any(&cpufreq_device->allowed_cpus); + unsigned int clip_freq; + + /* Request state should be less than max_level */ + if (WARN_ON(state > cpufreq_device->max_level)) + return -EINVAL; + + /* Check if the old cooling action is same as new cooling action */ + if (cpufreq_device->cpufreq_state == state) + return 0; - return cpufreq_apply_cooling(cpufreq_device, state); + clip_freq = cpufreq_device->freq_table[state]; + cpufreq_device->cpufreq_state = state; + cpufreq_device->cpufreq_val = clip_freq; + + cpufreq_update_policy(cpu); + + return 0; } /* Bind cpufreq callbacks to thermal cooling device ops */ @@ -419,10 +292,25 @@ static struct notifier_block thermal_cpufreq_notifier_block = { .notifier_call = cpufreq_thermal_notifier, }; +static unsigned int find_next_max(struct cpufreq_frequency_table *table, + unsigned int prev_max) +{ + struct cpufreq_frequency_table *pos; + unsigned int max = 0; + + cpufreq_for_each_valid_entry(pos, table) { + if (pos->frequency > max && pos->frequency < prev_max) + max = pos->frequency; + } + + return max; +} + /** * __cpufreq_cooling_register - helper function to create cpufreq cooling device * @np: a valid struct device_node to the cooling device device tree node * @clip_cpus: cpumask of cpus where the frequency constraints will happen. + * Normally this should be same as cpufreq policy->related_cpus. * * This interface function registers the cpufreq cooling device with the name * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq @@ -437,37 +325,42 @@ __cpufreq_cooling_register(struct device_node *np, const struct cpumask *clip_cpus) { struct thermal_cooling_device *cool_dev; - struct cpufreq_cooling_device *cpufreq_dev = NULL; - unsigned int min = 0, max = 0; + struct cpufreq_cooling_device *cpufreq_dev; char dev_name[THERMAL_NAME_LENGTH]; - int ret = 0, i; - struct cpufreq_policy policy; + struct cpufreq_frequency_table *pos, *table; + unsigned int freq, i; + int ret; - /* Verify that all the clip cpus have same freq_min, freq_max limit */ - for_each_cpu(i, clip_cpus) { - /* continue if cpufreq policy not found and not return error */ - if (!cpufreq_get_policy(&policy, i)) - continue; - if (min == 0 && max == 0) { - min = policy.cpuinfo.min_freq; - max = policy.cpuinfo.max_freq; - } else { - if (min != policy.cpuinfo.min_freq || - max != policy.cpuinfo.max_freq) - return ERR_PTR(-EINVAL); - } + table = cpufreq_frequency_get_table(cpumask_first(clip_cpus)); + if (!table) { + pr_debug("%s: CPUFreq table not found\n", __func__); + return ERR_PTR(-EPROBE_DEFER); } - cpufreq_dev = kzalloc(sizeof(struct cpufreq_cooling_device), - GFP_KERNEL); + + cpufreq_dev = kzalloc(sizeof(*cpufreq_dev), GFP_KERNEL); if (!cpufreq_dev) return ERR_PTR(-ENOMEM); + /* Find max levels */ + cpufreq_for_each_valid_entry(pos, table) + cpufreq_dev->max_level++; + + cpufreq_dev->freq_table = kmalloc(sizeof(*cpufreq_dev->freq_table) * + cpufreq_dev->max_level, GFP_KERNEL); + if (!cpufreq_dev->freq_table) { + cool_dev = ERR_PTR(-ENOMEM); + goto free_cdev; + } + + /* max_level is an index, not a counter */ + cpufreq_dev->max_level--; + cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus); ret = get_idr(&cpufreq_idr, &cpufreq_dev->id); if (ret) { - kfree(cpufreq_dev); - return ERR_PTR(-EINVAL); + cool_dev = ERR_PTR(ret); + goto free_table; } snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d", @@ -475,25 +368,44 @@ __cpufreq_cooling_register(struct device_node *np, cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev, &cpufreq_cooling_ops); - if (IS_ERR(cool_dev)) { - release_idr(&cpufreq_idr, cpufreq_dev->id); - kfree(cpufreq_dev); - return cool_dev; + if (IS_ERR(cool_dev)) + goto remove_idr; + + /* Fill freq-table in descending order of frequencies */ + for (i = 0, freq = -1; i <= cpufreq_dev->max_level; i++) { + freq = find_next_max(table, freq); + cpufreq_dev->freq_table[i] = freq; + + /* Warn for duplicate entries */ + if (!freq) + pr_warn("%s: table has duplicate entries\n", __func__); + else + pr_debug("%s: freq:%u KHz\n", __func__, freq); } + + cpufreq_dev->cpufreq_val = cpufreq_dev->freq_table[0]; cpufreq_dev->cool_dev = cool_dev; - cpufreq_dev->cpufreq_state = 0; + mutex_lock(&cooling_cpufreq_lock); /* Register the notifier for first cpufreq cooling device */ - if (cpufreq_dev_count == 0) + if (list_empty(&cpufreq_dev_list)) cpufreq_register_notifier(&thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER); - cpufreq_dev_count++; list_add(&cpufreq_dev->node, &cpufreq_dev_list); mutex_unlock(&cooling_cpufreq_lock); return cool_dev; + +remove_idr: + release_idr(&cpufreq_idr, cpufreq_dev->id); +free_table: + kfree(cpufreq_dev->freq_table); +free_cdev: + kfree(cpufreq_dev); + + return cool_dev; } /** @@ -554,16 +466,16 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) cpufreq_dev = cdev->devdata; mutex_lock(&cooling_cpufreq_lock); list_del(&cpufreq_dev->node); - cpufreq_dev_count--; /* Unregister the notifier for the last cpufreq cooling device */ - if (cpufreq_dev_count == 0) + if (list_empty(&cpufreq_dev_list)) cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER); mutex_unlock(&cooling_cpufreq_lock); thermal_cooling_device_unregister(cpufreq_dev->cool_dev); release_idr(&cpufreq_idr, cpufreq_dev->id); + kfree(cpufreq_dev->freq_table); kfree(cpufreq_dev); } EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister); diff --git a/drivers/thermal/db8500_cpufreq_cooling.c b/drivers/thermal/db8500_cpufreq_cooling.c index 000d53e934a0..607b62c7e611 100644 --- a/drivers/thermal/db8500_cpufreq_cooling.c +++ b/drivers/thermal/db8500_cpufreq_cooling.c @@ -18,7 +18,6 @@ */ #include <linux/cpu_cooling.h> -#include <linux/cpufreq.h> #include <linux/err.h> #include <linux/module.h> #include <linux/of.h> @@ -28,18 +27,17 @@ static int db8500_cpufreq_cooling_probe(struct platform_device *pdev) { struct thermal_cooling_device *cdev; - struct cpumask mask_val; - - /* make sure cpufreq driver has been initialized */ - if (!cpufreq_frequency_get_table(0)) - return -EPROBE_DEFER; - - cpumask_set_cpu(0, &mask_val); - cdev = cpufreq_cooling_register(&mask_val); + cdev = cpufreq_cooling_register(cpu_present_mask); if (IS_ERR(cdev)) { - dev_err(&pdev->dev, "Failed to register cooling device\n"); - return PTR_ERR(cdev); + int ret = PTR_ERR(cdev); + + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "Failed to register cooling device %d\n", + ret); + + return ret; } platform_set_drvdata(pdev, cdev); diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index 88b32f942dcf..c1188ac053c9 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c @@ -9,7 +9,6 @@ #include <linux/clk.h> #include <linux/cpu_cooling.h> -#include <linux/cpufreq.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/init.h> @@ -454,15 +453,10 @@ static int imx_thermal_probe(struct platform_device *pdev) const struct of_device_id *of_id = of_match_device(of_imx_thermal_match, &pdev->dev); struct imx_thermal_data *data; - struct cpumask clip_cpus; struct regmap *map; int measure_freq; int ret; - if (!cpufreq_get_current_driver()) { - dev_dbg(&pdev->dev, "no cpufreq driver!"); - return -EPROBE_DEFER; - } data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -516,12 +510,13 @@ static int imx_thermal_probe(struct platform_device *pdev) regmap_write(map, MISC0 + REG_SET, MISC0_REFTOP_SELBIASOFF); regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN); - cpumask_set_cpu(0, &clip_cpus); - data->cdev = cpufreq_cooling_register(&clip_cpus); + data->cdev = cpufreq_cooling_register(cpu_present_mask); if (IS_ERR(data->cdev)) { ret = PTR_ERR(data->cdev); - dev_err(&pdev->dev, - "failed to register cpufreq cooling device: %d\n", ret); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "failed to register cpufreq cooling device: %d\n", + ret); return ret; } diff --git a/drivers/thermal/int340x_thermal/Makefile b/drivers/thermal/int340x_thermal/Makefile index ffe40bffaf1a..d4413698a85f 100644 --- a/drivers/thermal/int340x_thermal/Makefile +++ b/drivers/thermal/int340x_thermal/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o +obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o obj-$(CONFIG_ACPI_THERMAL_REL) += acpi_thermal_rel.o diff --git a/drivers/thermal/int340x_thermal/acpi_thermal_rel.c b/drivers/thermal/int340x_thermal/acpi_thermal_rel.c index e4e61b3fb11e..231cabc16e16 100644 --- a/drivers/thermal/int340x_thermal/acpi_thermal_rel.c +++ b/drivers/thermal/int340x_thermal/acpi_thermal_rel.c @@ -82,7 +82,7 @@ int acpi_parse_trt(acpi_handle handle, int *trt_count, struct trt **trtp, struct acpi_buffer trt_format = { sizeof("RRNNNNNN"), "RRNNNNNN" }; if (!acpi_has_method(handle, "_TRT")) - return 0; + return -ENODEV; status = acpi_evaluate_object(handle, "_TRT", NULL, &buffer); if (ACPI_FAILURE(status)) @@ -167,7 +167,7 @@ int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp, sizeof("RRNNNNNNNNNNN"), "RRNNNNNNNNNNN" }; if (!acpi_has_method(handle, "_ART")) - return 0; + return -ENODEV; status = acpi_evaluate_object(handle, "_ART", NULL, &buffer); if (ACPI_FAILURE(status)) @@ -321,8 +321,8 @@ static long acpi_thermal_rel_ioctl(struct file *f, unsigned int cmd, unsigned long length = 0; int count = 0; char __user *arg = (void __user *)__arg; - struct trt *trts; - struct art *arts; + struct trt *trts = NULL; + struct art *arts = NULL; switch (cmd) { case ACPI_THERMAL_GET_TRT_COUNT: diff --git a/drivers/thermal/int340x_thermal/int3400_thermal.c b/drivers/thermal/int340x_thermal/int3400_thermal.c index dcb306ea14a4..65a98a97df07 100644 --- a/drivers/thermal/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/int340x_thermal/int3400_thermal.c @@ -335,7 +335,6 @@ static struct platform_driver int3400_thermal_driver = { .remove = int3400_thermal_remove, .driver = { .name = "int3400 thermal", - .owner = THIS_MODULE, .acpi_match_table = ACPI_PTR(int3400_thermal_match), }, }; diff --git a/drivers/thermal/int340x_thermal/int3402_thermal.c b/drivers/thermal/int340x_thermal/int3402_thermal.c index a5d08c14ba24..c5cbc3af3a05 100644 --- a/drivers/thermal/int340x_thermal/int3402_thermal.c +++ b/drivers/thermal/int340x_thermal/int3402_thermal.c @@ -231,7 +231,6 @@ static struct platform_driver int3402_thermal_driver = { .remove = int3402_thermal_remove, .driver = { .name = "int3402 thermal", - .owner = THIS_MODULE, .acpi_match_table = int3402_thermal_match, }, }; diff --git a/drivers/thermal/int340x_thermal/int3403_thermal.c b/drivers/thermal/int340x_thermal/int3403_thermal.c index 1bfa6a69e77a..0faf500d8a77 100644 --- a/drivers/thermal/int340x_thermal/int3403_thermal.c +++ b/drivers/thermal/int340x_thermal/int3403_thermal.c @@ -301,6 +301,8 @@ static int int3403_sensor_remove(struct int3403_priv *priv) { struct int3403_sensor *obj = priv->priv; + acpi_remove_notify_handler(priv->adev->handle, + ACPI_DEVICE_NOTIFY, int3403_notify); thermal_zone_device_unregister(obj->tzone); return 0; } @@ -369,6 +371,7 @@ static int int3403_cdev_add(struct int3403_priv *priv) p = buf.pointer; if (!p || (p->type != ACPI_TYPE_PACKAGE)) { printk(KERN_WARNING "Invalid PPSS data\n"); + kfree(buf.pointer); return -EFAULT; } @@ -381,6 +384,7 @@ static int int3403_cdev_add(struct int3403_priv *priv) priv->priv = obj; + kfree(buf.pointer); /* TODO: add ACPI notification support */ return result; diff --git a/drivers/thermal/int340x_thermal/processor_thermal_device.c b/drivers/thermal/int340x_thermal/processor_thermal_device.c new file mode 100644 index 000000000000..31bb553aac26 --- /dev/null +++ b/drivers/thermal/int340x_thermal/processor_thermal_device.c @@ -0,0 +1,309 @@ +/* + * processor_thermal_device.c + * Copyright (c) 2014, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/platform_device.h> +#include <linux/acpi.h> + +/* Broadwell-U/HSB thermal reporting device */ +#define PCI_DEVICE_ID_PROC_BDW_THERMAL 0x1603 +#define PCI_DEVICE_ID_PROC_HSB_THERMAL 0x0A03 + +/* Braswell thermal reporting device */ +#define PCI_DEVICE_ID_PROC_BSW_THERMAL 0x22DC + +struct power_config { + u32 index; + u32 min_uw; + u32 max_uw; + u32 tmin_us; + u32 tmax_us; + u32 step_uw; +}; + +struct proc_thermal_device { + struct device *dev; + struct acpi_device *adev; + struct power_config power_limits[2]; +}; + +enum proc_thermal_emum_mode_type { + PROC_THERMAL_NONE, + PROC_THERMAL_PCI, + PROC_THERMAL_PLATFORM_DEV +}; + +/* + * We can have only one type of enumeration, PCI or Platform, + * not both. So we don't need instance specific data. + */ +static enum proc_thermal_emum_mode_type proc_thermal_emum_mode = + PROC_THERMAL_NONE; + +#define POWER_LIMIT_SHOW(index, suffix) \ +static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct pci_dev *pci_dev; \ + struct platform_device *pdev; \ + struct proc_thermal_device *proc_dev; \ +\ + if (proc_thermal_emum_mode == PROC_THERMAL_PLATFORM_DEV) { \ + pdev = to_platform_device(dev); \ + proc_dev = platform_get_drvdata(pdev); \ + } else { \ + pci_dev = to_pci_dev(dev); \ + proc_dev = pci_get_drvdata(pci_dev); \ + } \ + return sprintf(buf, "%lu\n",\ + (unsigned long)proc_dev->power_limits[index].suffix * 1000); \ +} + +POWER_LIMIT_SHOW(0, min_uw) +POWER_LIMIT_SHOW(0, max_uw) +POWER_LIMIT_SHOW(0, step_uw) +POWER_LIMIT_SHOW(0, tmin_us) +POWER_LIMIT_SHOW(0, tmax_us) + +POWER_LIMIT_SHOW(1, min_uw) +POWER_LIMIT_SHOW(1, max_uw) +POWER_LIMIT_SHOW(1, step_uw) +POWER_LIMIT_SHOW(1, tmin_us) +POWER_LIMIT_SHOW(1, tmax_us) + +static DEVICE_ATTR_RO(power_limit_0_min_uw); +static DEVICE_ATTR_RO(power_limit_0_max_uw); +static DEVICE_ATTR_RO(power_limit_0_step_uw); +static DEVICE_ATTR_RO(power_limit_0_tmin_us); +static DEVICE_ATTR_RO(power_limit_0_tmax_us); + +static DEVICE_ATTR_RO(power_limit_1_min_uw); +static DEVICE_ATTR_RO(power_limit_1_max_uw); +static DEVICE_ATTR_RO(power_limit_1_step_uw); +static DEVICE_ATTR_RO(power_limit_1_tmin_us); +static DEVICE_ATTR_RO(power_limit_1_tmax_us); + +static struct attribute *power_limit_attrs[] = { + &dev_attr_power_limit_0_min_uw.attr, + &dev_attr_power_limit_1_min_uw.attr, + &dev_attr_power_limit_0_max_uw.attr, + &dev_attr_power_limit_1_max_uw.attr, + &dev_attr_power_limit_0_step_uw.attr, + &dev_attr_power_limit_1_step_uw.attr, + &dev_attr_power_limit_0_tmin_us.attr, + &dev_attr_power_limit_1_tmin_us.attr, + &dev_attr_power_limit_0_tmax_us.attr, + &dev_attr_power_limit_1_tmax_us.attr, + NULL +}; + +static struct attribute_group power_limit_attribute_group = { + .attrs = power_limit_attrs, + .name = "power_limits" +}; + +static int proc_thermal_add(struct device *dev, + struct proc_thermal_device **priv) +{ + struct proc_thermal_device *proc_priv; + struct acpi_device *adev; + acpi_status status; + struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *elements, *ppcc; + union acpi_object *p; + int i; + int ret; + + adev = ACPI_COMPANION(dev); + + status = acpi_evaluate_object(adev->handle, "PPCC", NULL, &buf); + if (ACPI_FAILURE(status)) + return -ENODEV; + + p = buf.pointer; + if (!p || (p->type != ACPI_TYPE_PACKAGE)) { + dev_err(dev, "Invalid PPCC data\n"); + ret = -EFAULT; + goto free_buffer; + } + if (!p->package.count) { + dev_err(dev, "Invalid PPCC package size\n"); + ret = -EFAULT; + goto free_buffer; + } + + proc_priv = devm_kzalloc(dev, sizeof(*proc_priv), GFP_KERNEL); + if (!proc_priv) { + ret = -ENOMEM; + goto free_buffer; + } + + proc_priv->dev = dev; + proc_priv->adev = adev; + + for (i = 0; i < min((int)p->package.count - 1, 2); ++i) { + elements = &(p->package.elements[i+1]); + if (elements->type != ACPI_TYPE_PACKAGE || + elements->package.count != 6) { + ret = -EFAULT; + goto free_buffer; + } + ppcc = elements->package.elements; + proc_priv->power_limits[i].index = ppcc[0].integer.value; + proc_priv->power_limits[i].min_uw = ppcc[1].integer.value; + proc_priv->power_limits[i].max_uw = ppcc[2].integer.value; + proc_priv->power_limits[i].tmin_us = ppcc[3].integer.value; + proc_priv->power_limits[i].tmax_us = ppcc[4].integer.value; + proc_priv->power_limits[i].step_uw = ppcc[5].integer.value; + } + + *priv = proc_priv; + + ret = sysfs_create_group(&dev->kobj, + &power_limit_attribute_group); + +free_buffer: + kfree(buf.pointer); + + return ret; +} + +void proc_thermal_remove(struct proc_thermal_device *proc_priv) +{ + sysfs_remove_group(&proc_priv->dev->kobj, + &power_limit_attribute_group); +} + +static int int3401_add(struct platform_device *pdev) +{ + struct proc_thermal_device *proc_priv; + int ret; + + if (proc_thermal_emum_mode == PROC_THERMAL_PCI) { + dev_err(&pdev->dev, "error: enumerated as PCI dev\n"); + return -ENODEV; + } + + ret = proc_thermal_add(&pdev->dev, &proc_priv); + if (ret) + return ret; + + platform_set_drvdata(pdev, proc_priv); + proc_thermal_emum_mode = PROC_THERMAL_PLATFORM_DEV; + + return 0; +} + +static int int3401_remove(struct platform_device *pdev) +{ + proc_thermal_remove(platform_get_drvdata(pdev)); + + return 0; +} + +static int proc_thermal_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *unused) +{ + struct proc_thermal_device *proc_priv; + int ret; + + if (proc_thermal_emum_mode == PROC_THERMAL_PLATFORM_DEV) { + dev_err(&pdev->dev, "error: enumerated as platform dev\n"); + return -ENODEV; + } + + ret = pci_enable_device(pdev); + if (ret < 0) { + dev_err(&pdev->dev, "error: could not enable device\n"); + return ret; + } + + ret = proc_thermal_add(&pdev->dev, &proc_priv); + if (ret) { + pci_disable_device(pdev); + return ret; + } + + pci_set_drvdata(pdev, proc_priv); + proc_thermal_emum_mode = PROC_THERMAL_PCI; + + return 0; +} + +static void proc_thermal_pci_remove(struct pci_dev *pdev) +{ + proc_thermal_remove(pci_get_drvdata(pdev)); + pci_disable_device(pdev); +} + +static const struct pci_device_id proc_thermal_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BDW_THERMAL)}, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_HSB_THERMAL)}, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BSW_THERMAL)}, + { 0, }, +}; + +MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids); + +static struct pci_driver proc_thermal_pci_driver = { + .name = "proc_thermal", + .probe = proc_thermal_pci_probe, + .remove = proc_thermal_pci_remove, + .id_table = proc_thermal_pci_ids, +}; + +static const struct acpi_device_id int3401_device_ids[] = { + {"INT3401", 0}, + {"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, int3401_device_ids); + +static struct platform_driver int3401_driver = { + .probe = int3401_add, + .remove = int3401_remove, + .driver = { + .name = "int3401 thermal", + .acpi_match_table = int3401_device_ids, + }, +}; + +static int __init proc_thermal_init(void) +{ + int ret; + + ret = platform_driver_register(&int3401_driver); + if (ret) + return ret; + + ret = pci_register_driver(&proc_thermal_pci_driver); + + return ret; +} + +static void __exit proc_thermal_exit(void) +{ + platform_driver_unregister(&int3401_driver); + pci_unregister_driver(&proc_thermal_pci_driver); +} + +module_init(proc_thermal_init); +module_exit(proc_thermal_exit); + +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); +MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/thermal/intel_powerclamp.c b/drivers/thermal/intel_powerclamp.c index e98b4249187c..6ceebd659dd4 100644 --- a/drivers/thermal/intel_powerclamp.c +++ b/drivers/thermal/intel_powerclamp.c @@ -688,6 +688,7 @@ static const struct x86_cpu_id intel_powerclamp_ids[] = { { X86_VENDOR_INTEL, 6, 0x45}, { X86_VENDOR_INTEL, 6, 0x46}, { X86_VENDOR_INTEL, 6, 0x4c}, + { X86_VENDOR_INTEL, 6, 0x56}, {} }; MODULE_DEVICE_TABLE(x86cpu, intel_powerclamp_ids); diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index 1bcddfc60e91..9c6ce548e363 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -677,7 +677,6 @@ static SIMPLE_DEV_PM_OPS(rockchip_thermal_pm_ops, static struct platform_driver rockchip_thermal_driver = { .driver = { .name = "rockchip-thermal", - .owner = THIS_MODULE, .pm = &rockchip_thermal_pm_ops, .of_match_table = of_rockchip_thermal_match, }, diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig index f760389a204c..c43306ecc0ab 100644 --- a/drivers/thermal/samsung/Kconfig +++ b/drivers/thermal/samsung/Kconfig @@ -1,6 +1,6 @@ config EXYNOS_THERMAL tristate "Exynos thermal management unit driver" - depends on ARCH_HAS_BANDGAP && OF + depends on OF help If you say yes here you get support for the TMU (Thermal Management Unit) driver for SAMSUNG EXYNOS series of SoCs. This driver initialises diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c index b6be572704a4..6dc3815cc73f 100644 --- a/drivers/thermal/samsung/exynos_thermal_common.c +++ b/drivers/thermal/samsung/exynos_thermal_common.c @@ -347,7 +347,6 @@ void exynos_report_trigger(struct thermal_sensor_conf *conf) int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) { int ret; - struct cpumask mask_val; struct exynos_thermal_zone *th_zone; if (!sensor_conf || !sensor_conf->read_temperature) { @@ -367,13 +366,14 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) * sensor */ if (sensor_conf->cooling_data.freq_clip_count > 0) { - cpumask_set_cpu(0, &mask_val); th_zone->cool_dev[th_zone->cool_dev_size] = - cpufreq_cooling_register(&mask_val); + cpufreq_cooling_register(cpu_present_mask); if (IS_ERR(th_zone->cool_dev[th_zone->cool_dev_size])) { - dev_err(sensor_conf->dev, - "Failed to register cpufreq cooling device\n"); - ret = -EINVAL; + ret = PTR_ERR(th_zone->cool_dev[th_zone->cool_dev_size]); + if (ret != -EPROBE_DEFER) + dev_err(sensor_conf->dev, + "Failed to register cpufreq cooling device: %d\n", + ret); goto err_unregister; } th_zone->cool_dev_size++; diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index d44d91d681d4..d2f1e62a4232 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -927,7 +927,10 @@ static int exynos_tmu_probe(struct platform_device *pdev) /* Register the sensor with thermal management interface */ ret = exynos_register_thermal(sensor_conf); if (ret) { - dev_err(&pdev->dev, "Failed to register thermal interface\n"); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "Failed to register thermal interface: %d\n", + ret); goto err_clk; } data->reg_conf = sensor_conf; diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 84fdf0792e27..87e0b0782023 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -930,7 +930,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, struct thermal_zone_device *pos1; struct thermal_cooling_device *pos2; unsigned long max_state; - int result; + int result, ret; if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE)) return -EINVAL; @@ -947,7 +947,9 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, if (tz != pos1 || cdev != pos2) return -EINVAL; - cdev->ops->get_max_state(cdev, &max_state); + ret = cdev->ops->get_max_state(cdev, &max_state); + if (ret) + return ret; /* lower default 0, upper default max_state */ lower = lower == THERMAL_NO_LIMIT ? 0 : lower; diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c index 5fd03865e396..3fb054a10f6a 100644 --- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c +++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c @@ -28,7 +28,6 @@ #include <linux/kernel.h> #include <linux/workqueue.h> #include <linux/thermal.h> -#include <linux/cpufreq.h> #include <linux/cpumask.h> #include <linux/cpu_cooling.h> #include <linux/of.h> @@ -407,17 +406,17 @@ int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id) if (!data) return -EINVAL; - if (!cpufreq_get_current_driver()) { - dev_dbg(bgp->dev, "no cpufreq driver yet\n"); - return -EPROBE_DEFER; - } - /* Register cooling device */ data->cool_dev = cpufreq_cooling_register(cpu_present_mask); if (IS_ERR(data->cool_dev)) { - dev_err(bgp->dev, - "Failed to register cpufreq cooling device\n"); - return PTR_ERR(data->cool_dev); + int ret = PTR_ERR(data->cool_dev); + + if (ret != -EPROBE_DEFER) + dev_err(bgp->dev, + "Failed to register cpu cooling device %d\n", + ret); + + return ret; } ti_bandgap_set_sensor_data(bgp, id, data); diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index ed71b5347a76..cb807d0ea498 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -713,9 +713,13 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp) r = -EFAULT; break; } - if ((a.avail_user_addr & (sizeof *vq->avail->ring - 1)) || - (a.used_user_addr & (sizeof *vq->used->ring - 1)) || - (a.log_guest_addr & (sizeof *vq->used->ring - 1))) { + + /* Make sure it's safe to cast pointers to vring types. */ + BUILD_BUG_ON(__alignof__ *vq->avail > VRING_AVAIL_ALIGN_SIZE); + BUILD_BUG_ON(__alignof__ *vq->used > VRING_USED_ALIGN_SIZE); + if ((a.avail_user_addr & (VRING_AVAIL_ALIGN_SIZE - 1)) || + (a.used_user_addr & (VRING_USED_ALIGN_SIZE - 1)) || + (a.log_guest_addr & (sizeof(u64) - 1))) { r = -EINVAL; break; } diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c index 900aa4ecd617..d6cab1fd9a47 100644 --- a/drivers/video/fbdev/core/fb_defio.c +++ b/drivers/video/fbdev/core/fb_defio.c @@ -83,9 +83,10 @@ int fb_deferred_io_fsync(struct file *file, loff_t start, loff_t end, int datasy cancel_delayed_work_sync(&info->deferred_work); /* Run it immediately */ - err = schedule_delayed_work(&info->deferred_work, 0); + schedule_delayed_work(&info->deferred_work, 0); mutex_unlock(&inode->i_mutex); - return err; + + return 0; } EXPORT_SYMBOL_GPL(fb_deferred_io_fsync); diff --git a/drivers/video/fbdev/omap2/dss/hdmi_pll.c b/drivers/video/fbdev/omap2/dss/hdmi_pll.c index 87accdb59c81..ac83ef5cfd7d 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi_pll.c +++ b/drivers/video/fbdev/omap2/dss/hdmi_pll.c @@ -132,7 +132,6 @@ static const struct dss_pll_hw dss_omap4_hdmi_pll_hw = { .mX_max = 127, .fint_min = 500000, .fint_max = 2500000, - .clkdco_max = 1800000000, .clkdco_min = 500000000, .clkdco_low = 1000000000, @@ -156,7 +155,6 @@ static const struct dss_pll_hw dss_omap5_hdmi_pll_hw = { .mX_max = 127, .fint_min = 620000, .fint_max = 2500000, - .clkdco_max = 1800000000, .clkdco_min = 750000000, .clkdco_low = 1500000000, diff --git a/drivers/video/fbdev/omap2/dss/pll.c b/drivers/video/fbdev/omap2/dss/pll.c index 50bc62c5d367..335ffac224b9 100644 --- a/drivers/video/fbdev/omap2/dss/pll.c +++ b/drivers/video/fbdev/omap2/dss/pll.c @@ -97,7 +97,8 @@ int dss_pll_enable(struct dss_pll *pll) return 0; err_enable: - regulator_disable(pll->regulator); + if (pll->regulator) + regulator_disable(pll->regulator); err_reg: clk_disable_unprepare(pll->clkin); return r; diff --git a/drivers/video/fbdev/omap2/dss/sdi.c b/drivers/video/fbdev/omap2/dss/sdi.c index d51a983075bc..5c2ccab5a958 100644 --- a/drivers/video/fbdev/omap2/dss/sdi.c +++ b/drivers/video/fbdev/omap2/dss/sdi.c @@ -342,6 +342,8 @@ static void sdi_init_output(struct platform_device *pdev) out->output_type = OMAP_DISPLAY_TYPE_SDI; out->name = "sdi.0"; out->dispc_channel = OMAP_DSS_CHANNEL_LCD; + /* We have SDI only on OMAP3, where it's on port 1 */ + out->port_num = 1; out->ops.sdi = &sdi_ops; out->owner = THIS_MODULE; diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c index 940cd196eef5..10fbfd8ab963 100644 --- a/drivers/video/logo/logo.c +++ b/drivers/video/logo/logo.c @@ -21,6 +21,21 @@ static bool nologo; module_param(nologo, bool, 0); MODULE_PARM_DESC(nologo, "Disables startup logo"); +/* + * Logos are located in the initdata, and will be freed in kernel_init. + * Use late_init to mark the logos as freed to prevent any further use. + */ + +static bool logos_freed; + +static int __init fb_logo_late_init(void) +{ + logos_freed = true; + return 0; +} + +late_initcall(fb_logo_late_init); + /* logo's are marked __initdata. Use __init_refok to tell * modpost that it is intended that this function uses data * marked __initdata. @@ -29,7 +44,7 @@ const struct linux_logo * __init_refok fb_find_logo(int depth) { const struct linux_logo *logo = NULL; - if (nologo) + if (nologo || logos_freed) return NULL; if (depth >= 1) { |