diff options
Diffstat (limited to 'drivers')
235 files changed, 4768 insertions, 2253 deletions
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index d97b8dce166..18b3f1468b7 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -70,6 +70,7 @@ acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, acpi_status acpi_enable(void) { acpi_status status; + int retry; ACPI_FUNCTION_TRACE(acpi_enable); @@ -98,16 +99,18 @@ acpi_status acpi_enable(void) /* Sanity check that transition succeeded */ - if (acpi_hw_get_mode() != ACPI_SYS_MODE_ACPI) { - ACPI_ERROR((AE_INFO, - "Hardware did not enter ACPI mode")); - return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE); + for (retry = 0; retry < 30000; ++retry) { + if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) { + if (retry != 0) + ACPI_WARNING((AE_INFO, + "Platform took > %d00 usec to enter ACPI mode", retry)); + return_ACPI_STATUS(AE_OK); + } + acpi_os_stall(100); /* 100 usec */ } - ACPI_DEBUG_PRINT((ACPI_DB_INIT, - "Transition to ACPI mode successful\n")); - - return_ACPI_STATUS(AE_OK); + ACPI_ERROR((AE_INFO, "Hardware did not enter ACPI mode")); + return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE); } ACPI_EXPORT_SYMBOL(acpi_enable) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 3026e3fa83e..dc58402b0a1 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -868,9 +868,15 @@ static void acpi_battery_remove_fs(struct acpi_device *device) static void acpi_battery_notify(struct acpi_device *device, u32 event) { struct acpi_battery *battery = acpi_driver_data(device); +#ifdef CONFIG_ACPI_SYSFS_POWER + struct device *old; +#endif if (!battery) return; +#ifdef CONFIG_ACPI_SYSFS_POWER + old = battery->bat.dev; +#endif acpi_battery_update(battery); acpi_bus_generate_proc_event(device, event, acpi_battery_present(battery)); @@ -879,7 +885,7 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event) acpi_battery_present(battery)); #ifdef CONFIG_ACPI_SYSFS_POWER /* acpi_battery_update could remove power_supply object */ - if (battery->bat.dev) + if (old && battery->bat.dev) power_supply_changed(&battery->bat); #endif } diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 01381be05e9..2bb28b9d91c 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -214,7 +214,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { .ident = "Sony VGN-SR290J", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "Sony VGN-SR290J"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR290J"), }, }, { diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 51284351418..e9699aaed10 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -223,7 +223,7 @@ static bool processor_physically_present(acpi_handle handle) type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0; cpuid = acpi_get_cpuid(handle, type, acpi_id); - if (cpuid == -1) + if ((cpuid == -1) && (num_possible_cpus() > 1)) return false; return true; diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index b1b385692f4..e9a8026d39f 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -76,14 +76,19 @@ static unsigned int max_cstate __read_mostly = ACPI_PROCESSOR_MAX_POWER; module_param(max_cstate, uint, 0000); static unsigned int nocst __read_mostly; module_param(nocst, uint, 0000); +static int bm_check_disable __read_mostly; +module_param(bm_check_disable, uint, 0000); static unsigned int latency_factor __read_mostly = 2; module_param(latency_factor, uint, 0644); +#ifdef CONFIG_ACPI_PROCFS static u64 us_to_pm_timer_ticks(s64 t) { return div64_u64(t * PM_TIMER_FREQUENCY, 1000000); } +#endif + /* * IBM ThinkPad R40e crashes mysteriously when going into C2 or C3. * For now disable this. Probably a bug somewhere else. @@ -763,6 +768,9 @@ static int acpi_idle_bm_check(void) { u32 bm_status = 0; + if (bm_check_disable) + return 0; + acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status); if (bm_status) acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_STATUS, 1); @@ -947,7 +955,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, if (acpi_idle_suspend) return(acpi_idle_enter_c1(dev, state)); - if (acpi_idle_bm_check()) { + if (!cx->bm_sts_skip && acpi_idle_bm_check()) { if (dev->safe_state) { dev->last_state = dev->safe_state; return dev->safe_state->enter(dev, dev->safe_state); diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 5b7c52e4a00..2862c781b37 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -82,6 +82,20 @@ static int acpi_sleep_prepare(u32 acpi_state) static u32 acpi_target_sleep_state = ACPI_STATE_S0; /* + * The ACPI specification wants us to save NVS memory regions during hibernation + * and to restore them during the subsequent resume. Windows does that also for + * suspend to RAM. However, it is known that this mechanism does not work on + * all machines, so we allow the user to disable it with the help of the + * 'acpi_sleep=nonvs' kernel command line option. + */ +static bool nvs_nosave; + +void __init acpi_nvs_nosave(void) +{ + nvs_nosave = true; +} + +/* * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the * user to request that behavior by using the 'acpi_old_suspend_ordering' * kernel command line option that causes the following variable to be set. @@ -197,8 +211,7 @@ static int acpi_suspend_begin(suspend_state_t pm_state) u32 acpi_state = acpi_suspend_states[pm_state]; int error = 0; - error = suspend_nvs_alloc(); - + error = nvs_nosave ? 0 : suspend_nvs_alloc(); if (error) return error; @@ -388,20 +401,6 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { #endif /* CONFIG_SUSPEND */ #ifdef CONFIG_HIBERNATION -/* - * The ACPI specification wants us to save NVS memory regions during hibernation - * and to restore them during the subsequent resume. However, it is not certain - * if this mechanism is going to work on all machines, so we allow the user to - * disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line - * option. - */ -static bool s4_no_nvs; - -void __init acpi_s4_no_nvs(void) -{ - s4_no_nvs = true; -} - static unsigned long s4_hardware_signature; static struct acpi_table_facs *facs; static bool nosigcheck; @@ -415,7 +414,7 @@ static int acpi_hibernation_begin(void) { int error; - error = s4_no_nvs ? 0 : suspend_nvs_alloc(); + error = nvs_nosave ? 0 : suspend_nvs_alloc(); if (!error) { acpi_target_sleep_state = ACPI_STATE_S4; acpi_sleep_tts_switch(acpi_target_sleep_state); @@ -510,7 +509,7 @@ static int acpi_hibernation_begin_old(void) error = acpi_sleep_prepare(ACPI_STATE_S4); if (!error) { - if (!s4_no_nvs) + if (!nvs_nosave) error = suspend_nvs_alloc(); if (!error) acpi_target_sleep_state = ACPI_STATE_S4; diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index f60b2b6a093..d31590e7011 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -122,6 +122,31 @@ static int __init amba_init(void) postcore_initcall(amba_init); +static int amba_get_enable_pclk(struct amba_device *pcdev) +{ + struct clk *pclk = clk_get(&pcdev->dev, "apb_pclk"); + int ret; + + pcdev->pclk = pclk; + + if (IS_ERR(pclk)) + return PTR_ERR(pclk); + + ret = clk_enable(pclk); + if (ret) + clk_put(pclk); + + return ret; +} + +static void amba_put_disable_pclk(struct amba_device *pcdev) +{ + struct clk *pclk = pcdev->pclk; + + clk_disable(pclk); + clk_put(pclk); +} + /* * These are the device model conversion veneers; they convert the * device model structures to our more specific structures. @@ -130,17 +155,33 @@ static int amba_probe(struct device *dev) { struct amba_device *pcdev = to_amba_device(dev); struct amba_driver *pcdrv = to_amba_driver(dev->driver); - struct amba_id *id; + struct amba_id *id = amba_lookup(pcdrv->id_table, pcdev); + int ret; - id = amba_lookup(pcdrv->id_table, pcdev); + do { + ret = amba_get_enable_pclk(pcdev); + if (ret) + break; + + ret = pcdrv->probe(pcdev, id); + if (ret == 0) + break; - return pcdrv->probe(pcdev, id); + amba_put_disable_pclk(pcdev); + } while (0); + + return ret; } static int amba_remove(struct device *dev) { + struct amba_device *pcdev = to_amba_device(dev); struct amba_driver *drv = to_amba_driver(dev->driver); - return drv->remove(to_amba_device(dev)); + int ret = drv->remove(pcdev); + + amba_put_disable_pclk(pcdev); + + return ret; } static void amba_shutdown(struct device *dev) @@ -203,7 +244,6 @@ static void amba_device_release(struct device *dev) */ int amba_device_register(struct amba_device *dev, struct resource *parent) { - u32 pid, cid; u32 size; void __iomem *tmp; int i, ret; @@ -241,25 +281,35 @@ int amba_device_register(struct amba_device *dev, struct resource *parent) goto err_release; } - /* - * Read pid and cid based on size of resource - * they are located at end of region - */ - for (pid = 0, i = 0; i < 4; i++) - pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) << (i * 8); - for (cid = 0, i = 0; i < 4; i++) - cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) << (i * 8); + ret = amba_get_enable_pclk(dev); + if (ret == 0) { + u32 pid, cid; - iounmap(tmp); + /* + * Read pid and cid based on size of resource + * they are located at end of region + */ + for (pid = 0, i = 0; i < 4; i++) + pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) << + (i * 8); + for (cid = 0, i = 0; i < 4; i++) + cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) << + (i * 8); - if (cid == 0xb105f00d) - dev->periphid = pid; + amba_put_disable_pclk(dev); - if (!dev->periphid) { - ret = -ENODEV; - goto err_release; + if (cid == 0xb105f00d) + dev->periphid = pid; + + if (!dev->periphid) + ret = -ENODEV; } + iounmap(tmp); + + if (ret) + goto err_release; + ret = device_add(&dev->dev); if (ret) goto err_release; diff --git a/drivers/base/core.c b/drivers/base/core.c index 9630fbdf4e6..9b9d3bd54e3 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -673,7 +673,7 @@ static struct kobject *get_device_parent(struct device *dev, */ if (parent == NULL) parent_kobj = virtual_device_parent(dev); - else if (parent->class) + else if (parent->class && !dev->class->ns_type) return &parent->kobj; else parent_kobj = &parent->kobj; diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 6f907ebed2d..6d34f405a2f 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -37,7 +37,7 @@ #include <linux/wait.h> #include <linux/skbuff.h> -#include <asm/io.h> +#include <linux/io.h> #include <pcmcia/cs_types.h> #include <pcmcia/cs.h> diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 40aec0fb859..42d69d4de05 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -244,7 +244,7 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data, if (rel) { hdr[0] |= 0x80 + bcsp->msgq_txseq; BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq); - bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07; + bcsp->msgq_txseq = (bcsp->msgq_txseq + 1) & 0x07; } if (bcsp->use_crc) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 9344216183a..a7547150a70 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1216,17 +1216,20 @@ static int intel_i915_get_gtt_size(void) /* G33's GTT size defined in gmch_ctrl */ pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl); - switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) { - case G33_PGETBL_SIZE_1M: + switch (gmch_ctrl & I830_GMCH_GMS_MASK) { + case I830_GMCH_GMS_STOLEN_512: + size = 512; + break; + case I830_GMCH_GMS_STOLEN_1024: size = 1024; break; - case G33_PGETBL_SIZE_2M: - size = 2048; + case I830_GMCH_GMS_STOLEN_8192: + size = 8*1024; break; default: dev_info(&agp_bridge->dev->dev, "unknown page table size 0x%x, assuming 512KB\n", - (gmch_ctrl & G33_PGETBL_SIZE_MASK)); + (gmch_ctrl & I830_GMCH_GMS_MASK)); size = 512; } } else { diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 5d64e3acb00..878ac0c2cc6 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -493,7 +493,7 @@ static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p) sysrq_key_table[i] = op_p; } -static void __handle_sysrq(int key, struct tty_struct *tty, int check_mask) +void __handle_sysrq(int key, struct tty_struct *tty, int check_mask) { struct sysrq_key_op *op_p; int orig_log_level; diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 24314a9cffe..1030f842013 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -623,7 +623,14 @@ static int tpm_tis_pnp_suspend(struct pnp_dev *dev, pm_message_t msg) static int tpm_tis_pnp_resume(struct pnp_dev *dev) { - return tpm_pm_resume(&dev->dev); + struct tpm_chip *chip = pnp_get_drvdata(dev); + int ret; + + ret = tpm_pm_resume(&dev->dev); + if (!ret) + tpm_continue_selftest(chip); + + return ret; } static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = { diff --git a/drivers/clocksource/cs5535-clockevt.c b/drivers/clocksource/cs5535-clockevt.c index d7be69f1315..b7dab32ce63 100644 --- a/drivers/clocksource/cs5535-clockevt.c +++ b/drivers/clocksource/cs5535-clockevt.c @@ -194,6 +194,6 @@ err_timer: module_init(cs5535_mfgpt_init); -MODULE_AUTHOR("Andres Salomon <dilinger@collabora.co.uk>"); +MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>"); MODULE_DESCRIPTION("CS5535/CS5536 MFGPT clock event driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 063b2184caf..938b74ea9ff 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1077,6 +1077,7 @@ err_out_unregister: err_unlock_policy: unlock_policy_rwsem_write(cpu); + free_cpumask_var(policy->related_cpus); err_free_cpumask: free_cpumask_var(policy->cpus); err_free_policy: @@ -1762,17 +1763,8 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, dprintk("governor switch\n"); /* end old governor */ - if (data->governor) { - /* - * Need to release the rwsem around governor - * stop due to lock dependency between - * cancel_delayed_work_sync and the read lock - * taken in the delayed work handler. - */ - unlock_policy_rwsem_write(data->cpu); + if (data->governor) __cpufreq_governor(data, CPUFREQ_GOV_STOP); - lock_policy_rwsem_write(data->cpu); - } /* start new governor */ data->governor = policy->governor; diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 637c105f53d..bd78acf3c36 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -1183,10 +1183,14 @@ static size_t sg_copy_end_to_buffer(struct scatterlist *sgl, unsigned int nents, /* Copy part of this segment */ ignore = skip - offset; len = miter.length - ignore; + if (boffset + len > buflen) + len = buflen - boffset; memcpy(buf + boffset, miter.addr + ignore, len); } else { - /* Copy all of this segment */ + /* Copy all of this segment (up to buflen) */ len = miter.length; + if (boffset + len > buflen) + len = buflen - boffset; memcpy(buf + boffset, miter.addr, len); } boffset += len; diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index aedef7941b2..0d2f9dbb47e 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -209,7 +209,7 @@ config EDAC_I5100 config EDAC_MPC85XX tristate "Freescale MPC83xx / MPC85xx" - depends on EDAC_MM_EDAC && FSL_SOC && (PPC_83xx || MPC85xx) + depends on EDAC_MM_EDAC && FSL_SOC && (PPC_83xx || PPC_85xx) help Support for error detection and correction on the Freescale MPC8349, MPC8560, MPC8540, MPC8548 diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index cc9357da0e3..e0187d16dd7 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1300,7 +1300,7 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno, if (devno == 0) return -ENODEV; - i7core_printk(KERN_ERR, + i7core_printk(KERN_INFO, "Device not found: dev %02x.%d PCI ID %04x:%04x\n", dev_descr->dev, dev_descr->func, PCI_VENDOR_ID_INTEL, dev_descr->dev_id); diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index 52ca09bf472..1052340e680 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -336,6 +336,7 @@ static struct of_device_id mpc85xx_pci_err_of_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, mpc85xx_pci_err_of_match); static struct of_platform_driver mpc85xx_pci_err_driver = { .probe = mpc85xx_pci_err_probe, @@ -650,6 +651,7 @@ static struct of_device_id mpc85xx_l2_err_of_match[] = { { .compatible = "fsl,p2020-l2-cache-controller", }, {}, }; +MODULE_DEVICE_TABLE(of, mpc85xx_l2_err_of_match); static struct of_platform_driver mpc85xx_l2_err_driver = { .probe = mpc85xx_l2_err_probe, @@ -1120,11 +1122,13 @@ static struct of_device_id mpc85xx_mc_err_of_match[] = { { .compatible = "fsl,mpc8555-memory-controller", }, { .compatible = "fsl,mpc8560-memory-controller", }, { .compatible = "fsl,mpc8568-memory-controller", }, + { .compatible = "fsl,mpc8569-memory-controller", }, { .compatible = "fsl,mpc8572-memory-controller", }, { .compatible = "fsl,mpc8349-memory-controller", }, { .compatible = "fsl,p2020-memory-controller", }, {}, }; +MODULE_DEVICE_TABLE(of, mpc85xx_mc_err_of_match); static struct of_platform_driver mpc85xx_mc_err_driver = { .probe = mpc85xx_mc_err_probe, diff --git a/drivers/gpio/cs5535-gpio.c b/drivers/gpio/cs5535-gpio.c index f73a1555e49..e23c06893d1 100644 --- a/drivers/gpio/cs5535-gpio.c +++ b/drivers/gpio/cs5535-gpio.c @@ -352,6 +352,6 @@ static void __exit cs5535_gpio_exit(void) module_init(cs5535_gpio_init); module_exit(cs5535_gpio_exit); -MODULE_AUTHOR("Andres Salomon <dilinger@collabora.co.uk>"); +MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>"); MODULE_DESCRIPTION("AMD CS5535/CS5536 GPIO driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 3ca36542e33..4e51fe3c1fc 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -893,10 +893,12 @@ EXPORT_SYMBOL_GPL(gpio_sysfs_set_active_low); void gpio_unexport(unsigned gpio) { struct gpio_desc *desc; - int status = -EINVAL; + int status = 0; - if (!gpio_is_valid(gpio)) + if (!gpio_is_valid(gpio)) { + status = -EINVAL; goto done; + } mutex_lock(&sysfs_lock); @@ -911,7 +913,6 @@ void gpio_unexport(unsigned gpio) clear_bit(FLAG_EXPORT, &desc->flags); put_device(dev); device_unregister(dev); - status = 0; } else status = -ENODEV; } diff --git a/drivers/gpio/pl061.c b/drivers/gpio/pl061.c index ee568c8fcbd..5005990f751 100644 --- a/drivers/gpio/pl061.c +++ b/drivers/gpio/pl061.c @@ -232,7 +232,7 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) desc->chip->unmask(irq); } -static int __init pl061_probe(struct amba_device *dev, struct amba_id *id) +static int pl061_probe(struct amba_device *dev, struct amba_id *id) { struct pl061_platform_data *pdata; struct pl061_gpio *chip; @@ -333,7 +333,7 @@ free_mem: return ret; } -static struct amba_id pl061_ids[] __initdata = { +static struct amba_id pl061_ids[] = { { .id = 0x00041061, .mask = 0x000fffff, diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index c1981861bbb..f87bf104df7 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -864,8 +864,8 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid, mode = drm_cvt_mode(dev, 1366, 768, vrefresh_rate, 0, 0, false); mode->hdisplay = 1366; - mode->vsync_start = mode->vsync_start - 1; - mode->vsync_end = mode->vsync_end - 1; + mode->hsync_start = mode->hsync_start - 1; + mode->hsync_end = mode->hsync_end - 1; return mode; } diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 1f2cc6b0962..719662034bb 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -315,8 +315,9 @@ static void drm_fb_helper_on(struct fb_info *info) struct drm_device *dev = fb_helper->dev; struct drm_crtc *crtc; struct drm_crtc_helper_funcs *crtc_funcs; + struct drm_connector *connector; struct drm_encoder *encoder; - int i; + int i, j; /* * For each CRTC in this fb, turn the crtc on then, @@ -332,7 +333,14 @@ static void drm_fb_helper_on(struct fb_info *info) crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); - + /* Walk the connectors & encoders on this fb turning them on */ + for (j = 0; j < fb_helper->connector_count; j++) { + connector = fb_helper->connector_info[j]->connector; + connector->dpms = DRM_MODE_DPMS_ON; + drm_connector_property_set_value(connector, + dev->mode_config.dpms_property, + DRM_MODE_DPMS_ON); + } /* Found a CRTC on this fb, now find encoders */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->crtc == crtc) { @@ -352,8 +360,9 @@ static void drm_fb_helper_off(struct fb_info *info, int dpms_mode) struct drm_device *dev = fb_helper->dev; struct drm_crtc *crtc; struct drm_crtc_helper_funcs *crtc_funcs; + struct drm_connector *connector; struct drm_encoder *encoder; - int i; + int i, j; /* * For each CRTC in this fb, find all associated encoders @@ -367,6 +376,14 @@ static void drm_fb_helper_off(struct fb_info *info, int dpms_mode) if (!crtc->enabled) continue; + /* Walk the connectors on this fb and mark them off */ + for (j = 0; j < fb_helper->connector_count; j++) { + connector = fb_helper->connector_info[j]->connector; + connector->dpms = dpms_mode; + drm_connector_property_set_value(connector, + dev->mode_config.dpms_property, + dpms_mode); + } /* Found a CRTC on this fb, now find encoders */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->crtc == crtc) { diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index aee83fa178f..9214119c015 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -605,6 +605,9 @@ static int i915_fbc_status(struct seq_file *m, void *unused) case FBC_NOT_TILED: seq_printf(m, "scanout buffer not tiled"); break; + case FBC_MULTIPLE_PIPES: + seq_printf(m, "multiple pipes are enabled"); + break; default: seq_printf(m, "unknown reason"); } diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index f00c5ae9556..2305a1234f1 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1300,7 +1300,7 @@ static void i915_cleanup_compression(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; drm_mm_put_block(dev_priv->compressed_fb); - if (!IS_GM45(dev)) + if (dev_priv->compressed_llb) drm_mm_put_block(dev_priv->compressed_llb); } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d147ab2f5bf..2e1744d37ad 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -215,6 +215,7 @@ enum no_fbc_reason { FBC_MODE_TOO_LARGE, /* mode too large for compression */ FBC_BAD_PLANE, /* fbc not supported on plane */ FBC_NOT_TILED, /* buffer not tiled */ + FBC_MULTIPLE_PIPES, /* more than one pipe active */ }; enum intel_pch { @@ -222,6 +223,8 @@ enum intel_pch { PCH_CPT, /* Cougarpoint PCH */ }; +#define QUIRK_PIPEA_FORCE (1<<0) + struct intel_fbdev; typedef struct drm_i915_private { @@ -337,6 +340,8 @@ typedef struct drm_i915_private { /* PCH chipset type */ enum intel_pch pch_type; + unsigned long quirks; + /* Register state */ bool modeset_on_lid; u8 saveLBB; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 074385882cc..5aa747fc25a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2241,6 +2241,7 @@ i915_gem_object_get_pages(struct drm_gem_object *obj, page = read_cache_page_gfp(mapping, i, GFP_HIGHUSER | __GFP_COLD | + __GFP_RECLAIMABLE | gfpmask); if (IS_ERR(page)) goto err_pages; @@ -3646,6 +3647,7 @@ i915_gem_wait_for_pending_flip(struct drm_device *dev, return ret; } + int i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv, @@ -3793,7 +3795,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, unsigned long long total_size = 0; int num_fences = 0; for (i = 0; i < args->buffer_count; i++) { - obj_priv = object_list[i]->driver_private; + obj_priv = to_intel_bo(object_list[i]); total_size += object_list[i]->size; num_fences += @@ -4741,6 +4743,16 @@ i915_gem_load(struct drm_device *dev) list_add(&dev_priv->mm.shrink_list, &shrink_list); spin_unlock(&shrink_list_lock); + /* On GEN3 we really need to make sure the ARB C3 LP bit is set */ + if (IS_GEN3(dev)) { + u32 tmp = I915_READ(MI_ARB_STATE); + if (!(tmp & MI_ARB_C3_LP_WRITE_ENABLE)) { + /* arb state is a masked write, so set bit + bit in mask */ + tmp = MI_ARB_C3_LP_WRITE_ENABLE | (MI_ARB_C3_LP_WRITE_ENABLE << MI_ARB_MASK_SHIFT); + I915_WRITE(MI_ARB_STATE, tmp); + } + } + /* Old X drivers will take 0-2 for front, back, depth buffers */ if (!drm_core_check_feature(dev, DRIVER_MODESET)) dev_priv->fence_reg_start = 3; @@ -4977,7 +4989,7 @@ i915_gpu_is_active(struct drm_device *dev) } static int -i915_gem_shrink(int nr_to_scan, gfp_t gfp_mask) +i915_gem_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask) { drm_i915_private_t *dev_priv, *next_dev; struct drm_i915_gem_object *obj_priv, *next_obj; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 150400f4053..cf41c672def 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -359,6 +359,70 @@ #define LM_BURST_LENGTH 0x00000700 #define LM_FIFO_WATERMARK 0x0000001F #define MI_ARB_STATE 0x020e4 /* 915+ only */ +#define MI_ARB_MASK_SHIFT 16 /* shift for enable bits */ + +/* Make render/texture TLB fetches lower priorty than associated data + * fetches. This is not turned on by default + */ +#define MI_ARB_RENDER_TLB_LOW_PRIORITY (1 << 15) + +/* Isoch request wait on GTT enable (Display A/B/C streams). + * Make isoch requests stall on the TLB update. May cause + * display underruns (test mode only) + */ +#define MI_ARB_ISOCH_WAIT_GTT (1 << 14) + +/* Block grant count for isoch requests when block count is + * set to a finite value. + */ +#define MI_ARB_BLOCK_GRANT_MASK (3 << 12) +#define MI_ARB_BLOCK_GRANT_8 (0 << 12) /* for 3 display planes */ +#define MI_ARB_BLOCK_GRANT_4 (1 << 12) /* for 2 display planes */ +#define MI_ARB_BLOCK_GRANT_2 (2 << 12) /* for 1 display plane */ +#define MI_ARB_BLOCK_GRANT_0 (3 << 12) /* don't use */ + +/* Enable render writes to complete in C2/C3/C4 power states. + * If this isn't enabled, render writes are prevented in low + * power states. That seems bad to me. + */ +#define MI_ARB_C3_LP_WRITE_ENABLE (1 << 11) + +/* This acknowledges an async flip immediately instead + * of waiting for 2TLB fetches. + */ +#define MI_ARB_ASYNC_FLIP_ACK_IMMEDIATE (1 << 10) + +/* Enables non-sequential data reads through arbiter + */ +#define MI_ARB_DUAL_DATA_PHASE_DISABLE (1 << 9) + +/* Disable FSB snooping of cacheable write cycles from binner/render + * command stream + */ +#define MI_ARB_CACHE_SNOOP_DISABLE (1 << 8) + +/* Arbiter time slice for non-isoch streams */ +#define MI_ARB_TIME_SLICE_MASK (7 << 5) +#define MI_ARB_TIME_SLICE_1 (0 << 5) +#define MI_ARB_TIME_SLICE_2 (1 << 5) +#define MI_ARB_TIME_SLICE_4 (2 << 5) +#define MI_ARB_TIME_SLICE_6 (3 << 5) +#define MI_ARB_TIME_SLICE_8 (4 << 5) +#define MI_ARB_TIME_SLICE_10 (5 << 5) +#define MI_ARB_TIME_SLICE_14 (6 << 5) +#define MI_ARB_TIME_SLICE_16 (7 << 5) + +/* Low priority grace period page size */ +#define MI_ARB_LOW_PRIORITY_GRACE_4KB (0 << 4) /* default */ +#define MI_ARB_LOW_PRIORITY_GRACE_8KB (1 << 4) + +/* Disable display A/B trickle feed */ +#define MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE (1 << 2) + +/* Set display plane priority */ +#define MI_ARB_DISPLAY_PRIORITY_A_B (0 << 0) /* display A > display B */ +#define MI_ARB_DISPLAY_PRIORITY_B_A (1 << 0) /* display B > display A */ + #define CACHE_MODE_0 0x02120 /* 915+ only */ #define CM0_MASK_SHIFT 16 #define CM0_IZ_OPT_DISABLE (1<<6) @@ -2805,6 +2869,7 @@ #define PCH_PP_STATUS 0xc7200 #define PCH_PP_CONTROL 0xc7204 +#define PANEL_UNLOCK_REGS (0xabcd << 16) #define EDP_FORCE_VDD (1 << 3) #define EDP_BLC_ENABLE (1 << 2) #define PANEL_POWER_RESET (1 << 1) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 68dcf36e279..5e21b311982 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -862,8 +862,8 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, intel_clock_t clock; int max_n; bool found; - /* approximately equals target * 0.00488 */ - int err_most = (target >> 8) + (target >> 10); + /* approximately equals target * 0.00585 */ + int err_most = (target >> 8) + (target >> 9); found = false; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { @@ -1180,8 +1180,12 @@ static void intel_update_fbc(struct drm_crtc *crtc, struct drm_framebuffer *fb = crtc->fb; struct intel_framebuffer *intel_fb; struct drm_i915_gem_object *obj_priv; + struct drm_crtc *tmp_crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int plane = intel_crtc->plane; + int crtcs_enabled = 0; + + DRM_DEBUG_KMS("\n"); if (!i915_powersave) return; @@ -1199,10 +1203,21 @@ static void intel_update_fbc(struct drm_crtc *crtc, * If FBC is already on, we just have to verify that we can * keep it that way... * Need to disable if: + * - more than one pipe is active * - changing FBC params (stride, fence, mode) * - new fb is too large to fit in compressed buffer * - going to an unsupported config (interlace, pixel multiply, etc.) */ + list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) { + if (tmp_crtc->enabled) + crtcs_enabled++; + } + DRM_DEBUG_KMS("%d pipes active\n", crtcs_enabled); + if (crtcs_enabled > 1) { + DRM_DEBUG_KMS("more than one pipe active, disabling compression\n"); + dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES; + goto out_disable; + } if (intel_fb->obj->size > dev_priv->cfb_size) { DRM_DEBUG_KMS("framebuffer too large, disabling " "compression\n"); @@ -1255,7 +1270,7 @@ out_disable: } } -static int +int intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj) { struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); @@ -2255,6 +2270,11 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) intel_wait_for_vblank(dev); } + /* Don't disable pipe A or pipe A PLLs if needed */ + if (pipeconf_reg == PIPEACONF && + (dev_priv->quirks & QUIRK_PIPEA_FORCE)) + goto skip_pipe_off; + /* Next, disable display pipes */ temp = I915_READ(pipeconf_reg); if ((temp & PIPEACONF_ENABLE) != 0) { @@ -2270,7 +2290,7 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) I915_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE); I915_READ(dpll_reg); } - + skip_pipe_off: /* Wait for the clocks to turn off. */ udelay(150); break; @@ -2356,8 +2376,6 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, if (mode->clock * 3 > 27000 * 4) return MODE_CLOCK_HIGH; } - - drm_mode_set_crtcinfo(adjusted_mode, 0); return true; } @@ -3736,6 +3754,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, if (dev_priv->lvds_dither) { if (HAS_PCH_SPLIT(dev)) { pipeconf |= PIPE_ENABLE_DITHER; + pipeconf &= ~PIPE_DITHER_TYPE_MASK; pipeconf |= PIPE_DITHER_TYPE_ST01; } else lvds |= LVDS_ENABLE_DITHER; @@ -4412,7 +4431,8 @@ static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule) DRM_DEBUG_DRIVER("upclocking LVDS\n"); /* Unlock panel regs */ - I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | (0xabcd << 16)); + I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | + PANEL_UNLOCK_REGS); dpll &= ~DISPLAY_RATE_SELECT_FPA1; I915_WRITE(dpll_reg, dpll); @@ -4455,7 +4475,8 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc) DRM_DEBUG_DRIVER("downclocking LVDS\n"); /* Unlock panel regs */ - I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | (0xabcd << 16)); + I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | + PANEL_UNLOCK_REGS); dpll |= DISPLAY_RATE_SELECT_FPA1; I915_WRITE(dpll_reg, dpll); @@ -4695,7 +4716,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, struct drm_gem_object *obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_unpin_work *work; - unsigned long flags; + unsigned long flags, offset; int pipesrc_reg = (intel_crtc->pipe == 0) ? PIPEASRC : PIPEBSRC; int ret, pipesrc; u32 flip_mask; @@ -4762,19 +4783,23 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, while (I915_READ(ISR) & flip_mask) ; + /* Offset into the new buffer for cases of shared fbs between CRTCs */ + offset = obj_priv->gtt_offset; + offset += (crtc->y * fb->pitch) + (crtc->x * (fb->bits_per_pixel) / 8); + BEGIN_LP_RING(4); if (IS_I965G(dev)) { OUT_RING(MI_DISPLAY_FLIP | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); OUT_RING(fb->pitch); - OUT_RING(obj_priv->gtt_offset | obj_priv->tiling_mode); + OUT_RING(offset | obj_priv->tiling_mode); pipesrc = I915_READ(pipesrc_reg); OUT_RING(pipesrc & 0x0fff0fff); } else { OUT_RING(MI_DISPLAY_FLIP_I915 | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); OUT_RING(fb->pitch); - OUT_RING(obj_priv->gtt_offset); + OUT_RING(offset); OUT_RING(MI_NOOP); } ADVANCE_LP_RING(); @@ -5506,6 +5531,66 @@ static void intel_init_display(struct drm_device *dev) } } +/* + * Some BIOSes insist on assuming the GPU's pipe A is enabled at suspend, + * resume, or other times. This quirk makes sure that's the case for + * affected systems. + */ +static void quirk_pipea_force (struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + dev_priv->quirks |= QUIRK_PIPEA_FORCE; + DRM_DEBUG_DRIVER("applying pipe a force quirk\n"); +} + +struct intel_quirk { + int device; + int subsystem_vendor; + int subsystem_device; + void (*hook)(struct drm_device *dev); +}; + +struct intel_quirk intel_quirks[] = { + /* HP Compaq 2730p needs pipe A force quirk (LP: #291555) */ + { 0x2a42, 0x103c, 0x30eb, quirk_pipea_force }, + /* HP Mini needs pipe A force quirk (LP: #322104) */ + { 0x27ae,0x103c, 0x361a, quirk_pipea_force }, + + /* Thinkpad R31 needs pipe A force quirk */ + { 0x3577, 0x1014, 0x0505, quirk_pipea_force }, + /* Toshiba Protege R-205, S-209 needs pipe A force quirk */ + { 0x2592, 0x1179, 0x0001, quirk_pipea_force }, + + /* ThinkPad X30 needs pipe A force quirk (LP: #304614) */ + { 0x3577, 0x1014, 0x0513, quirk_pipea_force }, + /* ThinkPad X40 needs pipe A force quirk */ + + /* ThinkPad T60 needs pipe A force quirk (bug #16494) */ + { 0x2782, 0x17aa, 0x201a, quirk_pipea_force }, + + /* 855 & before need to leave pipe A & dpll A up */ + { 0x3582, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force }, + { 0x2562, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force }, +}; + +static void intel_init_quirks(struct drm_device *dev) +{ + struct pci_dev *d = dev->pdev; + int i; + + for (i = 0; i < ARRAY_SIZE(intel_quirks); i++) { + struct intel_quirk *q = &intel_quirks[i]; + + if (d->device == q->device && + (d->subsystem_vendor == q->subsystem_vendor || + q->subsystem_vendor == PCI_ANY_ID) && + (d->subsystem_device == q->subsystem_device || + q->subsystem_device == PCI_ANY_ID)) + q->hook(dev); + } +} + void intel_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -5518,6 +5603,8 @@ void intel_modeset_init(struct drm_device *dev) dev->mode_config.funcs = (void *)&intel_mode_funcs; + intel_init_quirks(dev); + intel_init_display(dev); if (IS_I965G(dev)) { diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1aac59e83bf..5dde80f9e65 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -717,6 +717,51 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, } } +static void ironlake_edp_panel_on (struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long timeout = jiffies + msecs_to_jiffies(5000); + u32 pp, pp_status; + + pp_status = I915_READ(PCH_PP_STATUS); + if (pp_status & PP_ON) + return; + + pp = I915_READ(PCH_PP_CONTROL); + pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON; + I915_WRITE(PCH_PP_CONTROL, pp); + do { + pp_status = I915_READ(PCH_PP_STATUS); + } while (((pp_status & PP_ON) == 0) && !time_after(jiffies, timeout)); + + if (time_after(jiffies, timeout)) + DRM_DEBUG_KMS("panel on wait timed out: 0x%08x\n", pp_status); + + pp &= ~(PANEL_UNLOCK_REGS | EDP_FORCE_VDD); + I915_WRITE(PCH_PP_CONTROL, pp); +} + +static void ironlake_edp_panel_off (struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long timeout = jiffies + msecs_to_jiffies(5000); + u32 pp, pp_status; + + pp = I915_READ(PCH_PP_CONTROL); + pp &= ~POWER_TARGET_ON; + I915_WRITE(PCH_PP_CONTROL, pp); + do { + pp_status = I915_READ(PCH_PP_STATUS); + } while ((pp_status & PP_ON) && !time_after(jiffies, timeout)); + + if (time_after(jiffies, timeout)) + DRM_DEBUG_KMS("panel off wait timed out\n"); + + /* Make sure VDD is enabled so DP AUX will work */ + pp |= EDP_FORCE_VDD; + I915_WRITE(PCH_PP_CONTROL, pp); +} + static void ironlake_edp_backlight_on (struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -751,14 +796,18 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) if (mode != DRM_MODE_DPMS_ON) { if (dp_reg & DP_PORT_EN) { intel_dp_link_down(intel_encoder, dp_priv->DP); - if (IS_eDP(intel_encoder)) + if (IS_eDP(intel_encoder)) { ironlake_edp_backlight_off(dev); + ironlake_edp_panel_off(dev); + } } } else { if (!(dp_reg & DP_PORT_EN)) { intel_dp_link_train(intel_encoder, dp_priv->DP, dp_priv->link_configuration); - if (IS_eDP(intel_encoder)) + if (IS_eDP(intel_encoder)) { + ironlake_edp_panel_on(dev); ironlake_edp_backlight_on(dev); + } } } dp_priv->dpms_mode = mode; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 72206f37c4f..2f7970be905 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -215,6 +215,9 @@ extern void intel_init_clock_gating(struct drm_device *dev); extern void ironlake_enable_drps(struct drm_device *dev); extern void ironlake_disable_drps(struct drm_device *dev); +extern int intel_pin_and_fence_fb_obj(struct drm_device *dev, + struct drm_gem_object *obj); + extern int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *ifb, struct drm_mode_fb_cmd *mode_cmd, diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index c3c505244e0..3e18c9e7729 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -98,7 +98,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, mutex_lock(&dev->struct_mutex); - ret = i915_gem_object_pin(fbo, 64*1024); + ret = intel_pin_and_fence_fb_obj(dev, fbo); if (ret) { DRM_ERROR("failed to pin fb: %d\n", ret); goto out_unref; @@ -236,7 +236,7 @@ int intel_fbdev_destroy(struct drm_device *dev, drm_framebuffer_cleanup(&ifb->base); if (ifb->obj) - drm_gem_object_unreference_unlocked(ifb->obj); + drm_gem_object_unreference(ifb->obj); return 0; } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 31df55f0a0a..0eab8df5bf7 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -599,6 +599,26 @@ static int intel_lvds_get_modes(struct drm_connector *connector) return 0; } +static int intel_no_modeset_on_lid_dmi_callback(const struct dmi_system_id *id) +{ + DRM_DEBUG_KMS("Skipping forced modeset for %s\n", id->ident); + return 1; +} + +/* The GPU hangs up on these systems if modeset is performed on LID open */ +static const struct dmi_system_id intel_no_modeset_on_lid[] = { + { + .callback = intel_no_modeset_on_lid_dmi_callback, + .ident = "Toshiba Tecra A11", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "TECRA A11"), + }, + }, + + { } /* terminating entry */ +}; + /* * Lid events. Note the use of 'modeset_on_lid': * - we set it on lid close, and reset it on open @@ -622,6 +642,9 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, */ if (connector) connector->status = connector->funcs->detect(connector); + /* Don't force modeset on machines where it causes a GPU lockup */ + if (dmi_check_system(intel_no_modeset_on_lid)) + return NOTIFY_OK; if (!acpi_lid_open()) { dev_priv->modeset_on_lid = 1; return NOTIFY_OK; diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index fc924b64919..e492919faf4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -203,36 +203,26 @@ struct methods { const bool rw; }; -static struct methods nv04_methods[] = { - { "PROM", load_vbios_prom, false }, - { "PRAMIN", load_vbios_pramin, true }, - { "PCIROM", load_vbios_pci, true }, -}; - -static struct methods nv50_methods[] = { - { "ACPI", load_vbios_acpi, true }, +static struct methods shadow_methods[] = { { "PRAMIN", load_vbios_pramin, true }, { "PROM", load_vbios_prom, false }, { "PCIROM", load_vbios_pci, true }, + { "ACPI", load_vbios_acpi, true }, }; -#define METHODCNT 3 - static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct methods *methods; - int i; + const int nr_methods = ARRAY_SIZE(shadow_methods); + struct methods *methods = shadow_methods; int testscore = 3; - int scores[METHODCNT]; + int scores[nr_methods], i; if (nouveau_vbios) { - methods = nv04_methods; - for (i = 0; i < METHODCNT; i++) + for (i = 0; i < nr_methods; i++) if (!strcasecmp(nouveau_vbios, methods[i].desc)) break; - if (i < METHODCNT) { + if (i < nr_methods) { NV_INFO(dev, "Attempting to use BIOS image from %s\n", methods[i].desc); @@ -244,12 +234,7 @@ static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data) NV_ERROR(dev, "VBIOS source \'%s\' invalid\n", nouveau_vbios); } - if (dev_priv->card_type < NV_50) - methods = nv04_methods; - else - methods = nv50_methods; - - for (i = 0; i < METHODCNT; i++) { + for (i = 0; i < nr_methods; i++) { NV_TRACE(dev, "Attempting to load BIOS image from %s\n", methods[i].desc); data[0] = data[1] = 0; /* avoid reuse of previous image */ @@ -260,7 +245,7 @@ static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data) } while (--testscore > 0) { - for (i = 0; i < METHODCNT; i++) { + for (i = 0; i < nr_methods; i++) { if (scores[i] == testscore) { NV_TRACE(dev, "Using BIOS image from %s\n", methods[i].desc); diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index c9a4a0d2a11..257ea130ae1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -387,7 +387,8 @@ int nouveau_fbcon_init(struct drm_device *dev) dev_priv->nfbdev = nfbdev; nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs; - ret = drm_fb_helper_init(dev, &nfbdev->helper, 2, 4); + ret = drm_fb_helper_init(dev, &nfbdev->helper, + nv_two_heads(dev) ? 2 : 1, 4); if (ret) { kfree(nfbdev); return ret; diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index 010963d4570..345a75a03c9 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -333,7 +333,6 @@ static int evergreen_cs_packet_parse_vline(struct radeon_cs_parser *p) header = radeon_get_ib_value(p, h_idx); crtc_id = radeon_get_ib_value(p, h_idx + 2 + 7 + 1); reg = CP_PACKET0_GET_REG(header); - mutex_lock(&p->rdev->ddev->mode_config.mutex); obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) { DRM_ERROR("cannot find crtc %d\n", crtc_id); @@ -368,7 +367,6 @@ static int evergreen_cs_packet_parse_vline(struct radeon_cs_parser *p) } } out: - mutex_unlock(&p->rdev->ddev->mode_config.mutex); return r; } diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 3970e62eaab..a89a15ab524 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -1230,7 +1230,6 @@ int r100_cs_packet_parse_vline(struct radeon_cs_parser *p) header = radeon_get_ib_value(p, h_idx); crtc_id = radeon_get_ib_value(p, h_idx + 5); reg = CP_PACKET0_GET_REG(header); - mutex_lock(&p->rdev->ddev->mode_config.mutex); obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) { DRM_ERROR("cannot find crtc %d\n", crtc_id); @@ -1264,7 +1263,6 @@ int r100_cs_packet_parse_vline(struct radeon_cs_parser *p) ib[h_idx + 3] |= RADEON_ENG_DISPLAY_SELECT_CRTC1; } out: - mutex_unlock(&p->rdev->ddev->mode_config.mutex); return r; } @@ -2354,6 +2352,7 @@ void r100_mc_init(struct radeon_device *rdev) if (rdev->flags & RADEON_IS_IGP) base = (RREG32(RADEON_NB_TOM) & 0xffff) << 16; radeon_vram_location(rdev, &rdev->mc, base); + rdev->mc.gtt_base_align = 0; if (!(rdev->flags & RADEON_IS_AGP)) radeon_gtt_location(rdev, &rdev->mc); radeon_update_bandwidth_info(rdev); diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 7e81db5eb80..19a7ef7ee34 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -481,6 +481,7 @@ void r300_mc_init(struct radeon_device *rdev) if (rdev->flags & RADEON_IS_IGP) base = (RREG32(RADEON_NB_TOM) & 0xffff) << 16; radeon_vram_location(rdev, &rdev->mc, base); + rdev->mc.gtt_base_align = 0; if (!(rdev->flags & RADEON_IS_AGP)) radeon_gtt_location(rdev, &rdev->mc); radeon_update_bandwidth_info(rdev); @@ -1176,6 +1177,8 @@ int r300_cs_parse(struct radeon_cs_parser *p) int r; track = kzalloc(sizeof(*track), GFP_KERNEL); + if (track == NULL) + return -ENOMEM; r100_cs_track_clear(p->rdev, track); p->track = track; do { diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index 34330df2848..694af7cc23a 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -125,6 +125,7 @@ void r520_mc_init(struct radeon_device *rdev) r520_vram_get_type(rdev); r100_vram_init_sizes(rdev); radeon_vram_location(rdev, &rdev->mc, 0); + rdev->mc.gtt_base_align = 0; if (!(rdev->flags & RADEON_IS_AGP)) radeon_gtt_location(rdev, &rdev->mc); radeon_update_bandwidth_info(rdev); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 3d6645ce215..e100f69faee 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1179,6 +1179,7 @@ void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) if (rdev->flags & RADEON_IS_IGP) base = (RREG32(MC_VM_FB_LOCATION) & 0xFFFF) << 24; radeon_vram_location(rdev, &rdev->mc, base); + rdev->mc.gtt_base_align = 0; radeon_gtt_location(rdev, mc); } } diff --git a/drivers/gpu/drm/radeon/r600_blit.c b/drivers/gpu/drm/radeon/r600_blit.c index f4fb88ece2b..ca5c29f7077 100644 --- a/drivers/gpu/drm/radeon/r600_blit.c +++ b/drivers/gpu/drm/radeon/r600_blit.c @@ -538,9 +538,12 @@ int r600_prepare_blit_copy(struct drm_device *dev, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; + int ret; DRM_DEBUG("\n"); - r600_nomm_get_vb(dev); + ret = r600_nomm_get_vb(dev); + if (ret) + return ret; dev_priv->blit_vb->file_priv = file_priv; diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index c39c1bc1301..144c32d3713 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -585,7 +585,7 @@ static int r600_cs_packet_parse_vline(struct radeon_cs_parser *p) header = radeon_get_ib_value(p, h_idx); crtc_id = radeon_get_ib_value(p, h_idx + 2 + 7 + 1); reg = CP_PACKET0_GET_REG(header); - mutex_lock(&p->rdev->ddev->mode_config.mutex); + obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) { DRM_ERROR("cannot find crtc %d\n", crtc_id); @@ -620,7 +620,6 @@ static int r600_cs_packet_parse_vline(struct radeon_cs_parser *p) ib[h_idx + 4] = AVIVO_D2MODE_VLINE_STATUS >> 2; } out: - mutex_unlock(&p->rdev->ddev->mode_config.mutex); return r; } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index ab61aaa887b..2f94dc66c18 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -351,6 +351,7 @@ struct radeon_mc { int vram_mtrr; bool vram_is_ddr; bool igp_sideport_enabled; + u64 gtt_base_align; }; bool radeon_combios_sideport_present(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 99bd8a9c56b..10673ae59cf 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -280,6 +280,15 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, } } + /* ASUS HD 3600 board lists the DVI port as HDMI */ + if ((dev->pdev->device == 0x9598) && + (dev->pdev->subsystem_vendor == 0x1043) && + (dev->pdev->subsystem_device == 0x01e4)) { + if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) { + *connector_type = DRM_MODE_CONNECTOR_DVII; + } + } + /* ASUS HD 3450 board lists the DVI port as HDMI */ if ((dev->pdev->device == 0x95C5) && (dev->pdev->subsystem_vendor == 0x1043) && @@ -1029,8 +1038,15 @@ bool radeon_atombios_sideport_present(struct radeon_device *rdev) data_offset); switch (crev) { case 1: - if (igp_info->info.ucMemoryType & 0xf0) - return true; + /* AMD IGPS */ + if ((rdev->family == CHIP_RS690) || + (rdev->family == CHIP_RS740)) { + if (igp_info->info.ulBootUpMemoryClock) + return true; + } else { + if (igp_info->info.ucMemoryType & 0xf0) + return true; + } break; case 2: if (igp_info->info_2.ucMemoryType & 0x0f) diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index d1c1d8dd93c..2417d7b06fd 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -3050,6 +3050,14 @@ void radeon_combios_asic_init(struct drm_device *dev) rdev->pdev->subsystem_device == 0x308b) return; + /* quirk for rs4xx HP dv5000 laptop to make it resume + * - it hangs on resume inside the dynclk 1 table. + */ + if (rdev->family == CHIP_RS480 && + rdev->pdev->subsystem_vendor == 0x103c && + rdev->pdev->subsystem_device == 0x30a4) + return; + /* DYN CLK 1 */ table = combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE); if (table) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 0c7ccc6961a..adccbc2c202 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -771,30 +771,27 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect } else ret = connector_status_connected; - /* multiple connectors on the same encoder with the same ddc line - * This tends to be HDMI and DVI on the same encoder with the - * same ddc line. If the edid says HDMI, consider the HDMI port - * connected and the DVI port disconnected. If the edid doesn't - * say HDMI, vice versa. + /* This gets complicated. We have boards with VGA + HDMI with a + * shared DDC line and we have boards with DVI-D + HDMI with a shared + * DDC line. The latter is more complex because with DVI<->HDMI adapters + * you don't really know what's connected to which port as both are digital. */ if (radeon_connector->shared_ddc && (ret == connector_status_connected)) { struct drm_device *dev = connector->dev; + struct radeon_device *rdev = dev->dev_private; struct drm_connector *list_connector; struct radeon_connector *list_radeon_connector; list_for_each_entry(list_connector, &dev->mode_config.connector_list, head) { if (connector == list_connector) continue; list_radeon_connector = to_radeon_connector(list_connector); - if (radeon_connector->devices == list_radeon_connector->devices) { - if (drm_detect_hdmi_monitor(radeon_connector->edid)) { - if (connector->connector_type == DRM_MODE_CONNECTOR_DVID) { - kfree(radeon_connector->edid); - radeon_connector->edid = NULL; - ret = connector_status_disconnected; - } - } else { - if ((connector->connector_type == DRM_MODE_CONNECTOR_HDMIA) || - (connector->connector_type == DRM_MODE_CONNECTOR_HDMIB)) { + if (list_radeon_connector->shared_ddc && + (list_radeon_connector->ddc_bus->rec.i2c_id == + radeon_connector->ddc_bus->rec.i2c_id)) { + /* cases where both connectors are digital */ + if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) { + /* hpd is our only option in this case */ + if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) { kfree(radeon_connector->edid); radeon_connector->edid = NULL; ret = connector_status_disconnected; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 5f317317aba..dd279da9054 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -226,20 +226,20 @@ void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) { u64 size_af, size_bf; - size_af = 0xFFFFFFFF - mc->vram_end; - size_bf = mc->vram_start; + size_af = ((0xFFFFFFFF - mc->vram_end) + mc->gtt_base_align) & ~mc->gtt_base_align; + size_bf = mc->vram_start & ~mc->gtt_base_align; if (size_bf > size_af) { if (mc->gtt_size > size_bf) { dev_warn(rdev->dev, "limiting GTT\n"); mc->gtt_size = size_bf; } - mc->gtt_start = mc->vram_start - mc->gtt_size; + mc->gtt_start = (mc->vram_start & ~mc->gtt_base_align) - mc->gtt_size; } else { if (mc->gtt_size > size_af) { dev_warn(rdev->dev, "limiting GTT\n"); mc->gtt_size = size_af; } - mc->gtt_start = mc->vram_end + 1; + mc->gtt_start = (mc->vram_end + 1 + mc->gtt_base_align) & ~mc->gtt_base_align; } mc->gtt_end = mc->gtt_start + mc->gtt_size - 1; dev_info(rdev->dev, "GTT: %lluM 0x%08llX - 0x%08llX\n", diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 6a70c0dc7f9..ab389f89fa8 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -128,7 +128,8 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) for (i = 0, found = 0; i < rdev->num_crtc; i++) { crtc = (struct drm_crtc *)minfo->crtcs[i]; if (crtc && crtc->base.id == value) { - value = i; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + value = radeon_crtc->crtc_id; found = 1; break; } diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index bad77f40a9d..5688a0cf6bb 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -108,6 +108,7 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) udelay(panel_pwr_delay * 1000); WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); + udelay(panel_pwr_delay * 1000); break; } diff --git a/drivers/gpu/drm/radeon/radeon_legacy_tv.c b/drivers/gpu/drm/radeon/radeon_legacy_tv.c index f2ed27c8055..03204039774 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_tv.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_tv.c @@ -642,8 +642,8 @@ void radeon_legacy_tv_mode_set(struct drm_encoder *encoder, } flicker_removal = (tmp + 500) / 1000; - if (flicker_removal < 2) - flicker_removal = 2; + if (flicker_removal < 3) + flicker_removal = 3; for (i = 0; i < ARRAY_SIZE(SLOPE_limit); ++i) { if (flicker_removal == SLOPE_limit[i]) break; diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 115d26b762c..3fa6984d989 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -333,6 +333,7 @@ static ssize_t radeon_get_pm_profile(struct device *dev, return snprintf(buf, PAGE_SIZE, "%s\n", (cp == PM_PROFILE_AUTO) ? "auto" : (cp == PM_PROFILE_LOW) ? "low" : + (cp == PM_PROFILE_MID) ? "mid" : (cp == PM_PROFILE_HIGH) ? "high" : "default"); } diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 9e4240b3bf0..f454c9a5e7f 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -57,7 +57,9 @@ void rs400_gart_adjust_size(struct radeon_device *rdev) } if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480) { /* FIXME: RS400 & RS480 seems to have issue with GART size - * if 4G of system memory (needs more testing) */ + * if 4G of system memory (needs more testing) + */ + /* XXX is this still an issue with proper alignment? */ rdev->mc.gtt_size = 32 * 1024 * 1024; DRM_ERROR("Forcing to 32M GART size (because of ASIC bug ?)\n"); } @@ -263,6 +265,7 @@ void rs400_mc_init(struct radeon_device *rdev) r100_vram_init_sizes(rdev); base = (RREG32(RADEON_NB_TOM) & 0xffff) << 16; radeon_vram_location(rdev, &rdev->mc, base); + rdev->mc.gtt_base_align = rdev->mc.gtt_size - 1; radeon_gtt_location(rdev, &rdev->mc); radeon_update_bandwidth_info(rdev); } diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 7bb4c3e52f3..6dc15ea8ba3 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -698,6 +698,7 @@ void rs600_mc_init(struct radeon_device *rdev) base = G_000004_MC_FB_START(base) << 16; rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev); radeon_vram_location(rdev, &rdev->mc, base); + rdev->mc.gtt_base_align = 0; radeon_gtt_location(rdev, &rdev->mc); radeon_update_bandwidth_info(rdev); } diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index f4f0a61bcdc..ce4ecbe1081 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -162,6 +162,7 @@ void rs690_mc_init(struct radeon_device *rdev) rs690_pm_info(rdev); rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev); radeon_vram_location(rdev, &rdev->mc, base); + rdev->mc.gtt_base_align = rdev->mc.gtt_size - 1; radeon_gtt_location(rdev, &rdev->mc); radeon_update_bandwidth_info(rdev); } diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 7d9a7b0a180..0c9c169a685 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -195,6 +195,7 @@ void rv515_mc_init(struct radeon_device *rdev) rv515_vram_get_type(rdev); r100_vram_init_sizes(rdev); radeon_vram_location(rdev, &rdev->mc, 0); + rdev->mc.gtt_base_align = 0; if (!(rdev->flags & RADEON_IS_AGP)) radeon_gtt_location(rdev, &rdev->mc); radeon_update_bandwidth_info(rdev); diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c index 2f047577b1e..ca904799f01 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c @@ -40,11 +40,13 @@ #include <linux/slab.h> #include <asm/atomic.h> -#include <asm/agp.h> #include "ttm/ttm_bo_driver.h" #include "ttm/ttm_page_alloc.h" +#ifdef TTM_HAS_AGP +#include <asm/agp.h> +#endif #define NUM_PAGES_TO_ALLOC (PAGE_SIZE/sizeof(struct page *)) #define SMALL_ALLOCATION 16 @@ -104,7 +106,6 @@ struct ttm_pool_opts { struct ttm_pool_manager { struct kobject kobj; struct shrinker mm_shrink; - atomic_t page_alloc_inited; struct ttm_pool_opts options; union { @@ -142,7 +143,7 @@ static void ttm_pool_kobj_release(struct kobject *kobj) { struct ttm_pool_manager *m = container_of(kobj, struct ttm_pool_manager, kobj); - (void)m; + kfree(m); } static ssize_t ttm_pool_store(struct kobject *kobj, @@ -214,9 +215,7 @@ static struct kobj_type ttm_pool_kobj_type = { .default_attrs = ttm_pool_attrs, }; -static struct ttm_pool_manager _manager = { - .page_alloc_inited = ATOMIC_INIT(0) -}; +static struct ttm_pool_manager *_manager; #ifndef CONFIG_X86 static int set_pages_array_wb(struct page **pages, int addrinarray) @@ -271,7 +270,7 @@ static struct ttm_page_pool *ttm_get_pool(int flags, if (flags & TTM_PAGE_FLAG_DMA32) pool_index |= 0x2; - return &_manager.pools[pool_index]; + return &_manager->pools[pool_index]; } /* set memory back to wb and free the pages. */ @@ -387,7 +386,7 @@ static int ttm_pool_get_num_unused_pages(void) unsigned i; int total = 0; for (i = 0; i < NUM_POOLS; ++i) - total += _manager.pools[i].npages; + total += _manager->pools[i].npages; return total; } @@ -395,7 +394,7 @@ static int ttm_pool_get_num_unused_pages(void) /** * Callback for mm to request pool to reduce number of page held. */ -static int ttm_pool_mm_shrink(int shrink_pages, gfp_t gfp_mask) +static int ttm_pool_mm_shrink(struct shrinker *shrink, int shrink_pages, gfp_t gfp_mask) { static atomic_t start_pool = ATOMIC_INIT(0); unsigned i; @@ -408,7 +407,7 @@ static int ttm_pool_mm_shrink(int shrink_pages, gfp_t gfp_mask) unsigned nr_free = shrink_pages; if (shrink_pages == 0) break; - pool = &_manager.pools[(i + pool_offset)%NUM_POOLS]; + pool = &_manager->pools[(i + pool_offset)%NUM_POOLS]; shrink_pages = ttm_page_pool_free(pool, nr_free); } /* return estimated number of unused pages in pool */ @@ -576,10 +575,10 @@ static void ttm_page_pool_fill_locked(struct ttm_page_pool *pool, /* If allocation request is small and there is not enough * pages in pool we fill the pool first */ - if (count < _manager.options.small + if (count < _manager->options.small && count > pool->npages) { struct list_head new_pages; - unsigned alloc_size = _manager.options.alloc_size; + unsigned alloc_size = _manager->options.alloc_size; /** * Can't change page caching if in irqsave context. We have to @@ -759,8 +758,8 @@ void ttm_put_pages(struct list_head *pages, unsigned page_count, int flags, pool->npages += page_count; /* Check that we don't go over the pool limit */ page_count = 0; - if (pool->npages > _manager.options.max_size) { - page_count = pool->npages - _manager.options.max_size; + if (pool->npages > _manager->options.max_size) { + page_count = pool->npages - _manager->options.max_size; /* free at least NUM_PAGES_TO_ALLOC number of pages * to reduce calls to set_memory_wb */ if (page_count < NUM_PAGES_TO_ALLOC) @@ -785,33 +784,36 @@ static void ttm_page_pool_init_locked(struct ttm_page_pool *pool, int flags, int ttm_page_alloc_init(struct ttm_mem_global *glob, unsigned max_pages) { int ret; - if (atomic_add_return(1, &_manager.page_alloc_inited) > 1) - return 0; + + WARN_ON(_manager); printk(KERN_INFO TTM_PFX "Initializing pool allocator.\n"); - ttm_page_pool_init_locked(&_manager.wc_pool, GFP_HIGHUSER, "wc"); + _manager = kzalloc(sizeof(*_manager), GFP_KERNEL); + + ttm_page_pool_init_locked(&_manager->wc_pool, GFP_HIGHUSER, "wc"); - ttm_page_pool_init_locked(&_manager.uc_pool, GFP_HIGHUSER, "uc"); + ttm_page_pool_init_locked(&_manager->uc_pool, GFP_HIGHUSER, "uc"); - ttm_page_pool_init_locked(&_manager.wc_pool_dma32, GFP_USER | GFP_DMA32, - "wc dma"); + ttm_page_pool_init_locked(&_manager->wc_pool_dma32, + GFP_USER | GFP_DMA32, "wc dma"); - ttm_page_pool_init_locked(&_manager.uc_pool_dma32, GFP_USER | GFP_DMA32, - "uc dma"); + ttm_page_pool_init_locked(&_manager->uc_pool_dma32, + GFP_USER | GFP_DMA32, "uc dma"); - _manager.options.max_size = max_pages; - _manager.options.small = SMALL_ALLOCATION; - _manager.options.alloc_size = NUM_PAGES_TO_ALLOC; + _manager->options.max_size = max_pages; + _manager->options.small = SMALL_ALLOCATION; + _manager->options.alloc_size = NUM_PAGES_TO_ALLOC; - kobject_init(&_manager.kobj, &ttm_pool_kobj_type); - ret = kobject_add(&_manager.kobj, &glob->kobj, "pool"); + ret = kobject_init_and_add(&_manager->kobj, &ttm_pool_kobj_type, + &glob->kobj, "pool"); if (unlikely(ret != 0)) { - kobject_put(&_manager.kobj); + kobject_put(&_manager->kobj); + _manager = NULL; return ret; } - ttm_pool_mm_shrink_init(&_manager); + ttm_pool_mm_shrink_init(_manager); return 0; } @@ -820,16 +822,14 @@ void ttm_page_alloc_fini() { int i; - if (atomic_sub_return(1, &_manager.page_alloc_inited) > 0) - return; - printk(KERN_INFO TTM_PFX "Finalizing pool allocator.\n"); - ttm_pool_mm_shrink_fini(&_manager); + ttm_pool_mm_shrink_fini(_manager); for (i = 0; i < NUM_POOLS; ++i) - ttm_page_pool_free(&_manager.pools[i], FREE_ALL_PAGES); + ttm_page_pool_free(&_manager->pools[i], FREE_ALL_PAGES); - kobject_put(&_manager.kobj); + kobject_put(&_manager->kobj); + _manager = NULL; } int ttm_page_alloc_debugfs(struct seq_file *m, void *data) @@ -837,14 +837,14 @@ int ttm_page_alloc_debugfs(struct seq_file *m, void *data) struct ttm_page_pool *p; unsigned i; char *h[] = {"pool", "refills", "pages freed", "size"}; - if (atomic_read(&_manager.page_alloc_inited) == 0) { + if (!_manager) { seq_printf(m, "No pool allocator running.\n"); return 0; } seq_printf(m, "%6s %12s %13s %8s\n", h[0], h[1], h[2], h[3]); for (i = 0; i < NUM_POOLS; ++i) { - p = &_manager.pools[i]; + p = &_manager->pools[i]; seq_printf(m, "%6s %12ld %13ld %8d\n", p->name, p->nrefills, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index f1d62611241..437ac786277 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -972,6 +972,7 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, ret = copy_from_user(rects, user_rects, rects_size); if (unlikely(ret != 0)) { DRM_ERROR("Failed to get rects.\n"); + ret = -EFAULT; goto out_free; } diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 132278fa624..43409936905 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -358,6 +358,7 @@ config HID_ROCCAT config HID_ROCCAT_KONE tristate "Roccat Kone Mouse support" depends on USB_HID + select HID_ROCCAT ---help--- Support for Roccat Kone mouse. diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index aa0f7dcabcd..866e54ec5fb 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1337,6 +1337,24 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_3) }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_4) }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_5) }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_6) }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_7) }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_8) }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_9) }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_10) }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_11) }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_12) }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_13) }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_14) }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_15) }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_16) }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_17) }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) }, { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, @@ -1760,7 +1778,8 @@ int hid_add_device(struct hid_device *hdev) /* we need to kill them here, otherwise they will stay allocated to * wait for coming driver */ - if (!(hdev->quirks & HID_QUIRK_NO_IGNORE) && hid_ignore(hdev)) + if (!(hdev->quirks & HID_QUIRK_NO_IGNORE) + && (hid_ignore(hdev) || (hdev->quirks & HID_QUIRK_IGNORE))) return -ENODEV; /* XXX hack, any other cleaner solution after the driver core diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index c9402676857..850d02a7a92 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -949,8 +949,8 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer, int ret = 0, len; DECLARE_WAITQUEUE(wait, current); + mutex_lock(&list->read_mutex); while (ret == 0) { - mutex_lock(&list->read_mutex); if (list->head == list->tail) { add_wait_queue(&list->hdev->debug_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 6af77ed0b55..31601eef25d 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -134,6 +134,7 @@ #define USB_VENDOR_ID_CH 0x068e #define USB_DEVICE_ID_CH_PRO_PEDALS 0x00f2 #define USB_DEVICE_ID_CH_COMBATSTICK 0x00f4 +#define USB_DEVICE_ID_CH_FLIGHT_SIM_ECLIPSE_YOKE 0x0051 #define USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE 0x00ff #define USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK 0x00d3 @@ -369,6 +370,8 @@ #define USB_DEVICE_ID_MS_PRESENTER_8K_BT 0x0701 #define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713 +#define USB_VENDOR_ID_MOJO 0x8282 +#define USB_DEVICE_ID_RETRO_ADAPTER 0x3201 #define USB_VENDOR_ID_MONTEREY 0x0566 #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 @@ -391,6 +394,24 @@ #define USB_VENDOR_ID_NTRIG 0x1b96 #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001 +#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1 0x0003 +#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2 0x0004 +#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_3 0x0005 +#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_4 0x0006 +#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_5 0x0007 +#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_6 0x0008 +#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_7 0x0009 +#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_8 0x000A +#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_9 0x000B +#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_10 0x000C +#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_11 0x000D +#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_12 0x000E +#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_13 0x000F +#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_14 0x0010 +#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_15 0x0011 +#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_16 0x0012 +#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_17 0x0013 +#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18 0x0014 #define USB_VENDOR_ID_ONTRAK 0x0a07 #define USB_DEVICE_ID_ONTRAK_ADU100 0x0064 diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index b6b0caeeac5..fb69b8c4953 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c @@ -868,6 +868,42 @@ static void ntrig_remove(struct hid_device *hdev) static const struct hid_device_id ntrig_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN), .driver_data = NTRIG_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1), + .driver_data = NTRIG_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2), + .driver_data = NTRIG_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_3), + .driver_data = NTRIG_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_4), + .driver_data = NTRIG_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_5), + .driver_data = NTRIG_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_6), + .driver_data = NTRIG_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_7), + .driver_data = NTRIG_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_8), + .driver_data = NTRIG_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_9), + .driver_data = NTRIG_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_10), + .driver_data = NTRIG_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_11), + .driver_data = NTRIG_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_12), + .driver_data = NTRIG_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_13), + .driver_data = NTRIG_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_14), + .driver_data = NTRIG_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_15), + .driver_data = NTRIG_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_16), + .driver_data = NTRIG_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_17), + .driver_data = NTRIG_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18), + .driver_data = NTRIG_DUPLICATE_USAGES }, { } }; MODULE_DEVICE_TABLE(hid, ntrig_devices); diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 1ebd3244eb8..b729c028667 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -827,14 +827,21 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co ret++; } } else { + int skipped_report_id = 0; + if (buf[0] == 0x0) { + /* Don't send the Report ID */ + buf++; + count--; + skipped_report_id = 1; + } ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), HID_REQ_SET_REPORT, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, ((report_type + 1) << 8) | *buf, - interface->desc.bInterfaceNumber, buf + 1, count - 1, + interface->desc.bInterfaceNumber, buf, count, USB_CTRL_SET_TIMEOUT); - /* count also the report id */ - if (ret > 0) + /* count also the report id, if this was a numbered report. */ + if (ret > 0 && skipped_report_id) ret++; } diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 5ff8d327f33..5f5aa39b398 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -34,6 +34,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, @@ -56,6 +57,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_COMBATSTICK, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_ECLIPSE_YOKE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_PEDALS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK, HID_QUIRK_NOGET }, diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 2988da150ed..05344af5073 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -53,6 +53,7 @@ struct coretemp_data { struct mutex update_lock; const char *name; u32 id; + u16 core_id; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ int temp; @@ -75,7 +76,7 @@ static ssize_t show_name(struct device *dev, struct device_attribute if (attr->index == SHOW_NAME) ret = sprintf(buf, "%s\n", data->name); else /* show label */ - ret = sprintf(buf, "Core %d\n", data->id); + ret = sprintf(buf, "Core %d\n", data->core_id); return ret; } @@ -304,6 +305,9 @@ static int __devinit coretemp_probe(struct platform_device *pdev) } data->id = pdev->id; +#ifdef CONFIG_SMP + data->core_id = c->cpu_core_id; +#endif data->name = "coretemp"; mutex_init(&data->update_lock); @@ -405,6 +409,10 @@ struct pdev_entry { struct list_head list; struct platform_device *pdev; unsigned int cpu; +#ifdef CONFIG_SMP + u16 phys_proc_id; + u16 cpu_core_id; +#endif }; static LIST_HEAD(pdev_list); @@ -415,6 +423,22 @@ static int __cpuinit coretemp_device_add(unsigned int cpu) int err; struct platform_device *pdev; struct pdev_entry *pdev_entry; +#ifdef CONFIG_SMP + struct cpuinfo_x86 *c = &cpu_data(cpu); +#endif + + mutex_lock(&pdev_list_mutex); + +#ifdef CONFIG_SMP + /* Skip second HT entry of each core */ + list_for_each_entry(pdev_entry, &pdev_list, list) { + if (c->phys_proc_id == pdev_entry->phys_proc_id && + c->cpu_core_id == pdev_entry->cpu_core_id) { + err = 0; /* Not an error */ + goto exit; + } + } +#endif pdev = platform_device_alloc(DRVNAME, cpu); if (!pdev) { @@ -438,7 +462,10 @@ static int __cpuinit coretemp_device_add(unsigned int cpu) pdev_entry->pdev = pdev; pdev_entry->cpu = cpu; - mutex_lock(&pdev_list_mutex); +#ifdef CONFIG_SMP + pdev_entry->phys_proc_id = c->phys_proc_id; + pdev_entry->cpu_core_id = c->cpu_core_id; +#endif list_add_tail(&pdev_entry->list, &pdev_list); mutex_unlock(&pdev_list_mutex); @@ -449,6 +476,7 @@ exit_device_free: exit_device_put: platform_device_put(pdev); exit: + mutex_unlock(&pdev_list_mutex); return err; } diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 5be09c048c5..25763d2223b 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -80,6 +80,13 @@ superio_inb(int reg) return inb(VAL); } +static inline void +superio_outb(int reg, int val) +{ + outb(reg, REG); + outb(val, VAL); +} + static int superio_inw(int reg) { int val; @@ -1517,6 +1524,21 @@ static int __init it87_find(unsigned short *address, sio_data->vid_value = superio_inb(IT87_SIO_VID_REG); reg = superio_inb(IT87_SIO_PINX2_REG); + /* + * The IT8720F has no VIN7 pin, so VCCH should always be + * routed internally to VIN7 with an internal divider. + * Curiously, there still is a configuration bit to control + * this, which means it can be set incorrectly. And even + * more curiously, many boards out there are improperly + * configured, even though the IT8720F datasheet claims + * that the internal routing of VCCH to VIN7 is the default + * setting. So we force the internal routing in this case. + */ + if (sio_data->type == it8720 && !(reg & (1 << 1))) { + reg |= (1 << 1); + superio_outb(IT87_SIO_PINX2_REG, reg); + pr_notice("it87: Routing internal VCCH to in7\n"); + } if (reg & (1 << 0)) pr_info("it87: in3 is VCC (+5V)\n"); if (reg & (1 << 1)) diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c index f26acdb1168..8bdf80d9159 100644 --- a/drivers/hwmon/k8temp.c +++ b/drivers/hwmon/k8temp.c @@ -180,11 +180,13 @@ static int __devinit k8temp_probe(struct pci_dev *pdev, } if ((model >= 0x69) && - !(model == 0xc1 || model == 0x6c || model == 0x7c)) { + !(model == 0xc1 || model == 0x6c || model == 0x7c || + model == 0x6b || model == 0x6f || model == 0x7f)) { /* - * RevG desktop CPUs (i.e. no socket S1G1 parts) - * need additional offset, otherwise reported - * temperature is below ambient temperature + * RevG desktop CPUs (i.e. no socket S1G1 or + * ASB1 parts) need additional offset, + * otherwise reported temperature is below + * ambient temperature */ data->temp_offset = 21000; } diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index f4b21f2bb8e..c60081169cc 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -655,7 +655,7 @@ static void __devinit dmi_check_onboard_device(u8 type, const char *name, /* & ~0x80, ignore enabled/disabled bit */ if ((type & ~0x80) != dmi_devices[i].type) continue; - if (strcmp(name, dmi_devices[i].name)) + if (strcasecmp(name, dmi_devices[i].name)) continue; memset(&info, 0, sizeof(struct i2c_board_info)); @@ -704,9 +704,6 @@ static int __devinit i801_probe(struct pci_dev *dev, { unsigned char temp; int err, i; -#if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE - const char *vendor; -#endif I801_dev = dev; i801_features = 0; @@ -808,8 +805,7 @@ static int __devinit i801_probe(struct pci_dev *dev, } #endif #if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE - vendor = dmi_get_system_info(DMI_BOARD_VENDOR); - if (vendor && !strcmp(vendor, "FUJITSU SIEMENS")) + if (dmi_name_in_vendors("FUJITSU")) dmi_walk(dmi_check_onboard_devices, &i801_adapter); #endif diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c index 3d76a188e42..0fe505d7abe 100644 --- a/drivers/i2c/busses/i2c-sibyte.c +++ b/drivers/i2c/busses/i2c-sibyte.c @@ -94,7 +94,7 @@ static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr, } break; default: - return -1; /* XXXKW better error code? */ + return -EOPNOTSUPP; } while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY) @@ -104,7 +104,7 @@ static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr, if (error & M_SMB_ERROR) { /* Clear error bit by writing a 1 */ csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS)); - return -1; /* XXXKW better error code? */ + return (error & M_SMB_ERROR_TYPE) ? -EIO : -ENXIO; } if (data_bytes == 1) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 1cca2631e5b..0815e10da7c 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1428,13 +1428,12 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver) if (!(adapter->class & driver->class)) goto exit_free; - /* Stop here if we can't use SMBUS_QUICK */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) { + /* Stop here if the bus doesn't support probing */ + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE)) { if (address_list[0] == I2C_CLIENT_END) goto exit_free; - dev_warn(&adapter->dev, "SMBus Quick command not supported, " - "can't probe for chips\n"); + dev_warn(&adapter->dev, "Probing not supported\n"); err = -EOPNOTSUPP; goto exit_free; } diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 30ce0a8eca0..855ee44fdb5 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -969,7 +969,8 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb) goto err; goto out; err: - abort_connection(ep, skb, GFP_KERNEL); + state_set(&ep->com, ABORTING); + send_abort(ep, skb, GFP_KERNEL); out: connect_reply_upcall(ep, err); return; @@ -1372,7 +1373,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb) pdev, 0); mtu = pdev->mtu; tx_chan = cxgb4_port_chan(pdev); - smac_idx = tx_chan << 1; + smac_idx = (cxgb4_port_viid(pdev) & 0x7F) << 1; step = dev->rdev.lldi.ntxq / dev->rdev.lldi.nchan; txq_idx = cxgb4_port_idx(pdev) * step; step = dev->rdev.lldi.nrxq / dev->rdev.lldi.nchan; @@ -1383,7 +1384,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb) dst->neighbour->dev, 0); mtu = dst_mtu(dst); tx_chan = cxgb4_port_chan(dst->neighbour->dev); - smac_idx = tx_chan << 1; + smac_idx = (cxgb4_port_viid(dst->neighbour->dev) & 0x7F) << 1; step = dev->rdev.lldi.ntxq / dev->rdev.lldi.nchan; txq_idx = cxgb4_port_idx(dst->neighbour->dev) * step; step = dev->rdev.lldi.nrxq / dev->rdev.lldi.nchan; @@ -1950,7 +1951,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) pdev, 0); ep->mtu = pdev->mtu; ep->tx_chan = cxgb4_port_chan(pdev); - ep->smac_idx = ep->tx_chan << 1; + ep->smac_idx = (cxgb4_port_viid(pdev) & 0x7F) << 1; step = ep->com.dev->rdev.lldi.ntxq / ep->com.dev->rdev.lldi.nchan; ep->txq_idx = cxgb4_port_idx(pdev) * step; @@ -1965,7 +1966,8 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) ep->dst->neighbour->dev, 0); ep->mtu = dst_mtu(ep->dst); ep->tx_chan = cxgb4_port_chan(ep->dst->neighbour->dev); - ep->smac_idx = ep->tx_chan << 1; + ep->smac_idx = (cxgb4_port_viid(ep->dst->neighbour->dev) & + 0x7F) << 1; step = ep->com.dev->rdev.lldi.ntxq / ep->com.dev->rdev.lldi.nchan; ep->txq_idx = cxgb4_port_idx(ep->dst->neighbour->dev) * step; diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c index 2447f529548..fac5c6e6801 100644 --- a/drivers/infiniband/hw/cxgb4/cq.c +++ b/drivers/infiniband/hw/cxgb4/cq.c @@ -77,7 +77,7 @@ static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, kfree(cq->sw_queue); dma_free_coherent(&(rdev->lldi.pdev->dev), cq->memsize, cq->queue, - pci_unmap_addr(cq, mapping)); + dma_unmap_addr(cq, mapping)); c4iw_put_cqid(rdev, cq->cqid, uctx); return ret; } @@ -112,7 +112,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, ret = -ENOMEM; goto err3; } - pci_unmap_addr_set(cq, mapping, cq->dma_addr); + dma_unmap_addr_set(cq, mapping, cq->dma_addr); memset(cq->queue, 0, cq->memsize); /* build fw_ri_res_wr */ @@ -179,7 +179,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, return 0; err4: dma_free_coherent(&rdev->lldi.pdev->dev, cq->memsize, cq->queue, - pci_unmap_addr(cq, mapping)); + dma_unmap_addr(cq, mapping)); err3: kfree(cq->sw_queue); err2: @@ -764,7 +764,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries, struct c4iw_create_cq_resp uresp; struct c4iw_ucontext *ucontext = NULL; int ret; - size_t memsize; + size_t memsize, hwentries; struct c4iw_mm_entry *mm, *mm2; PDBG("%s ib_dev %p entries %d\n", __func__, ibdev, entries); @@ -788,14 +788,29 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries, * entries must be multiple of 16 for HW. */ entries = roundup(entries, 16); - memsize = entries * sizeof *chp->cq.queue; + + /* + * Make actual HW queue 2x to avoid cdix_inc overflows. + */ + hwentries = entries * 2; + + /* + * Make HW queue at least 64 entries so GTS updates aren't too + * frequent. + */ + if (hwentries < 64) + hwentries = 64; + + memsize = hwentries * sizeof *chp->cq.queue; /* * memsize must be a multiple of the page size if its a user cq. */ - if (ucontext) + if (ucontext) { memsize = roundup(memsize, PAGE_SIZE); - chp->cq.size = entries; + hwentries = memsize / sizeof *chp->cq.queue; + } + chp->cq.size = hwentries; chp->cq.memsize = memsize; ret = create_cq(&rhp->rdev, &chp->cq, @@ -805,7 +820,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries, chp->rhp = rhp; chp->cq.size--; /* status page */ - chp->ibcq.cqe = chp->cq.size - 1; + chp->ibcq.cqe = entries - 2; spin_lock_init(&chp->lock); atomic_set(&chp->refcnt, 1); init_waitqueue_head(&chp->wait); diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h index 277ab589b44..d33e1a66881 100644 --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h @@ -261,7 +261,7 @@ static inline struct c4iw_mw *to_c4iw_mw(struct ib_mw *ibmw) struct c4iw_fr_page_list { struct ib_fast_reg_page_list ibpl; - DECLARE_PCI_UNMAP_ADDR(mapping); + DEFINE_DMA_UNMAP_ADDR(mapping); dma_addr_t dma_addr; struct c4iw_dev *dev; int size; diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c index 7f94da1a243..82b5703b894 100644 --- a/drivers/infiniband/hw/cxgb4/mem.c +++ b/drivers/infiniband/hw/cxgb4/mem.c @@ -764,7 +764,7 @@ struct ib_fast_reg_page_list *c4iw_alloc_fastreg_pbl(struct ib_device *device, if (!c4pl) return ERR_PTR(-ENOMEM); - pci_unmap_addr_set(c4pl, mapping, dma_addr); + dma_unmap_addr_set(c4pl, mapping, dma_addr); c4pl->dma_addr = dma_addr; c4pl->dev = dev; c4pl->size = size; @@ -779,7 +779,7 @@ void c4iw_free_fastreg_pbl(struct ib_fast_reg_page_list *ibpl) struct c4iw_fr_page_list *c4pl = to_c4iw_fr_page_list(ibpl); dma_free_coherent(&c4pl->dev->rdev.lldi.pdev->dev, c4pl->size, - c4pl, pci_unmap_addr(c4pl, mapping)); + c4pl, dma_unmap_addr(c4pl, mapping)); } int c4iw_dereg_mr(struct ib_mr *ib_mr) diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 0c28ed1eafa..7065cb31055 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -40,10 +40,10 @@ static int destroy_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, */ dma_free_coherent(&(rdev->lldi.pdev->dev), wq->rq.memsize, wq->rq.queue, - pci_unmap_addr(&wq->rq, mapping)); + dma_unmap_addr(&wq->rq, mapping)); dma_free_coherent(&(rdev->lldi.pdev->dev), wq->sq.memsize, wq->sq.queue, - pci_unmap_addr(&wq->sq, mapping)); + dma_unmap_addr(&wq->sq, mapping)); c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size); kfree(wq->rq.sw_rq); kfree(wq->sq.sw_sq); @@ -99,7 +99,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, if (!wq->sq.queue) goto err5; memset(wq->sq.queue, 0, wq->sq.memsize); - pci_unmap_addr_set(&wq->sq, mapping, wq->sq.dma_addr); + dma_unmap_addr_set(&wq->sq, mapping, wq->sq.dma_addr); wq->rq.queue = dma_alloc_coherent(&(rdev->lldi.pdev->dev), wq->rq.memsize, &(wq->rq.dma_addr), @@ -112,7 +112,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, wq->rq.queue, (unsigned long long)virt_to_phys(wq->rq.queue)); memset(wq->rq.queue, 0, wq->rq.memsize); - pci_unmap_addr_set(&wq->rq, mapping, wq->rq.dma_addr); + dma_unmap_addr_set(&wq->rq, mapping, wq->rq.dma_addr); wq->db = rdev->lldi.db_reg; wq->gts = rdev->lldi.gts_reg; @@ -217,11 +217,11 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, err7: dma_free_coherent(&(rdev->lldi.pdev->dev), wq->rq.memsize, wq->rq.queue, - pci_unmap_addr(&wq->rq, mapping)); + dma_unmap_addr(&wq->rq, mapping)); err6: dma_free_coherent(&(rdev->lldi.pdev->dev), wq->sq.memsize, wq->sq.queue, - pci_unmap_addr(&wq->sq, mapping)); + dma_unmap_addr(&wq->sq, mapping)); err5: c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size); err4: diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h index 1057cb96302..9cf8d85bfcf 100644 --- a/drivers/infiniband/hw/cxgb4/t4.h +++ b/drivers/infiniband/hw/cxgb4/t4.h @@ -279,7 +279,7 @@ struct t4_swsqe { struct t4_sq { union t4_wr *queue; dma_addr_t dma_addr; - DECLARE_PCI_UNMAP_ADDR(mapping); + DEFINE_DMA_UNMAP_ADDR(mapping); struct t4_swsqe *sw_sq; struct t4_swsqe *oldest_read; u64 udb; @@ -298,7 +298,7 @@ struct t4_swrqe { struct t4_rq { union t4_recv_wr *queue; dma_addr_t dma_addr; - DECLARE_PCI_UNMAP_ADDR(mapping); + DEFINE_DMA_UNMAP_ADDR(mapping); struct t4_swrqe *sw_rq; u64 udb; size_t memsize; @@ -429,7 +429,7 @@ static inline int t4_wq_db_enabled(struct t4_wq *wq) struct t4_cq { struct t4_cqe *queue; dma_addr_t dma_addr; - DECLARE_PCI_UNMAP_ADDR(mapping); + DEFINE_DMA_UNMAP_ADDR(mapping); struct t4_cqe *sw_queue; void __iomem *gts; struct c4iw_rdev *rdev; diff --git a/drivers/infiniband/hw/qib/Makefile b/drivers/infiniband/hw/qib/Makefile index c6515a1b9a6..f12d7bb8b39 100644 --- a/drivers/infiniband/hw/qib/Makefile +++ b/drivers/infiniband/hw/qib/Makefile @@ -6,7 +6,7 @@ ib_qib-y := qib_cq.o qib_diag.o qib_dma.o qib_driver.o qib_eeprom.o \ qib_qp.o qib_qsfp.o qib_rc.o qib_ruc.o qib_sdma.o qib_srq.o \ qib_sysfs.o qib_twsi.o qib_tx.o qib_uc.o qib_ud.o \ qib_user_pages.o qib_user_sdma.o qib_verbs_mcast.o qib_iba7220.o \ - qib_sd7220.o qib_sd7220_img.o qib_iba7322.o qib_verbs.o + qib_sd7220.o qib_iba7322.o qib_verbs.o # 6120 has no fallback if no MSI interrupts, others can do INTx ib_qib-$(CONFIG_PCI_MSI) += qib_iba6120.o diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h index 32d9208efcf..3593983df7b 100644 --- a/drivers/infiniband/hw/qib/qib.h +++ b/drivers/infiniband/hw/qib/qib.h @@ -686,6 +686,7 @@ struct qib_devdata { void __iomem *piobase; /* mem-mapped pointer to base of user chip regs (if using WC PAT) */ u64 __iomem *userbase; + void __iomem *piovl15base; /* base of VL15 buffers, if not WC */ /* * points to area where PIOavail registers will be DMA'ed. * Has to be on a page of it's own, because the page will be diff --git a/drivers/infiniband/hw/qib/qib_7220.h b/drivers/infiniband/hw/qib/qib_7220.h index ea0bfd896f9..21f374aa063 100644 --- a/drivers/infiniband/hw/qib/qib_7220.h +++ b/drivers/infiniband/hw/qib/qib_7220.h @@ -109,10 +109,6 @@ struct qib_chippport_specific { */ int qib_sd7220_presets(struct qib_devdata *dd); int qib_sd7220_init(struct qib_devdata *dd); -int qib_sd7220_prog_ld(struct qib_devdata *dd, int sdnum, u8 *img, - int len, int offset); -int qib_sd7220_prog_vfy(struct qib_devdata *dd, int sdnum, const u8 *img, - int len, int offset); void qib_sd7220_clr_ibpar(struct qib_devdata *); /* * Below used for sdnum parameter, selecting one of the two sections @@ -121,9 +117,6 @@ void qib_sd7220_clr_ibpar(struct qib_devdata *); */ #define IB_7220_SERDES 2 -int qib_sd7220_ib_load(struct qib_devdata *dd); -int qib_sd7220_ib_vfy(struct qib_devdata *dd); - static inline u32 qib_read_kreg32(const struct qib_devdata *dd, const u16 regno) { diff --git a/drivers/infiniband/hw/qib/qib_7322_regs.h b/drivers/infiniband/hw/qib/qib_7322_regs.h index a97440ba924..32dc81ff8d4 100644 --- a/drivers/infiniband/hw/qib/qib_7322_regs.h +++ b/drivers/infiniband/hw/qib/qib_7322_regs.h @@ -742,15 +742,15 @@ #define QIB_7322_HwErrMask_IBCBusFromSPCParityErrMask_1_LSB 0xF #define QIB_7322_HwErrMask_IBCBusFromSPCParityErrMask_1_MSB 0xF #define QIB_7322_HwErrMask_IBCBusFromSPCParityErrMask_1_RMASK 0x1 -#define QIB_7322_HwErrMask_statusValidNoEopMask_1_LSB 0xE -#define QIB_7322_HwErrMask_statusValidNoEopMask_1_MSB 0xE -#define QIB_7322_HwErrMask_statusValidNoEopMask_1_RMASK 0x1 +#define QIB_7322_HwErrMask_IBCBusToSPCParityErrMask_1_LSB 0xE +#define QIB_7322_HwErrMask_IBCBusToSPCParityErrMask_1_MSB 0xE +#define QIB_7322_HwErrMask_IBCBusToSPCParityErrMask_1_RMASK 0x1 #define QIB_7322_HwErrMask_IBCBusFromSPCParityErrMask_0_LSB 0xD #define QIB_7322_HwErrMask_IBCBusFromSPCParityErrMask_0_MSB 0xD #define QIB_7322_HwErrMask_IBCBusFromSPCParityErrMask_0_RMASK 0x1 -#define QIB_7322_HwErrMask_statusValidNoEopMask_0_LSB 0xC -#define QIB_7322_HwErrMask_statusValidNoEopMask_0_MSB 0xC -#define QIB_7322_HwErrMask_statusValidNoEopMask_0_RMASK 0x1 +#define QIB_7322_HwErrMask_statusValidNoEopMask_LSB 0xC +#define QIB_7322_HwErrMask_statusValidNoEopMask_MSB 0xC +#define QIB_7322_HwErrMask_statusValidNoEopMask_RMASK 0x1 #define QIB_7322_HwErrMask_LATriggeredMask_LSB 0xB #define QIB_7322_HwErrMask_LATriggeredMask_MSB 0xB #define QIB_7322_HwErrMask_LATriggeredMask_RMASK 0x1 @@ -796,15 +796,15 @@ #define QIB_7322_HwErrStatus_IBCBusFromSPCParityErr_1_LSB 0xF #define QIB_7322_HwErrStatus_IBCBusFromSPCParityErr_1_MSB 0xF #define QIB_7322_HwErrStatus_IBCBusFromSPCParityErr_1_RMASK 0x1 -#define QIB_7322_HwErrStatus_statusValidNoEop_1_LSB 0xE -#define QIB_7322_HwErrStatus_statusValidNoEop_1_MSB 0xE -#define QIB_7322_HwErrStatus_statusValidNoEop_1_RMASK 0x1 +#define QIB_7322_HwErrStatus_IBCBusToSPCParityErr_1_LSB 0xE +#define QIB_7322_HwErrStatus_IBCBusToSPCParityErr_1_MSB 0xE +#define QIB_7322_HwErrStatus_IBCBusToSPCParityErr_1_RMASK 0x1 #define QIB_7322_HwErrStatus_IBCBusFromSPCParityErr_0_LSB 0xD #define QIB_7322_HwErrStatus_IBCBusFromSPCParityErr_0_MSB 0xD #define QIB_7322_HwErrStatus_IBCBusFromSPCParityErr_0_RMASK 0x1 -#define QIB_7322_HwErrStatus_statusValidNoEop_0_LSB 0xC -#define QIB_7322_HwErrStatus_statusValidNoEop_0_MSB 0xC -#define QIB_7322_HwErrStatus_statusValidNoEop_0_RMASK 0x1 +#define QIB_7322_HwErrStatus_statusValidNoEop_LSB 0xC +#define QIB_7322_HwErrStatus_statusValidNoEop_MSB 0xC +#define QIB_7322_HwErrStatus_statusValidNoEop_RMASK 0x1 #define QIB_7322_HwErrStatus_LATriggered_LSB 0xB #define QIB_7322_HwErrStatus_LATriggered_MSB 0xB #define QIB_7322_HwErrStatus_LATriggered_RMASK 0x1 @@ -850,15 +850,15 @@ #define QIB_7322_HwErrClear_IBCBusFromSPCParityErrClear_1_LSB 0xF #define QIB_7322_HwErrClear_IBCBusFromSPCParityErrClear_1_MSB 0xF #define QIB_7322_HwErrClear_IBCBusFromSPCParityErrClear_1_RMASK 0x1 -#define QIB_7322_HwErrClear_IBCBusToSPCparityErrClear_1_LSB 0xE -#define QIB_7322_HwErrClear_IBCBusToSPCparityErrClear_1_MSB 0xE -#define QIB_7322_HwErrClear_IBCBusToSPCparityErrClear_1_RMASK 0x1 +#define QIB_7322_HwErrClear_IBCBusToSPCParityErrClear_1_LSB 0xE +#define QIB_7322_HwErrClear_IBCBusToSPCParityErrClear_1_MSB 0xE +#define QIB_7322_HwErrClear_IBCBusToSPCParityErrClear_1_RMASK 0x1 #define QIB_7322_HwErrClear_IBCBusFromSPCParityErrClear_0_LSB 0xD #define QIB_7322_HwErrClear_IBCBusFromSPCParityErrClear_0_MSB 0xD #define QIB_7322_HwErrClear_IBCBusFromSPCParityErrClear_0_RMASK 0x1 -#define QIB_7322_HwErrClear_IBCBusToSPCparityErrClear_0_LSB 0xC -#define QIB_7322_HwErrClear_IBCBusToSPCparityErrClear_0_MSB 0xC -#define QIB_7322_HwErrClear_IBCBusToSPCparityErrClear_0_RMASK 0x1 +#define QIB_7322_HwErrClear_statusValidNoEopClear_LSB 0xC +#define QIB_7322_HwErrClear_statusValidNoEopClear_MSB 0xC +#define QIB_7322_HwErrClear_statusValidNoEopClear_RMASK 0x1 #define QIB_7322_HwErrClear_LATriggeredClear_LSB 0xB #define QIB_7322_HwErrClear_LATriggeredClear_MSB 0xB #define QIB_7322_HwErrClear_LATriggeredClear_RMASK 0x1 @@ -880,15 +880,15 @@ #define QIB_7322_HwDiagCtrl_ForceIBCBusFromSPCParityErr_1_LSB 0xF #define QIB_7322_HwDiagCtrl_ForceIBCBusFromSPCParityErr_1_MSB 0xF #define QIB_7322_HwDiagCtrl_ForceIBCBusFromSPCParityErr_1_RMASK 0x1 -#define QIB_7322_HwDiagCtrl_ForcestatusValidNoEop_1_LSB 0xE -#define QIB_7322_HwDiagCtrl_ForcestatusValidNoEop_1_MSB 0xE -#define QIB_7322_HwDiagCtrl_ForcestatusValidNoEop_1_RMASK 0x1 +#define QIB_7322_HwDiagCtrl_ForceIBCBusToSPCParityErr_1_LSB 0xE +#define QIB_7322_HwDiagCtrl_ForceIBCBusToSPCParityErr_1_MSB 0xE +#define QIB_7322_HwDiagCtrl_ForceIBCBusToSPCParityErr_1_RMASK 0x1 #define QIB_7322_HwDiagCtrl_ForceIBCBusFromSPCParityErr_0_LSB 0xD #define QIB_7322_HwDiagCtrl_ForceIBCBusFromSPCParityErr_0_MSB 0xD #define QIB_7322_HwDiagCtrl_ForceIBCBusFromSPCParityErr_0_RMASK 0x1 -#define QIB_7322_HwDiagCtrl_ForcestatusValidNoEop_0_LSB 0xC -#define QIB_7322_HwDiagCtrl_ForcestatusValidNoEop_0_MSB 0xC -#define QIB_7322_HwDiagCtrl_ForcestatusValidNoEop_0_RMASK 0x1 +#define QIB_7322_HwDiagCtrl_ForceIBCBusToSPCParityErr_0_LSB 0xC +#define QIB_7322_HwDiagCtrl_ForceIBCBusToSPCParityErr_0_MSB 0xC +#define QIB_7322_HwDiagCtrl_ForceIBCBusToSPCParityErr_0_RMASK 0x1 #define QIB_7322_EXTStatus_OFFS 0xC0 #define QIB_7322_EXTStatus_DEF 0x000000000000X000 diff --git a/drivers/infiniband/hw/qib/qib_diag.c b/drivers/infiniband/hw/qib/qib_diag.c index ca98dd52375..05dcf0d9a7d 100644 --- a/drivers/infiniband/hw/qib/qib_diag.c +++ b/drivers/infiniband/hw/qib/qib_diag.c @@ -233,6 +233,7 @@ static u32 __iomem *qib_remap_ioaddr32(struct qib_devdata *dd, u32 offset, u32 __iomem *krb32 = (u32 __iomem *)dd->kregbase; u32 __iomem *map = NULL; u32 cnt = 0; + u32 tot4k, offs4k; /* First, simplest case, offset is within the first map. */ kreglen = (dd->kregend - dd->kregbase) * sizeof(u64); @@ -250,7 +251,8 @@ static u32 __iomem *qib_remap_ioaddr32(struct qib_devdata *dd, u32 offset, if (dd->userbase) { /* If user regs mapped, they are after send, so set limit. */ u32 ulim = (dd->cfgctxts * dd->ureg_align) + dd->uregbase; - snd_lim = dd->uregbase; + if (!dd->piovl15base) + snd_lim = dd->uregbase; krb32 = (u32 __iomem *)dd->userbase; if (offset >= dd->uregbase && offset < ulim) { map = krb32 + (offset - dd->uregbase) / sizeof(u32); @@ -277,14 +279,14 @@ static u32 __iomem *qib_remap_ioaddr32(struct qib_devdata *dd, u32 offset, /* If 4k buffers exist, account for them by bumping * appropriate limit. */ + tot4k = dd->piobcnt4k * dd->align4k; + offs4k = dd->piobufbase >> 32; if (dd->piobcnt4k) { - u32 tot4k = dd->piobcnt4k * dd->align4k; - u32 offs4k = dd->piobufbase >> 32; if (snd_bottom > offs4k) snd_bottom = offs4k; else { /* 4k above 2k. Bump snd_lim, if needed*/ - if (!dd->userbase) + if (!dd->userbase || dd->piovl15base) snd_lim = offs4k + tot4k; } } @@ -298,6 +300,15 @@ static u32 __iomem *qib_remap_ioaddr32(struct qib_devdata *dd, u32 offset, cnt = snd_lim - offset; } + if (!map && offs4k && dd->piovl15base) { + snd_lim = offs4k + tot4k + 2 * dd->align4k; + if (offset >= (offs4k + tot4k) && offset < snd_lim) { + map = (u32 __iomem *)dd->piovl15base + + ((offset - (offs4k + tot4k)) / sizeof(u32)); + cnt = snd_lim - offset; + } + } + mapped: if (cntp) *cntp = cnt; diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c index 1eadadc13da..a5e29dbb953 100644 --- a/drivers/infiniband/hw/qib/qib_iba6120.c +++ b/drivers/infiniband/hw/qib/qib_iba6120.c @@ -1355,8 +1355,7 @@ static int qib_6120_bringup_serdes(struct qib_pportdata *ppd) hwstat = qib_read_kreg64(dd, kr_hwerrstatus); if (hwstat) { /* should just have PLL, clear all set, in an case */ - if (hwstat & ~QLOGIC_IB_HWE_SERDESPLLFAILED) - qib_write_kreg(dd, kr_hwerrclear, hwstat); + qib_write_kreg(dd, kr_hwerrclear, hwstat); qib_write_kreg(dd, kr_errclear, ERR_MASK(HardwareErr)); } diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 503992d9c5c..5eedf83e2c3 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -543,7 +543,7 @@ struct vendor_txdds_ent { static void write_tx_serdes_param(struct qib_pportdata *, struct txdds_ent *); #define TXDDS_TABLE_SZ 16 /* number of entries per speed in onchip table */ -#define TXDDS_EXTRA_SZ 11 /* number of extra tx settings entries */ +#define TXDDS_EXTRA_SZ 13 /* number of extra tx settings entries */ #define SERDES_CHANS 4 /* yes, it's obvious, but one less magic number */ #define H1_FORCE_VAL 8 @@ -1100,9 +1100,9 @@ static const struct qib_hwerror_msgs qib_7322_hwerror_msgs[] = { HWE_AUTO_P(SDmaMemReadErr, 1), HWE_AUTO_P(SDmaMemReadErr, 0), HWE_AUTO_P(IBCBusFromSPCParityErr, 1), + HWE_AUTO_P(IBCBusToSPCParityErr, 1), HWE_AUTO_P(IBCBusFromSPCParityErr, 0), - HWE_AUTO_P(statusValidNoEop, 1), - HWE_AUTO_P(statusValidNoEop, 0), + HWE_AUTO(statusValidNoEop), HWE_AUTO(LATriggered), { .mask = 0 } }; @@ -4763,6 +4763,8 @@ static void qib_7322_mini_pcs_reset(struct qib_pportdata *ppd) SYM_MASK(IBPCSConfig_0, tx_rx_reset); val = qib_read_kreg_port(ppd, krp_ib_pcsconfig); + qib_write_kreg(dd, kr_hwerrmask, + dd->cspec->hwerrmask & ~HWE_MASK(statusValidNoEop)); qib_write_kreg_port(ppd, krp_ibcctrl_a, ppd->cpspec->ibcctrl_a & ~SYM_MASK(IBCCtrlA_0, IBLinkEn)); @@ -4772,6 +4774,9 @@ static void qib_7322_mini_pcs_reset(struct qib_pportdata *ppd) qib_write_kreg_port(ppd, krp_ib_pcsconfig, val & ~reset_bits); qib_write_kreg_port(ppd, krp_ibcctrl_a, ppd->cpspec->ibcctrl_a); qib_write_kreg(dd, kr_scratch, 0ULL); + qib_write_kreg(dd, kr_hwerrclear, + SYM_MASK(HwErrClear, statusValidNoEopClear)); + qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask); } /* @@ -5624,6 +5629,8 @@ static void set_no_qsfp_atten(struct qib_devdata *dd, int change) if (ppd->port != port || !ppd->link_speed_supported) continue; ppd->cpspec->no_eep = val; + if (seth1) + ppd->cpspec->h1_val = h1; /* now change the IBC and serdes, overriding generic */ init_txdds_table(ppd, 1); any++; @@ -6064,9 +6071,9 @@ static int qib_init_7322_variables(struct qib_devdata *dd) * the "cable info" setup here. Can be overridden * in adapter-specific routines. */ - if (!(ppd->dd->flags & QIB_HAS_QSFP)) { - if (!IS_QMH(ppd->dd) && !IS_QME(ppd->dd)) - qib_devinfo(ppd->dd->pcidev, "IB%u:%u: " + if (!(dd->flags & QIB_HAS_QSFP)) { + if (!IS_QMH(dd) && !IS_QME(dd)) + qib_devinfo(dd->pcidev, "IB%u:%u: " "Unknown mezzanine card type\n", dd->unit, ppd->port); cp->h1_val = IS_QMH(dd) ? H1_FORCE_QMH : H1_FORCE_QME; @@ -6119,9 +6126,25 @@ static int qib_init_7322_variables(struct qib_devdata *dd) qib_set_ctxtcnt(dd); if (qib_wc_pat) { - ret = init_chip_wc_pat(dd, NUM_VL15_BUFS * dd->align4k); + resource_size_t vl15off; + /* + * We do not set WC on the VL15 buffers to avoid + * a rare problem with unaligned writes from + * interrupt-flushed store buffers, so we need + * to map those separately here. We can't solve + * this for the rarely used mtrr case. + */ + ret = init_chip_wc_pat(dd, 0); if (ret) goto bail; + + /* vl15 buffers start just after the 4k buffers */ + vl15off = dd->physaddr + (dd->piobufbase >> 32) + + dd->piobcnt4k * dd->align4k; + dd->piovl15base = ioremap_nocache(vl15off, + NUM_VL15_BUFS * dd->align4k); + if (!dd->piovl15base) + goto bail; } qib_7322_set_baseaddrs(dd); /* set chip access pointers now */ @@ -6932,6 +6955,8 @@ static const struct txdds_ent txdds_extra_sdr[TXDDS_EXTRA_SZ] = { { 0, 0, 0, 11 }, /* QME7342 backplane settings */ { 0, 0, 0, 11 }, /* QME7342 backplane settings */ { 0, 0, 0, 11 }, /* QME7342 backplane settings */ + { 0, 0, 0, 3 }, /* QMH7342 backplane settings */ + { 0, 0, 0, 4 }, /* QMH7342 backplane settings */ }; static const struct txdds_ent txdds_extra_ddr[TXDDS_EXTRA_SZ] = { @@ -6947,6 +6972,8 @@ static const struct txdds_ent txdds_extra_ddr[TXDDS_EXTRA_SZ] = { { 0, 0, 0, 13 }, /* QME7342 backplane settings */ { 0, 0, 0, 13 }, /* QME7342 backplane settings */ { 0, 0, 0, 13 }, /* QME7342 backplane settings */ + { 0, 0, 0, 9 }, /* QMH7342 backplane settings */ + { 0, 0, 0, 10 }, /* QMH7342 backplane settings */ }; static const struct txdds_ent txdds_extra_qdr[TXDDS_EXTRA_SZ] = { @@ -6962,6 +6989,8 @@ static const struct txdds_ent txdds_extra_qdr[TXDDS_EXTRA_SZ] = { { 0, 1, 12, 6 }, /* QME7342 backplane setting */ { 0, 1, 12, 7 }, /* QME7342 backplane setting */ { 0, 1, 12, 8 }, /* QME7342 backplane setting */ + { 0, 1, 0, 10 }, /* QMH7342 backplane settings */ + { 0, 1, 0, 12 }, /* QMH7342 backplane settings */ }; static const struct txdds_ent *get_atten_table(const struct txdds_ent *txdds, diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c index 9b40f345ac3..a873dd596e8 100644 --- a/drivers/infiniband/hw/qib/qib_init.c +++ b/drivers/infiniband/hw/qib/qib_init.c @@ -1059,7 +1059,7 @@ static int __init qlogic_ib_init(void) goto bail_dev; } - qib_cq_wq = create_workqueue("qib_cq"); + qib_cq_wq = create_singlethread_workqueue("qib_cq"); if (!qib_cq_wq) { ret = -ENOMEM; goto bail_wq; @@ -1289,8 +1289,18 @@ static int __devinit qib_init_one(struct pci_dev *pdev, if (qib_mini_init || initfail || ret) { qib_stop_timers(dd); + flush_scheduled_work(); for (pidx = 0; pidx < dd->num_pports; ++pidx) dd->f_quiet_serdes(dd->pport + pidx); + if (qib_mini_init) + goto bail; + if (!j) { + (void) qibfs_remove(dd); + qib_device_remove(dd); + } + if (!ret) + qib_unregister_ib_device(dd); + qib_postinit_cleanup(dd); if (initfail) ret = initfail; goto bail; @@ -1472,6 +1482,9 @@ int qib_setup_eagerbufs(struct qib_ctxtdata *rcd) dma_addr_t pa = rcd->rcvegrbuf_phys[chunk]; unsigned i; + /* clear for security and sanity on each use */ + memset(rcd->rcvegrbuf[chunk], 0, size); + for (i = 0; e < egrcnt && i < egrperchunk; e++, i++) { dd->f_put_tid(dd, e + egroff + (u64 __iomem *) @@ -1499,6 +1512,12 @@ bail: return -ENOMEM; } +/* + * Note: Changes to this routine should be mirrored + * for the diagnostics routine qib_remap_ioaddr32(). + * There is also related code for VL15 buffers in qib_init_7322_variables(). + * The teardown code that unmaps is in qib_pcie_ddcleanup() + */ int init_chip_wc_pat(struct qib_devdata *dd, u32 vl15buflen) { u64 __iomem *qib_kregbase = NULL; diff --git a/drivers/infiniband/hw/qib/qib_pcie.c b/drivers/infiniband/hw/qib/qib_pcie.c index c926bf4541d..7fa6e559263 100644 --- a/drivers/infiniband/hw/qib/qib_pcie.c +++ b/drivers/infiniband/hw/qib/qib_pcie.c @@ -179,6 +179,8 @@ void qib_pcie_ddcleanup(struct qib_devdata *dd) iounmap(dd->piobase); if (dd->userbase) iounmap(dd->userbase); + if (dd->piovl15base) + iounmap(dd->piovl15base); pci_disable_device(dd->pcidev); pci_release_regions(dd->pcidev); diff --git a/drivers/infiniband/hw/qib/qib_sd7220.c b/drivers/infiniband/hw/qib/qib_sd7220.c index 0aeed0e74cb..e9f9f8bc320 100644 --- a/drivers/infiniband/hw/qib/qib_sd7220.c +++ b/drivers/infiniband/hw/qib/qib_sd7220.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved. + * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation. + * All rights reserved. * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. * * This software is available to you under a choice of one of two @@ -37,10 +38,14 @@ #include <linux/pci.h> #include <linux/delay.h> +#include <linux/firmware.h> #include "qib.h" #include "qib_7220.h" +#define SD7220_FW_NAME "qlogic/sd7220.fw" +MODULE_FIRMWARE(SD7220_FW_NAME); + /* * Same as in qib_iba7220.c, but just the registers needed here. * Could move whole set to qib_7220.h, but decided better to keep @@ -102,6 +107,10 @@ static int qib_internal_presets(struct qib_devdata *dd); /* Tweak the register (CMUCTRL5) that contains the TRIMSELF controls */ static int qib_sd_trimself(struct qib_devdata *dd, int val); static int epb_access(struct qib_devdata *dd, int sdnum, int claim); +static int qib_sd7220_ib_load(struct qib_devdata *dd, + const struct firmware *fw); +static int qib_sd7220_ib_vfy(struct qib_devdata *dd, + const struct firmware *fw); /* * Below keeps track of whether the "once per power-on" initialization has @@ -110,10 +119,13 @@ static int epb_access(struct qib_devdata *dd, int sdnum, int claim); * state of the reset "pin", is no longer valid. Instead, we check for the * actual uC code having been loaded. */ -static int qib_ibsd_ucode_loaded(struct qib_pportdata *ppd) +static int qib_ibsd_ucode_loaded(struct qib_pportdata *ppd, + const struct firmware *fw) { struct qib_devdata *dd = ppd->dd; - if (!dd->cspec->serdes_first_init_done && (qib_sd7220_ib_vfy(dd) > 0)) + + if (!dd->cspec->serdes_first_init_done && + qib_sd7220_ib_vfy(dd, fw) > 0) dd->cspec->serdes_first_init_done = 1; return dd->cspec->serdes_first_init_done; } @@ -377,6 +389,7 @@ static void qib_sd_trimdone_monitor(struct qib_devdata *dd, */ int qib_sd7220_init(struct qib_devdata *dd) { + const struct firmware *fw; int ret = 1; /* default to failure */ int first_reset, was_reset; @@ -387,8 +400,15 @@ int qib_sd7220_init(struct qib_devdata *dd) qib_ibsd_reset(dd, 1); qib_sd_trimdone_monitor(dd, "Driver-reload"); } + + ret = request_firmware(&fw, SD7220_FW_NAME, &dd->pcidev->dev); + if (ret) { + qib_dev_err(dd, "Failed to load IB SERDES image\n"); + goto done; + } + /* Substitute our deduced value for was_reset */ - ret = qib_ibsd_ucode_loaded(dd->pport); + ret = qib_ibsd_ucode_loaded(dd->pport, fw); if (ret < 0) goto bail; @@ -437,13 +457,13 @@ int qib_sd7220_init(struct qib_devdata *dd) int vfy; int trim_done; - ret = qib_sd7220_ib_load(dd); + ret = qib_sd7220_ib_load(dd, fw); if (ret < 0) { qib_dev_err(dd, "Failed to load IB SERDES image\n"); goto bail; } else { /* Loaded image, try to verify */ - vfy = qib_sd7220_ib_vfy(dd); + vfy = qib_sd7220_ib_vfy(dd, fw); if (vfy != ret) { qib_dev_err(dd, "SERDES PRAM VFY failed\n"); goto bail; @@ -506,6 +526,8 @@ bail: done: /* start relock timer regardless, but start at 1 second */ set_7220_relock_poll(dd, -1); + + release_firmware(fw); return ret; } @@ -829,8 +851,8 @@ static int qib_sd7220_ram_xfer(struct qib_devdata *dd, int sdnum, u32 loc, #define PROG_CHUNK 64 -int qib_sd7220_prog_ld(struct qib_devdata *dd, int sdnum, - u8 *img, int len, int offset) +static int qib_sd7220_prog_ld(struct qib_devdata *dd, int sdnum, + const u8 *img, int len, int offset) { int cnt, sofar, req; @@ -840,7 +862,7 @@ int qib_sd7220_prog_ld(struct qib_devdata *dd, int sdnum, if (req > PROG_CHUNK) req = PROG_CHUNK; cnt = qib_sd7220_ram_xfer(dd, sdnum, offset + sofar, - img + sofar, req, 0); + (u8 *)img + sofar, req, 0); if (cnt < req) { sofar = -1; break; @@ -853,8 +875,8 @@ int qib_sd7220_prog_ld(struct qib_devdata *dd, int sdnum, #define VFY_CHUNK 64 #define SD_PRAM_ERROR_LIMIT 42 -int qib_sd7220_prog_vfy(struct qib_devdata *dd, int sdnum, - const u8 *img, int len, int offset) +static int qib_sd7220_prog_vfy(struct qib_devdata *dd, int sdnum, + const u8 *img, int len, int offset) { int cnt, sofar, req, idx, errors; unsigned char readback[VFY_CHUNK]; @@ -881,6 +903,18 @@ int qib_sd7220_prog_vfy(struct qib_devdata *dd, int sdnum, return errors ? -errors : sofar; } +static int +qib_sd7220_ib_load(struct qib_devdata *dd, const struct firmware *fw) +{ + return qib_sd7220_prog_ld(dd, IB_7220_SERDES, fw->data, fw->size, 0); +} + +static int +qib_sd7220_ib_vfy(struct qib_devdata *dd, const struct firmware *fw) +{ + return qib_sd7220_prog_vfy(dd, IB_7220_SERDES, fw->data, fw->size, 0); +} + /* * IRQ not set up at this point in init, so we poll. */ diff --git a/drivers/infiniband/hw/qib/qib_sd7220_img.c b/drivers/infiniband/hw/qib/qib_sd7220_img.c deleted file mode 100644 index a1118fbd237..00000000000 --- a/drivers/infiniband/hw/qib/qib_sd7220_img.c +++ /dev/null @@ -1,1081 +0,0 @@ -/* - * Copyright (c) 2007, 2008 QLogic Corporation. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* - * This file contains the memory image from the vendor, to be copied into - * the IB SERDES of the IBA7220 during initialization. - * The file also includes the two functions which use this image. - */ -#include <linux/pci.h> -#include <linux/delay.h> - -#include "qib.h" -#include "qib_7220.h" - -static unsigned char qib_sd7220_ib_img[] = { -/*0000*/0x02, 0x0A, 0x29, 0x02, 0x0A, 0x87, 0xE5, 0xE6, - 0x30, 0xE6, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, -/*0010*/0x00, 0xE5, 0xE2, 0x30, 0xE4, 0x04, 0x7E, 0x01, - 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x5F, 0x60, 0x08, -/*0020*/0x53, 0xF9, 0xF7, 0xE4, 0xF5, 0xFE, 0x80, 0x08, - 0x7F, 0x0A, 0x12, 0x17, 0x31, 0x12, 0x0E, 0xA2, -/*0030*/0x75, 0xFC, 0x08, 0xE4, 0xF5, 0xFD, 0xE5, 0xE7, - 0x20, 0xE7, 0x03, 0x43, 0xF9, 0x08, 0x22, 0x00, -/*0040*/0x01, 0x20, 0x11, 0x00, 0x04, 0x20, 0x00, 0x75, - 0x51, 0x01, 0xE4, 0xF5, 0x52, 0xF5, 0x53, 0xF5, -/*0050*/0x52, 0xF5, 0x7E, 0x7F, 0x04, 0x02, 0x04, 0x38, - 0xC2, 0x36, 0x05, 0x52, 0xE5, 0x52, 0xD3, 0x94, -/*0060*/0x0C, 0x40, 0x05, 0x75, 0x52, 0x01, 0xD2, 0x36, - 0x90, 0x07, 0x0C, 0x74, 0x07, 0xF0, 0xA3, 0x74, -/*0070*/0xFF, 0xF0, 0xE4, 0xF5, 0x0C, 0xA3, 0xF0, 0x90, - 0x07, 0x14, 0xF0, 0xA3, 0xF0, 0x75, 0x0B, 0x20, -/*0080*/0xF5, 0x09, 0xE4, 0xF5, 0x08, 0xE5, 0x08, 0xD3, - 0x94, 0x30, 0x40, 0x03, 0x02, 0x04, 0x04, 0x12, -/*0090*/0x00, 0x06, 0x15, 0x0B, 0xE5, 0x08, 0x70, 0x04, - 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x09, -/*00A0*/0x70, 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, - 0xEE, 0x5F, 0x60, 0x05, 0x12, 0x18, 0x71, 0xD2, -/*00B0*/0x35, 0x53, 0xE1, 0xF7, 0xE5, 0x08, 0x45, 0x09, - 0xFF, 0xE5, 0x0B, 0x25, 0xE0, 0x25, 0xE0, 0x24, -/*00C0*/0x83, 0xF5, 0x82, 0xE4, 0x34, 0x07, 0xF5, 0x83, - 0xEF, 0xF0, 0x85, 0xE2, 0x20, 0xE5, 0x52, 0xD3, -/*00D0*/0x94, 0x01, 0x40, 0x0D, 0x12, 0x19, 0xF3, 0xE0, - 0x54, 0xA0, 0x64, 0x40, 0x70, 0x03, 0x02, 0x03, -/*00E0*/0xFB, 0x53, 0xF9, 0xF8, 0x90, 0x94, 0x70, 0xE4, - 0xF0, 0xE0, 0xF5, 0x10, 0xAF, 0x09, 0x12, 0x1E, -/*00F0*/0xB3, 0xAF, 0x08, 0xEF, 0x44, 0x08, 0xF5, 0x82, - 0x75, 0x83, 0x80, 0xE0, 0xF5, 0x29, 0xEF, 0x44, -/*0100*/0x07, 0x12, 0x1A, 0x3C, 0xF5, 0x22, 0x54, 0x40, - 0xD3, 0x94, 0x00, 0x40, 0x1E, 0xE5, 0x29, 0x54, -/*0110*/0xF0, 0x70, 0x21, 0x12, 0x19, 0xF3, 0xE0, 0x44, - 0x80, 0xF0, 0xE5, 0x22, 0x54, 0x30, 0x65, 0x08, -/*0120*/0x70, 0x09, 0x12, 0x19, 0xF3, 0xE0, 0x54, 0xBF, - 0xF0, 0x80, 0x09, 0x12, 0x19, 0xF3, 0x74, 0x40, -/*0130*/0xF0, 0x02, 0x03, 0xFB, 0x12, 0x1A, 0x12, 0x75, - 0x83, 0xAE, 0x74, 0xFF, 0xF0, 0xAF, 0x08, 0x7E, -/*0140*/0x00, 0xEF, 0x44, 0x07, 0xF5, 0x82, 0xE0, 0xFD, - 0xE5, 0x0B, 0x25, 0xE0, 0x25, 0xE0, 0x24, 0x81, -/*0150*/0xF5, 0x82, 0xE4, 0x34, 0x07, 0xF5, 0x83, 0xED, - 0xF0, 0x90, 0x07, 0x0E, 0xE0, 0x04, 0xF0, 0xEF, -/*0160*/0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0x98, 0xE0, - 0xF5, 0x28, 0x12, 0x1A, 0x23, 0x40, 0x0C, 0x12, -/*0170*/0x19, 0xF3, 0xE0, 0x44, 0x01, 0x12, 0x1A, 0x32, - 0x02, 0x03, 0xF6, 0xAF, 0x08, 0x7E, 0x00, 0x74, -/*0180*/0x80, 0xCD, 0xEF, 0xCD, 0x8D, 0x82, 0xF5, 0x83, - 0xE0, 0x30, 0xE0, 0x0A, 0x12, 0x19, 0xF3, 0xE0, -/*0190*/0x44, 0x20, 0xF0, 0x02, 0x03, 0xFB, 0x12, 0x19, - 0xF3, 0xE0, 0x54, 0xDF, 0xF0, 0xEE, 0x44, 0xAE, -/*01A0*/0x12, 0x1A, 0x43, 0x30, 0xE4, 0x03, 0x02, 0x03, - 0xFB, 0x74, 0x9E, 0x12, 0x1A, 0x05, 0x20, 0xE0, -/*01B0*/0x03, 0x02, 0x03, 0xFB, 0x8F, 0x82, 0x8E, 0x83, - 0xE0, 0x20, 0xE0, 0x03, 0x02, 0x03, 0xFB, 0x12, -/*01C0*/0x19, 0xF3, 0xE0, 0x44, 0x10, 0xF0, 0xE5, 0xE3, - 0x20, 0xE7, 0x08, 0xE5, 0x08, 0x12, 0x1A, 0x3A, -/*01D0*/0x44, 0x04, 0xF0, 0xAF, 0x08, 0x7E, 0x00, 0xEF, - 0x12, 0x1A, 0x3A, 0x20, 0xE2, 0x34, 0x12, 0x19, -/*01E0*/0xF3, 0xE0, 0x44, 0x08, 0xF0, 0xE5, 0xE4, 0x30, - 0xE6, 0x04, 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00, -/*01F0*/0xE5, 0x7E, 0xC3, 0x94, 0x04, 0x50, 0x04, 0x7C, - 0x01, 0x80, 0x02, 0x7C, 0x00, 0xEC, 0x4D, 0x60, -/*0200*/0x05, 0xC2, 0x35, 0x02, 0x03, 0xFB, 0xEE, 0x44, - 0xD2, 0x12, 0x1A, 0x43, 0x44, 0x40, 0xF0, 0x02, -/*0210*/0x03, 0xFB, 0x12, 0x19, 0xF3, 0xE0, 0x54, 0xF7, - 0xF0, 0x12, 0x1A, 0x12, 0x75, 0x83, 0xD2, 0xE0, -/*0220*/0x54, 0xBF, 0xF0, 0x90, 0x07, 0x14, 0xE0, 0x04, - 0xF0, 0xE5, 0x7E, 0x70, 0x03, 0x75, 0x7E, 0x01, -/*0230*/0xAF, 0x08, 0x7E, 0x00, 0x12, 0x1A, 0x23, 0x40, - 0x12, 0x12, 0x19, 0xF3, 0xE0, 0x44, 0x01, 0x12, -/*0240*/0x19, 0xF2, 0xE0, 0x54, 0x02, 0x12, 0x1A, 0x32, - 0x02, 0x03, 0xFB, 0x12, 0x19, 0xF3, 0xE0, 0x44, -/*0250*/0x02, 0x12, 0x19, 0xF2, 0xE0, 0x54, 0xFE, 0xF0, - 0xC2, 0x35, 0xEE, 0x44, 0x8A, 0x8F, 0x82, 0xF5, -/*0260*/0x83, 0xE0, 0xF5, 0x17, 0x54, 0x8F, 0x44, 0x40, - 0xF0, 0x74, 0x90, 0xFC, 0xE5, 0x08, 0x44, 0x07, -/*0270*/0xFD, 0xF5, 0x82, 0x8C, 0x83, 0xE0, 0x54, 0x3F, - 0x90, 0x07, 0x02, 0xF0, 0xE0, 0x54, 0xC0, 0x8D, -/*0280*/0x82, 0x8C, 0x83, 0xF0, 0x74, 0x92, 0x12, 0x1A, - 0x05, 0x90, 0x07, 0x03, 0x12, 0x1A, 0x19, 0x74, -/*0290*/0x82, 0x12, 0x1A, 0x05, 0x90, 0x07, 0x04, 0x12, - 0x1A, 0x19, 0x74, 0xB4, 0x12, 0x1A, 0x05, 0x90, -/*02A0*/0x07, 0x05, 0x12, 0x1A, 0x19, 0x74, 0x94, 0xFE, - 0xE5, 0x08, 0x44, 0x06, 0x12, 0x1A, 0x0A, 0xF5, -/*02B0*/0x10, 0x30, 0xE0, 0x04, 0xD2, 0x37, 0x80, 0x02, - 0xC2, 0x37, 0xE5, 0x10, 0x54, 0x7F, 0x8F, 0x82, -/*02C0*/0x8E, 0x83, 0xF0, 0x30, 0x44, 0x30, 0x12, 0x1A, - 0x03, 0x54, 0x80, 0xD3, 0x94, 0x00, 0x40, 0x04, -/*02D0*/0xD2, 0x39, 0x80, 0x02, 0xC2, 0x39, 0x8F, 0x82, - 0x8E, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0x12, 0x1A, -/*02E0*/0x03, 0x54, 0x40, 0xD3, 0x94, 0x00, 0x40, 0x04, - 0xD2, 0x3A, 0x80, 0x02, 0xC2, 0x3A, 0x8F, 0x82, -/*02F0*/0x8E, 0x83, 0xE0, 0x44, 0x40, 0xF0, 0x74, 0x92, - 0xFE, 0xE5, 0x08, 0x44, 0x06, 0x12, 0x1A, 0x0A, -/*0300*/0x30, 0xE7, 0x04, 0xD2, 0x38, 0x80, 0x02, 0xC2, - 0x38, 0x8F, 0x82, 0x8E, 0x83, 0xE0, 0x54, 0x7F, -/*0310*/0xF0, 0x12, 0x1E, 0x46, 0xE4, 0xF5, 0x0A, 0x20, - 0x03, 0x02, 0x80, 0x03, 0x30, 0x43, 0x03, 0x12, -/*0320*/0x19, 0x95, 0x20, 0x02, 0x02, 0x80, 0x03, 0x30, - 0x42, 0x03, 0x12, 0x0C, 0x8F, 0x30, 0x30, 0x06, -/*0330*/0x12, 0x19, 0x95, 0x12, 0x0C, 0x8F, 0x12, 0x0D, - 0x47, 0x12, 0x19, 0xF3, 0xE0, 0x54, 0xFB, 0xF0, -/*0340*/0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x40, 0x46, 0x43, - 0xE1, 0x08, 0x12, 0x19, 0xF3, 0xE0, 0x44, 0x04, -/*0350*/0xF0, 0xE5, 0xE4, 0x20, 0xE7, 0x2A, 0x12, 0x1A, - 0x12, 0x75, 0x83, 0xD2, 0xE0, 0x54, 0x08, 0xD3, -/*0360*/0x94, 0x00, 0x40, 0x04, 0x7F, 0x01, 0x80, 0x02, - 0x7F, 0x00, 0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x40, -/*0370*/0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEF, - 0x5E, 0x60, 0x05, 0x12, 0x1D, 0xD7, 0x80, 0x17, -/*0380*/0x12, 0x1A, 0x12, 0x75, 0x83, 0xD2, 0xE0, 0x44, - 0x08, 0xF0, 0x02, 0x03, 0xFB, 0x12, 0x1A, 0x12, -/*0390*/0x75, 0x83, 0xD2, 0xE0, 0x54, 0xF7, 0xF0, 0x12, - 0x1E, 0x46, 0x7F, 0x08, 0x12, 0x17, 0x31, 0x74, -/*03A0*/0x8E, 0xFE, 0x12, 0x1A, 0x12, 0x8E, 0x83, 0xE0, - 0xF5, 0x10, 0x54, 0xFE, 0xF0, 0xE5, 0x10, 0x44, -/*03B0*/0x01, 0xFF, 0xE5, 0x08, 0xFD, 0xED, 0x44, 0x07, - 0xF5, 0x82, 0xEF, 0xF0, 0xE5, 0x10, 0x54, 0xFE, -/*03C0*/0xFF, 0xED, 0x44, 0x07, 0xF5, 0x82, 0xEF, 0x12, - 0x1A, 0x11, 0x75, 0x83, 0x86, 0xE0, 0x44, 0x10, -/*03D0*/0x12, 0x1A, 0x11, 0xE0, 0x44, 0x10, 0xF0, 0x12, - 0x19, 0xF3, 0xE0, 0x54, 0xFD, 0x44, 0x01, 0xFF, -/*03E0*/0x12, 0x19, 0xF3, 0xEF, 0x12, 0x1A, 0x32, 0x30, - 0x32, 0x0C, 0xE5, 0x08, 0x44, 0x08, 0xF5, 0x82, -/*03F0*/0x75, 0x83, 0x82, 0x74, 0x05, 0xF0, 0xAF, 0x0B, - 0x12, 0x18, 0xD7, 0x74, 0x10, 0x25, 0x08, 0xF5, -/*0400*/0x08, 0x02, 0x00, 0x85, 0x05, 0x09, 0xE5, 0x09, - 0xD3, 0x94, 0x07, 0x50, 0x03, 0x02, 0x00, 0x82, -/*0410*/0xE5, 0x7E, 0xD3, 0x94, 0x00, 0x40, 0x04, 0x7F, - 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x7E, 0xC3, -/*0420*/0x94, 0xFA, 0x50, 0x04, 0x7E, 0x01, 0x80, 0x02, - 0x7E, 0x00, 0xEE, 0x5F, 0x60, 0x02, 0x05, 0x7E, -/*0430*/0x30, 0x35, 0x0B, 0x43, 0xE1, 0x01, 0x7F, 0x09, - 0x12, 0x17, 0x31, 0x02, 0x00, 0x58, 0x53, 0xE1, -/*0440*/0xFE, 0x02, 0x00, 0x58, 0x8E, 0x6A, 0x8F, 0x6B, - 0x8C, 0x6C, 0x8D, 0x6D, 0x75, 0x6E, 0x01, 0x75, -/*0450*/0x6F, 0x01, 0x75, 0x70, 0x01, 0xE4, 0xF5, 0x73, - 0xF5, 0x74, 0xF5, 0x75, 0x90, 0x07, 0x2F, 0xF0, -/*0460*/0xF5, 0x3C, 0xF5, 0x3E, 0xF5, 0x46, 0xF5, 0x47, - 0xF5, 0x3D, 0xF5, 0x3F, 0xF5, 0x6F, 0xE5, 0x6F, -/*0470*/0x70, 0x0F, 0xE5, 0x6B, 0x45, 0x6A, 0x12, 0x07, - 0x2A, 0x75, 0x83, 0x80, 0x74, 0x3A, 0xF0, 0x80, -/*0480*/0x09, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x80, 0x74, - 0x1A, 0xF0, 0xE4, 0xF5, 0x6E, 0xC3, 0x74, 0x3F, -/*0490*/0x95, 0x6E, 0xFF, 0x12, 0x08, 0x65, 0x75, 0x83, - 0x82, 0xEF, 0xF0, 0x12, 0x1A, 0x4D, 0x12, 0x08, -/*04A0*/0xC6, 0xE5, 0x33, 0xF0, 0x12, 0x08, 0xFA, 0x12, - 0x08, 0xB1, 0x40, 0xE1, 0xE5, 0x6F, 0x70, 0x0B, -/*04B0*/0x12, 0x07, 0x2A, 0x75, 0x83, 0x80, 0x74, 0x36, - 0xF0, 0x80, 0x09, 0x12, 0x07, 0x2A, 0x75, 0x83, -/*04C0*/0x80, 0x74, 0x16, 0xF0, 0x75, 0x6E, 0x01, 0x12, - 0x07, 0x2A, 0x75, 0x83, 0xB4, 0xE5, 0x6E, 0xF0, -/*04D0*/0x12, 0x1A, 0x4D, 0x74, 0x3F, 0x25, 0x6E, 0xF5, - 0x82, 0xE4, 0x34, 0x00, 0xF5, 0x83, 0xE5, 0x33, -/*04E0*/0xF0, 0x74, 0xBF, 0x25, 0x6E, 0xF5, 0x82, 0xE4, - 0x34, 0x00, 0x12, 0x08, 0xB1, 0x40, 0xD8, 0xE4, -/*04F0*/0xF5, 0x70, 0xF5, 0x46, 0xF5, 0x47, 0xF5, 0x6E, - 0x12, 0x08, 0xFA, 0xF5, 0x83, 0xE0, 0xFE, 0x12, -/*0500*/0x08, 0xC6, 0xE0, 0x7C, 0x00, 0x24, 0x00, 0xFF, - 0xEC, 0x3E, 0xFE, 0xAD, 0x3B, 0xD3, 0xEF, 0x9D, -/*0510*/0xEE, 0x9C, 0x50, 0x04, 0x7B, 0x01, 0x80, 0x02, - 0x7B, 0x00, 0xE5, 0x70, 0x70, 0x04, 0x7A, 0x01, -/*0520*/0x80, 0x02, 0x7A, 0x00, 0xEB, 0x5A, 0x60, 0x06, - 0x85, 0x6E, 0x46, 0x75, 0x70, 0x01, 0xD3, 0xEF, -/*0530*/0x9D, 0xEE, 0x9C, 0x50, 0x04, 0x7F, 0x01, 0x80, - 0x02, 0x7F, 0x00, 0xE5, 0x70, 0xB4, 0x01, 0x04, -/*0540*/0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEF, 0x5E, - 0x60, 0x03, 0x85, 0x6E, 0x47, 0x05, 0x6E, 0xE5, -/*0550*/0x6E, 0x64, 0x7F, 0x70, 0xA3, 0xE5, 0x46, 0x60, - 0x05, 0xE5, 0x47, 0xB4, 0x7E, 0x03, 0x85, 0x46, -/*0560*/0x47, 0xE5, 0x6F, 0x70, 0x08, 0x85, 0x46, 0x76, - 0x85, 0x47, 0x77, 0x80, 0x0E, 0xC3, 0x74, 0x7F, -/*0570*/0x95, 0x46, 0xF5, 0x78, 0xC3, 0x74, 0x7F, 0x95, - 0x47, 0xF5, 0x79, 0xE5, 0x6F, 0x70, 0x37, 0xE5, -/*0580*/0x46, 0x65, 0x47, 0x70, 0x0C, 0x75, 0x73, 0x01, - 0x75, 0x74, 0x01, 0xF5, 0x3C, 0xF5, 0x3D, 0x80, -/*0590*/0x35, 0xE4, 0xF5, 0x4E, 0xC3, 0xE5, 0x47, 0x95, - 0x46, 0xF5, 0x3C, 0xC3, 0x13, 0xF5, 0x71, 0x25, -/*05A0*/0x46, 0xF5, 0x72, 0xC3, 0x94, 0x3F, 0x40, 0x05, - 0xE4, 0xF5, 0x3D, 0x80, 0x40, 0xC3, 0x74, 0x3F, -/*05B0*/0x95, 0x72, 0xF5, 0x3D, 0x80, 0x37, 0xE5, 0x46, - 0x65, 0x47, 0x70, 0x0F, 0x75, 0x73, 0x01, 0x75, -/*05C0*/0x75, 0x01, 0xF5, 0x3E, 0xF5, 0x3F, 0x75, 0x4E, - 0x01, 0x80, 0x22, 0xE4, 0xF5, 0x4E, 0xC3, 0xE5, -/*05D0*/0x47, 0x95, 0x46, 0xF5, 0x3E, 0xC3, 0x13, 0xF5, - 0x71, 0x25, 0x46, 0xF5, 0x72, 0xD3, 0x94, 0x3F, -/*05E0*/0x50, 0x05, 0xE4, 0xF5, 0x3F, 0x80, 0x06, 0xE5, - 0x72, 0x24, 0xC1, 0xF5, 0x3F, 0x05, 0x6F, 0xE5, -/*05F0*/0x6F, 0xC3, 0x94, 0x02, 0x50, 0x03, 0x02, 0x04, - 0x6E, 0xE5, 0x6D, 0x45, 0x6C, 0x70, 0x02, 0x80, -/*0600*/0x04, 0xE5, 0x74, 0x45, 0x75, 0x90, 0x07, 0x2F, - 0xF0, 0x7F, 0x01, 0xE5, 0x3E, 0x60, 0x04, 0xE5, -/*0610*/0x3C, 0x70, 0x14, 0xE4, 0xF5, 0x3C, 0xF5, 0x3D, - 0xF5, 0x3E, 0xF5, 0x3F, 0x12, 0x08, 0xD2, 0x70, -/*0620*/0x04, 0xF0, 0x02, 0x06, 0xA4, 0x80, 0x7A, 0xE5, - 0x3C, 0xC3, 0x95, 0x3E, 0x40, 0x07, 0xE5, 0x3C, -/*0630*/0x95, 0x3E, 0xFF, 0x80, 0x06, 0xC3, 0xE5, 0x3E, - 0x95, 0x3C, 0xFF, 0xE5, 0x76, 0xD3, 0x95, 0x79, -/*0640*/0x40, 0x05, 0x85, 0x76, 0x7A, 0x80, 0x03, 0x85, - 0x79, 0x7A, 0xE5, 0x77, 0xC3, 0x95, 0x78, 0x50, -/*0650*/0x05, 0x85, 0x77, 0x7B, 0x80, 0x03, 0x85, 0x78, - 0x7B, 0xE5, 0x7B, 0xD3, 0x95, 0x7A, 0x40, 0x30, -/*0660*/0xE5, 0x7B, 0x95, 0x7A, 0xF5, 0x3C, 0xF5, 0x3E, - 0xC3, 0xE5, 0x7B, 0x95, 0x7A, 0x90, 0x07, 0x19, -/*0670*/0xF0, 0xE5, 0x3C, 0xC3, 0x13, 0xF5, 0x71, 0x25, - 0x7A, 0xF5, 0x72, 0xC3, 0x94, 0x3F, 0x40, 0x05, -/*0680*/0xE4, 0xF5, 0x3D, 0x80, 0x1F, 0xC3, 0x74, 0x3F, - 0x95, 0x72, 0xF5, 0x3D, 0xF5, 0x3F, 0x80, 0x14, -/*0690*/0xE4, 0xF5, 0x3C, 0xF5, 0x3E, 0x90, 0x07, 0x19, - 0xF0, 0x12, 0x08, 0xD2, 0x70, 0x03, 0xF0, 0x80, -/*06A0*/0x03, 0x74, 0x01, 0xF0, 0x12, 0x08, 0x65, 0x75, - 0x83, 0xD0, 0xE0, 0x54, 0x0F, 0xFE, 0xAD, 0x3C, -/*06B0*/0x70, 0x02, 0x7E, 0x07, 0xBE, 0x0F, 0x02, 0x7E, - 0x80, 0xEE, 0xFB, 0xEF, 0xD3, 0x9B, 0x74, 0x80, -/*06C0*/0xF8, 0x98, 0x40, 0x1F, 0xE4, 0xF5, 0x3C, 0xF5, - 0x3E, 0x12, 0x08, 0xD2, 0x70, 0x03, 0xF0, 0x80, -/*06D0*/0x12, 0x74, 0x01, 0xF0, 0xE5, 0x08, 0xFB, 0xEB, - 0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0xD2, 0xE0, -/*06E0*/0x44, 0x10, 0xF0, 0xE5, 0x08, 0xFB, 0xEB, 0x44, - 0x09, 0xF5, 0x82, 0x75, 0x83, 0x9E, 0xED, 0xF0, -/*06F0*/0xEB, 0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0xCA, - 0xED, 0xF0, 0x12, 0x08, 0x65, 0x75, 0x83, 0xCC, -/*0700*/0xEF, 0xF0, 0x22, 0xE5, 0x08, 0x44, 0x07, 0xF5, - 0x82, 0x75, 0x83, 0xBC, 0xE0, 0x54, 0xF0, 0xF0, -/*0710*/0xE5, 0x08, 0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, - 0xBE, 0xE0, 0x54, 0xF0, 0xF0, 0xE5, 0x08, 0x44, -/*0720*/0x07, 0xF5, 0x82, 0x75, 0x83, 0xC0, 0xE0, 0x54, - 0xF0, 0xF0, 0xE5, 0x08, 0x44, 0x07, 0xF5, 0x82, -/*0730*/0x22, 0xF0, 0x90, 0x07, 0x28, 0xE0, 0xFE, 0xA3, - 0xE0, 0xF5, 0x82, 0x8E, 0x83, 0x22, 0x85, 0x42, -/*0740*/0x42, 0x85, 0x41, 0x41, 0x85, 0x40, 0x40, 0x74, - 0xC0, 0x2F, 0xF5, 0x82, 0x74, 0x02, 0x3E, 0xF5, -/*0750*/0x83, 0xE5, 0x42, 0xF0, 0x74, 0xE0, 0x2F, 0xF5, - 0x82, 0x74, 0x02, 0x3E, 0xF5, 0x83, 0x22, 0xE5, -/*0760*/0x42, 0x29, 0xFD, 0xE4, 0x33, 0xFC, 0xE5, 0x3C, - 0xC3, 0x9D, 0xEC, 0x64, 0x80, 0xF8, 0x74, 0x80, -/*0770*/0x98, 0x22, 0xF5, 0x83, 0xE0, 0x90, 0x07, 0x22, - 0x54, 0x1F, 0xFD, 0xE0, 0xFA, 0xA3, 0xE0, 0xF5, -/*0780*/0x82, 0x8A, 0x83, 0xED, 0xF0, 0x22, 0x90, 0x07, - 0x22, 0xE0, 0xFC, 0xA3, 0xE0, 0xF5, 0x82, 0x8C, -/*0790*/0x83, 0x22, 0x90, 0x07, 0x24, 0xFF, 0xED, 0x44, - 0x07, 0xCF, 0xF0, 0xA3, 0xEF, 0xF0, 0x22, 0x85, -/*07A0*/0x38, 0x38, 0x85, 0x39, 0x39, 0x85, 0x3A, 0x3A, - 0x74, 0xC0, 0x2F, 0xF5, 0x82, 0x74, 0x02, 0x3E, -/*07B0*/0xF5, 0x83, 0x22, 0x90, 0x07, 0x26, 0xFF, 0xED, - 0x44, 0x07, 0xCF, 0xF0, 0xA3, 0xEF, 0xF0, 0x22, -/*07C0*/0xF0, 0x74, 0xA0, 0x2F, 0xF5, 0x82, 0x74, 0x02, - 0x3E, 0xF5, 0x83, 0x22, 0x74, 0xC0, 0x25, 0x11, -/*07D0*/0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0x22, - 0x74, 0x00, 0x25, 0x11, 0xF5, 0x82, 0xE4, 0x34, -/*07E0*/0x02, 0xF5, 0x83, 0x22, 0x74, 0x60, 0x25, 0x11, - 0xF5, 0x82, 0xE4, 0x34, 0x03, 0xF5, 0x83, 0x22, -/*07F0*/0x74, 0x80, 0x25, 0x11, 0xF5, 0x82, 0xE4, 0x34, - 0x03, 0xF5, 0x83, 0x22, 0x74, 0xE0, 0x25, 0x11, -/*0800*/0xF5, 0x82, 0xE4, 0x34, 0x03, 0xF5, 0x83, 0x22, - 0x74, 0x40, 0x25, 0x11, 0xF5, 0x82, 0xE4, 0x34, -/*0810*/0x06, 0xF5, 0x83, 0x22, 0x74, 0x80, 0x2F, 0xF5, - 0x82, 0x74, 0x02, 0x3E, 0xF5, 0x83, 0x22, 0xAF, -/*0820*/0x08, 0x7E, 0x00, 0xEF, 0x44, 0x07, 0xF5, 0x82, - 0x22, 0xF5, 0x83, 0xE5, 0x82, 0x44, 0x07, 0xF5, -/*0830*/0x82, 0xE5, 0x40, 0xF0, 0x22, 0x74, 0x40, 0x25, - 0x11, 0xF5, 0x82, 0xE4, 0x34, 0x02, 0xF5, 0x83, -/*0840*/0x22, 0x74, 0xC0, 0x25, 0x11, 0xF5, 0x82, 0xE4, - 0x34, 0x03, 0xF5, 0x83, 0x22, 0x74, 0x00, 0x25, -/*0850*/0x11, 0xF5, 0x82, 0xE4, 0x34, 0x06, 0xF5, 0x83, - 0x22, 0x74, 0x20, 0x25, 0x11, 0xF5, 0x82, 0xE4, -/*0860*/0x34, 0x06, 0xF5, 0x83, 0x22, 0xE5, 0x08, 0xFD, - 0xED, 0x44, 0x07, 0xF5, 0x82, 0x22, 0xE5, 0x41, -/*0870*/0xF0, 0xE5, 0x65, 0x64, 0x01, 0x45, 0x64, 0x22, - 0x7E, 0x00, 0xFB, 0x7A, 0x00, 0xFD, 0x7C, 0x00, -/*0880*/0x22, 0x74, 0x20, 0x25, 0x11, 0xF5, 0x82, 0xE4, - 0x34, 0x02, 0x22, 0x74, 0xA0, 0x25, 0x11, 0xF5, -/*0890*/0x82, 0xE4, 0x34, 0x03, 0x22, 0x85, 0x3E, 0x42, - 0x85, 0x3F, 0x41, 0x8F, 0x40, 0x22, 0x85, 0x3C, -/*08A0*/0x42, 0x85, 0x3D, 0x41, 0x8F, 0x40, 0x22, 0x75, - 0x45, 0x3F, 0x90, 0x07, 0x20, 0xE4, 0xF0, 0xA3, -/*08B0*/0x22, 0xF5, 0x83, 0xE5, 0x32, 0xF0, 0x05, 0x6E, - 0xE5, 0x6E, 0xC3, 0x94, 0x40, 0x22, 0xF0, 0xE5, -/*08C0*/0x08, 0x44, 0x06, 0xF5, 0x82, 0x22, 0x74, 0x00, - 0x25, 0x6E, 0xF5, 0x82, 0xE4, 0x34, 0x00, 0xF5, -/*08D0*/0x83, 0x22, 0xE5, 0x6D, 0x45, 0x6C, 0x90, 0x07, - 0x2F, 0x22, 0xE4, 0xF9, 0xE5, 0x3C, 0xD3, 0x95, -/*08E0*/0x3E, 0x22, 0x74, 0x80, 0x2E, 0xF5, 0x82, 0xE4, - 0x34, 0x02, 0xF5, 0x83, 0xE0, 0x22, 0x74, 0xA0, -/*08F0*/0x2E, 0xF5, 0x82, 0xE4, 0x34, 0x02, 0xF5, 0x83, - 0xE0, 0x22, 0x74, 0x80, 0x25, 0x6E, 0xF5, 0x82, -/*0900*/0xE4, 0x34, 0x00, 0x22, 0x25, 0x42, 0xFD, 0xE4, - 0x33, 0xFC, 0x22, 0x85, 0x42, 0x42, 0x85, 0x41, -/*0910*/0x41, 0x85, 0x40, 0x40, 0x22, 0xED, 0x4C, 0x60, - 0x03, 0x02, 0x09, 0xE5, 0xEF, 0x4E, 0x70, 0x37, -/*0920*/0x90, 0x07, 0x26, 0x12, 0x07, 0x89, 0xE0, 0xFD, - 0x12, 0x07, 0xCC, 0xED, 0xF0, 0x90, 0x07, 0x28, -/*0930*/0x12, 0x07, 0x89, 0xE0, 0xFD, 0x12, 0x07, 0xD8, - 0xED, 0xF0, 0x12, 0x07, 0x86, 0xE0, 0x54, 0x1F, -/*0940*/0xFD, 0x12, 0x08, 0x81, 0xF5, 0x83, 0xED, 0xF0, - 0x90, 0x07, 0x24, 0x12, 0x07, 0x89, 0xE0, 0x54, -/*0950*/0x1F, 0xFD, 0x12, 0x08, 0x35, 0xED, 0xF0, 0xEF, - 0x64, 0x04, 0x4E, 0x70, 0x37, 0x90, 0x07, 0x26, -/*0960*/0x12, 0x07, 0x89, 0xE0, 0xFD, 0x12, 0x07, 0xE4, - 0xED, 0xF0, 0x90, 0x07, 0x28, 0x12, 0x07, 0x89, -/*0970*/0xE0, 0xFD, 0x12, 0x07, 0xF0, 0xED, 0xF0, 0x12, - 0x07, 0x86, 0xE0, 0x54, 0x1F, 0xFD, 0x12, 0x08, -/*0980*/0x8B, 0xF5, 0x83, 0xED, 0xF0, 0x90, 0x07, 0x24, - 0x12, 0x07, 0x89, 0xE0, 0x54, 0x1F, 0xFD, 0x12, -/*0990*/0x08, 0x41, 0xED, 0xF0, 0xEF, 0x64, 0x01, 0x4E, - 0x70, 0x04, 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00, -/*09A0*/0xEF, 0x64, 0x02, 0x4E, 0x70, 0x04, 0x7F, 0x01, - 0x80, 0x02, 0x7F, 0x00, 0xEF, 0x4D, 0x60, 0x78, -/*09B0*/0x90, 0x07, 0x26, 0x12, 0x07, 0x35, 0xE0, 0xFF, - 0x12, 0x07, 0xFC, 0xEF, 0x12, 0x07, 0x31, 0xE0, -/*09C0*/0xFF, 0x12, 0x08, 0x08, 0xEF, 0xF0, 0x90, 0x07, - 0x22, 0x12, 0x07, 0x35, 0xE0, 0x54, 0x1F, 0xFF, -/*09D0*/0x12, 0x08, 0x4D, 0xEF, 0xF0, 0x90, 0x07, 0x24, - 0x12, 0x07, 0x35, 0xE0, 0x54, 0x1F, 0xFF, 0x12, -/*09E0*/0x08, 0x59, 0xEF, 0xF0, 0x22, 0x12, 0x07, 0xCC, - 0xE4, 0xF0, 0x12, 0x07, 0xD8, 0xE4, 0xF0, 0x12, -/*09F0*/0x08, 0x81, 0xF5, 0x83, 0xE4, 0xF0, 0x12, 0x08, - 0x35, 0x74, 0x14, 0xF0, 0x12, 0x07, 0xE4, 0xE4, -/*0A00*/0xF0, 0x12, 0x07, 0xF0, 0xE4, 0xF0, 0x12, 0x08, - 0x8B, 0xF5, 0x83, 0xE4, 0xF0, 0x12, 0x08, 0x41, -/*0A10*/0x74, 0x14, 0xF0, 0x12, 0x07, 0xFC, 0xE4, 0xF0, - 0x12, 0x08, 0x08, 0xE4, 0xF0, 0x12, 0x08, 0x4D, -/*0A20*/0xE4, 0xF0, 0x12, 0x08, 0x59, 0x74, 0x14, 0xF0, - 0x22, 0x53, 0xF9, 0xF7, 0x75, 0xFC, 0x10, 0xE4, -/*0A30*/0xF5, 0xFD, 0x75, 0xFE, 0x30, 0xF5, 0xFF, 0xE5, - 0xE7, 0x20, 0xE7, 0x03, 0x43, 0xF9, 0x08, 0xE5, -/*0A40*/0xE6, 0x20, 0xE7, 0x0B, 0x78, 0xFF, 0xE4, 0xF6, - 0xD8, 0xFD, 0x53, 0xE6, 0xFE, 0x80, 0x09, 0x78, -/*0A50*/0x08, 0xE4, 0xF6, 0xD8, 0xFD, 0x53, 0xE6, 0xFE, - 0x75, 0x81, 0x80, 0xE4, 0xF5, 0xA8, 0xD2, 0xA8, -/*0A60*/0xC2, 0xA9, 0xD2, 0xAF, 0xE5, 0xE2, 0x20, 0xE5, - 0x05, 0x20, 0xE6, 0x02, 0x80, 0x03, 0x43, 0xE1, -/*0A70*/0x02, 0xE5, 0xE2, 0x20, 0xE0, 0x0E, 0x90, 0x00, - 0x00, 0x7F, 0x00, 0x7E, 0x08, 0xE4, 0xF0, 0xA3, -/*0A80*/0xDF, 0xFC, 0xDE, 0xFA, 0x02, 0x0A, 0xDB, 0x43, - 0xFA, 0x01, 0xC0, 0xE0, 0xC0, 0xF0, 0xC0, 0x83, -/*0A90*/0xC0, 0x82, 0xC0, 0xD0, 0x12, 0x1C, 0xE7, 0xD0, - 0xD0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xF0, 0xD0, -/*0AA0*/0xE0, 0x53, 0xFA, 0xFE, 0x32, 0x02, 0x1B, 0x55, - 0xE4, 0x93, 0xA3, 0xF8, 0xE4, 0x93, 0xA3, 0xF6, -/*0AB0*/0x08, 0xDF, 0xF9, 0x80, 0x29, 0xE4, 0x93, 0xA3, - 0xF8, 0x54, 0x07, 0x24, 0x0C, 0xC8, 0xC3, 0x33, -/*0AC0*/0xC4, 0x54, 0x0F, 0x44, 0x20, 0xC8, 0x83, 0x40, - 0x04, 0xF4, 0x56, 0x80, 0x01, 0x46, 0xF6, 0xDF, -/*0AD0*/0xE4, 0x80, 0x0B, 0x01, 0x02, 0x04, 0x08, 0x10, - 0x20, 0x40, 0x80, 0x90, 0x00, 0x3F, 0xE4, 0x7E, -/*0AE0*/0x01, 0x93, 0x60, 0xC1, 0xA3, 0xFF, 0x54, 0x3F, - 0x30, 0xE5, 0x09, 0x54, 0x1F, 0xFE, 0xE4, 0x93, -/*0AF0*/0xA3, 0x60, 0x01, 0x0E, 0xCF, 0x54, 0xC0, 0x25, - 0xE0, 0x60, 0xAD, 0x40, 0xB8, 0x80, 0xFE, 0x8C, -/*0B00*/0x64, 0x8D, 0x65, 0x8A, 0x66, 0x8B, 0x67, 0xE4, - 0xF5, 0x69, 0xEF, 0x4E, 0x70, 0x03, 0x02, 0x1D, -/*0B10*/0x55, 0xE4, 0xF5, 0x68, 0xE5, 0x67, 0x45, 0x66, - 0x70, 0x32, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x90, -/*0B20*/0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, 0xE4, - 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0xE4, 0x12, -/*0B30*/0x08, 0x70, 0x70, 0x29, 0x12, 0x07, 0x2A, 0x75, - 0x83, 0x92, 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, -/*0B40*/0xC6, 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC8, - 0xE4, 0xF0, 0x80, 0x11, 0x90, 0x07, 0x26, 0x12, -/*0B50*/0x07, 0x35, 0xE4, 0x12, 0x08, 0x70, 0x70, 0x05, - 0x12, 0x07, 0x32, 0xE4, 0xF0, 0x12, 0x1D, 0x55, -/*0B60*/0x12, 0x1E, 0xBF, 0xE5, 0x67, 0x45, 0x66, 0x70, - 0x33, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x90, 0xE5, -/*0B70*/0x41, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, 0xE5, - 0x41, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0x12, -/*0B80*/0x08, 0x6E, 0x70, 0x29, 0x12, 0x07, 0x2A, 0x75, - 0x83, 0x92, 0xE5, 0x40, 0x12, 0x07, 0x29, 0x75, -/*0B90*/0x83, 0xC6, 0xE5, 0x40, 0x12, 0x07, 0x29, 0x75, - 0x83, 0xC8, 0x80, 0x0E, 0x90, 0x07, 0x26, 0x12, -/*0BA0*/0x07, 0x35, 0x12, 0x08, 0x6E, 0x70, 0x06, 0x12, - 0x07, 0x32, 0xE5, 0x40, 0xF0, 0xAF, 0x69, 0x7E, -/*0BB0*/0x00, 0xAD, 0x67, 0xAC, 0x66, 0x12, 0x04, 0x44, - 0x12, 0x07, 0x2A, 0x75, 0x83, 0xCA, 0xE0, 0xD3, -/*0BC0*/0x94, 0x00, 0x50, 0x0C, 0x05, 0x68, 0xE5, 0x68, - 0xC3, 0x94, 0x05, 0x50, 0x03, 0x02, 0x0B, 0x14, -/*0BD0*/0x22, 0x8C, 0x60, 0x8D, 0x61, 0x12, 0x08, 0xDA, - 0x74, 0x20, 0x40, 0x0D, 0x2F, 0xF5, 0x82, 0x74, -/*0BE0*/0x03, 0x3E, 0xF5, 0x83, 0xE5, 0x3E, 0xF0, 0x80, - 0x0B, 0x2F, 0xF5, 0x82, 0x74, 0x03, 0x3E, 0xF5, -/*0BF0*/0x83, 0xE5, 0x3C, 0xF0, 0xE5, 0x3C, 0xD3, 0x95, - 0x3E, 0x40, 0x3C, 0xE5, 0x61, 0x45, 0x60, 0x70, -/*0C00*/0x10, 0xE9, 0x12, 0x09, 0x04, 0xE5, 0x3E, 0x12, - 0x07, 0x68, 0x40, 0x3B, 0x12, 0x08, 0x95, 0x80, -/*0C10*/0x18, 0xE5, 0x3E, 0xC3, 0x95, 0x38, 0x40, 0x1D, - 0x85, 0x3E, 0x38, 0xE5, 0x3E, 0x60, 0x05, 0x85, -/*0C20*/0x3F, 0x39, 0x80, 0x03, 0x85, 0x39, 0x39, 0x8F, - 0x3A, 0x12, 0x08, 0x14, 0xE5, 0x3E, 0x12, 0x07, -/*0C30*/0xC0, 0xE5, 0x3F, 0xF0, 0x22, 0x80, 0x43, 0xE5, - 0x61, 0x45, 0x60, 0x70, 0x19, 0x12, 0x07, 0x5F, -/*0C40*/0x40, 0x05, 0x12, 0x08, 0x9E, 0x80, 0x27, 0x12, - 0x09, 0x0B, 0x12, 0x08, 0x14, 0xE5, 0x42, 0x12, -/*0C50*/0x07, 0xC0, 0xE5, 0x41, 0xF0, 0x22, 0xE5, 0x3C, - 0xC3, 0x95, 0x38, 0x40, 0x1D, 0x85, 0x3C, 0x38, -/*0C60*/0xE5, 0x3C, 0x60, 0x05, 0x85, 0x3D, 0x39, 0x80, - 0x03, 0x85, 0x39, 0x39, 0x8F, 0x3A, 0x12, 0x08, -/*0C70*/0x14, 0xE5, 0x3C, 0x12, 0x07, 0xC0, 0xE5, 0x3D, - 0xF0, 0x22, 0x85, 0x38, 0x38, 0x85, 0x39, 0x39, -/*0C80*/0x85, 0x3A, 0x3A, 0x12, 0x08, 0x14, 0xE5, 0x38, - 0x12, 0x07, 0xC0, 0xE5, 0x39, 0xF0, 0x22, 0x7F, -/*0C90*/0x06, 0x12, 0x17, 0x31, 0x12, 0x1D, 0x23, 0x12, - 0x0E, 0x04, 0x12, 0x0E, 0x33, 0xE0, 0x44, 0x0A, -/*0CA0*/0xF0, 0x74, 0x8E, 0xFE, 0x12, 0x0E, 0x04, 0x12, - 0x0E, 0x0B, 0xEF, 0xF0, 0xE5, 0x28, 0x30, 0xE5, -/*0CB0*/0x03, 0xD3, 0x80, 0x01, 0xC3, 0x40, 0x05, 0x75, - 0x14, 0x20, 0x80, 0x03, 0x75, 0x14, 0x08, 0x12, -/*0CC0*/0x0E, 0x04, 0x75, 0x83, 0x8A, 0xE5, 0x14, 0xF0, - 0xB4, 0xFF, 0x05, 0x75, 0x12, 0x80, 0x80, 0x06, -/*0CD0*/0xE5, 0x14, 0xC3, 0x13, 0xF5, 0x12, 0xE4, 0xF5, - 0x16, 0xF5, 0x7F, 0x12, 0x19, 0x36, 0x12, 0x13, -/*0CE0*/0xA3, 0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x50, 0x09, - 0x05, 0x16, 0xE5, 0x16, 0xC3, 0x94, 0x14, 0x40, -/*0CF0*/0xEA, 0xE5, 0xE4, 0x20, 0xE7, 0x28, 0x12, 0x0E, - 0x04, 0x75, 0x83, 0xD2, 0xE0, 0x54, 0x08, 0xD3, -/*0D00*/0x94, 0x00, 0x40, 0x04, 0x7F, 0x01, 0x80, 0x02, - 0x7F, 0x00, 0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x40, -/*0D10*/0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEF, - 0x5E, 0x60, 0x03, 0x12, 0x1D, 0xD7, 0xE5, 0x7F, -/*0D20*/0xC3, 0x94, 0x11, 0x40, 0x14, 0x12, 0x0E, 0x04, - 0x75, 0x83, 0xD2, 0xE0, 0x44, 0x80, 0xF0, 0xE5, -/*0D30*/0xE4, 0x20, 0xE7, 0x0F, 0x12, 0x1D, 0xD7, 0x80, - 0x0A, 0x12, 0x0E, 0x04, 0x75, 0x83, 0xD2, 0xE0, -/*0D40*/0x54, 0x7F, 0xF0, 0x12, 0x1D, 0x23, 0x22, 0x74, - 0x8A, 0x85, 0x08, 0x82, 0xF5, 0x83, 0xE5, 0x17, -/*0D50*/0xF0, 0x12, 0x0E, 0x3A, 0xE4, 0xF0, 0x90, 0x07, - 0x02, 0xE0, 0x12, 0x0E, 0x17, 0x75, 0x83, 0x90, -/*0D60*/0xEF, 0xF0, 0x74, 0x92, 0xFE, 0xE5, 0x08, 0x44, - 0x07, 0xFF, 0xF5, 0x82, 0x8E, 0x83, 0xE0, 0x54, -/*0D70*/0xC0, 0xFD, 0x90, 0x07, 0x03, 0xE0, 0x54, 0x3F, - 0x4D, 0x8F, 0x82, 0x8E, 0x83, 0xF0, 0x90, 0x07, -/*0D80*/0x04, 0xE0, 0x12, 0x0E, 0x17, 0x75, 0x83, 0x82, - 0xEF, 0xF0, 0x90, 0x07, 0x05, 0xE0, 0xFF, 0xED, -/*0D90*/0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0xB4, 0xEF, - 0x12, 0x0E, 0x03, 0x75, 0x83, 0x80, 0xE0, 0x54, -/*0DA0*/0xBF, 0xF0, 0x30, 0x37, 0x0A, 0x12, 0x0E, 0x91, - 0x75, 0x83, 0x94, 0xE0, 0x44, 0x80, 0xF0, 0x30, -/*0DB0*/0x38, 0x0A, 0x12, 0x0E, 0x91, 0x75, 0x83, 0x92, - 0xE0, 0x44, 0x80, 0xF0, 0xE5, 0x28, 0x30, 0xE4, -/*0DC0*/0x1A, 0x20, 0x39, 0x0A, 0x12, 0x0E, 0x04, 0x75, - 0x83, 0x88, 0xE0, 0x54, 0x7F, 0xF0, 0x20, 0x3A, -/*0DD0*/0x0A, 0x12, 0x0E, 0x04, 0x75, 0x83, 0x88, 0xE0, - 0x54, 0xBF, 0xF0, 0x74, 0x8C, 0xFE, 0x12, 0x0E, -/*0DE0*/0x04, 0x8E, 0x83, 0xE0, 0x54, 0x0F, 0x12, 0x0E, - 0x03, 0x75, 0x83, 0x86, 0xE0, 0x54, 0xBF, 0xF0, -/*0DF0*/0xE5, 0x08, 0x44, 0x06, 0x12, 0x0D, 0xFD, 0x75, - 0x83, 0x8A, 0xE4, 0xF0, 0x22, 0xF5, 0x82, 0x75, -/*0E00*/0x83, 0x82, 0xE4, 0xF0, 0xE5, 0x08, 0x44, 0x07, - 0xF5, 0x82, 0x22, 0x8E, 0x83, 0xE0, 0xF5, 0x10, -/*0E10*/0x54, 0xFE, 0xF0, 0xE5, 0x10, 0x44, 0x01, 0xFF, - 0xE5, 0x08, 0xFD, 0xED, 0x44, 0x07, 0xF5, 0x82, -/*0E20*/0x22, 0xE5, 0x15, 0xC4, 0x54, 0x07, 0xFF, 0xE5, - 0x08, 0xFD, 0xED, 0x44, 0x08, 0xF5, 0x82, 0x75, -/*0E30*/0x83, 0x82, 0x22, 0x75, 0x83, 0x80, 0xE0, 0x44, - 0x40, 0xF0, 0xE5, 0x08, 0x44, 0x08, 0xF5, 0x82, -/*0E40*/0x75, 0x83, 0x8A, 0x22, 0xE5, 0x16, 0x25, 0xE0, - 0x25, 0xE0, 0x24, 0xAF, 0xF5, 0x82, 0xE4, 0x34, -/*0E50*/0x1A, 0xF5, 0x83, 0xE4, 0x93, 0xF5, 0x0D, 0x22, - 0x43, 0xE1, 0x10, 0x43, 0xE1, 0x80, 0x53, 0xE1, -/*0E60*/0xFD, 0x85, 0xE1, 0x10, 0x22, 0xE5, 0x16, 0x25, - 0xE0, 0x25, 0xE0, 0x24, 0xB2, 0xF5, 0x82, 0xE4, -/*0E70*/0x34, 0x1A, 0xF5, 0x83, 0xE4, 0x93, 0x22, 0x85, - 0x55, 0x82, 0x85, 0x54, 0x83, 0xE5, 0x15, 0xF0, -/*0E80*/0x22, 0xE5, 0xE2, 0x54, 0x20, 0xD3, 0x94, 0x00, - 0x22, 0xE5, 0xE2, 0x54, 0x40, 0xD3, 0x94, 0x00, -/*0E90*/0x22, 0xE5, 0x08, 0x44, 0x06, 0xF5, 0x82, 0x22, - 0xFD, 0xE5, 0x08, 0xFB, 0xEB, 0x44, 0x07, 0xF5, -/*0EA0*/0x82, 0x22, 0x53, 0xF9, 0xF7, 0x75, 0xFE, 0x30, - 0x22, 0xEF, 0x4E, 0x70, 0x26, 0x12, 0x07, 0xCC, -/*0EB0*/0xE0, 0xFD, 0x90, 0x07, 0x26, 0x12, 0x07, 0x7B, - 0x12, 0x07, 0xD8, 0xE0, 0xFD, 0x90, 0x07, 0x28, -/*0EC0*/0x12, 0x07, 0x7B, 0x12, 0x08, 0x81, 0x12, 0x07, - 0x72, 0x12, 0x08, 0x35, 0xE0, 0x90, 0x07, 0x24, -/*0ED0*/0x12, 0x07, 0x78, 0xEF, 0x64, 0x04, 0x4E, 0x70, - 0x29, 0x12, 0x07, 0xE4, 0xE0, 0xFD, 0x90, 0x07, -/*0EE0*/0x26, 0x12, 0x07, 0x7B, 0x12, 0x07, 0xF0, 0xE0, - 0xFD, 0x90, 0x07, 0x28, 0x12, 0x07, 0x7B, 0x12, -/*0EF0*/0x08, 0x8B, 0x12, 0x07, 0x72, 0x12, 0x08, 0x41, - 0xE0, 0x54, 0x1F, 0xFD, 0x90, 0x07, 0x24, 0x12, -/*0F00*/0x07, 0x7B, 0xEF, 0x64, 0x01, 0x4E, 0x70, 0x04, - 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00, 0xEF, 0x64, -/*0F10*/0x02, 0x4E, 0x70, 0x04, 0x7F, 0x01, 0x80, 0x02, - 0x7F, 0x00, 0xEF, 0x4D, 0x60, 0x35, 0x12, 0x07, -/*0F20*/0xFC, 0xE0, 0xFF, 0x90, 0x07, 0x26, 0x12, 0x07, - 0x89, 0xEF, 0xF0, 0x12, 0x08, 0x08, 0xE0, 0xFF, -/*0F30*/0x90, 0x07, 0x28, 0x12, 0x07, 0x89, 0xEF, 0xF0, - 0x12, 0x08, 0x4D, 0xE0, 0x54, 0x1F, 0xFF, 0x12, -/*0F40*/0x07, 0x86, 0xEF, 0xF0, 0x12, 0x08, 0x59, 0xE0, - 0x54, 0x1F, 0xFF, 0x90, 0x07, 0x24, 0x12, 0x07, -/*0F50*/0x89, 0xEF, 0xF0, 0x22, 0xE4, 0xF5, 0x53, 0x12, - 0x0E, 0x81, 0x40, 0x04, 0x7F, 0x01, 0x80, 0x02, -/*0F60*/0x7F, 0x00, 0x12, 0x0E, 0x89, 0x40, 0x04, 0x7E, - 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, 0x70, -/*0F70*/0x03, 0x02, 0x0F, 0xF6, 0x85, 0xE1, 0x10, 0x43, - 0xE1, 0x02, 0x53, 0xE1, 0x0F, 0x85, 0xE1, 0x10, -/*0F80*/0xE4, 0xF5, 0x51, 0xE5, 0xE3, 0x54, 0x3F, 0xF5, - 0x52, 0x12, 0x0E, 0x89, 0x40, 0x1D, 0xAD, 0x52, -/*0F90*/0xAF, 0x51, 0x12, 0x11, 0x18, 0xEF, 0x60, 0x08, - 0x85, 0xE1, 0x10, 0x43, 0xE1, 0x40, 0x80, 0x0B, -/*0FA0*/0x53, 0xE1, 0xBF, 0x12, 0x0E, 0x58, 0x12, 0x00, - 0x06, 0x80, 0xFB, 0xE5, 0xE3, 0x54, 0x3F, 0xF5, -/*0FB0*/0x51, 0xE5, 0xE4, 0x54, 0x3F, 0xF5, 0x52, 0x12, - 0x0E, 0x81, 0x40, 0x1D, 0xAD, 0x52, 0xAF, 0x51, -/*0FC0*/0x12, 0x11, 0x18, 0xEF, 0x60, 0x08, 0x85, 0xE1, - 0x10, 0x43, 0xE1, 0x20, 0x80, 0x0B, 0x53, 0xE1, -/*0FD0*/0xDF, 0x12, 0x0E, 0x58, 0x12, 0x00, 0x06, 0x80, - 0xFB, 0x12, 0x0E, 0x81, 0x40, 0x04, 0x7F, 0x01, -/*0FE0*/0x80, 0x02, 0x7F, 0x00, 0x12, 0x0E, 0x89, 0x40, - 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, -/*0FF0*/0x4F, 0x60, 0x03, 0x12, 0x0E, 0x5B, 0x22, 0x12, - 0x0E, 0x21, 0xEF, 0xF0, 0x12, 0x10, 0x91, 0x22, -/*1000*/0x02, 0x11, 0x00, 0x02, 0x10, 0x40, 0x02, 0x10, - 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/*1010*/0x01, 0x20, 0x01, 0x20, 0xE4, 0xF5, 0x57, 0x12, - 0x16, 0xBD, 0x12, 0x16, 0x44, 0xE4, 0x12, 0x10, -/*1020*/0x56, 0x12, 0x14, 0xB7, 0x90, 0x07, 0x26, 0x12, - 0x07, 0x35, 0xE4, 0x12, 0x07, 0x31, 0xE4, 0xF0, -/*1030*/0x12, 0x10, 0x56, 0x12, 0x14, 0xB7, 0x90, 0x07, - 0x26, 0x12, 0x07, 0x35, 0xE5, 0x41, 0x12, 0x07, -/*1040*/0x31, 0xE5, 0x40, 0xF0, 0xAF, 0x57, 0x7E, 0x00, - 0xAD, 0x56, 0x7C, 0x00, 0x12, 0x04, 0x44, 0xAF, -/*1050*/0x56, 0x7E, 0x00, 0x02, 0x11, 0xEE, 0xFF, 0x90, - 0x07, 0x20, 0xA3, 0xE0, 0xFD, 0xE4, 0xF5, 0x56, -/*1060*/0xF5, 0x40, 0xFE, 0xFC, 0xAB, 0x56, 0xFA, 0x12, - 0x11, 0x51, 0x7F, 0x0F, 0x7D, 0x18, 0xE4, 0xF5, -/*1070*/0x56, 0xF5, 0x40, 0xFE, 0xFC, 0xAB, 0x56, 0xFA, - 0x12, 0x15, 0x41, 0xAF, 0x56, 0x7E, 0x00, 0x12, -/*1080*/0x1A, 0xFF, 0xE4, 0xFF, 0xF5, 0x56, 0x7D, 0x1F, - 0xF5, 0x40, 0xFE, 0xFC, 0xAB, 0x56, 0xFA, 0x22, -/*1090*/0x22, 0xE4, 0xF5, 0x55, 0xE5, 0x08, 0xFD, 0x74, - 0xA0, 0xF5, 0x56, 0xED, 0x44, 0x07, 0xF5, 0x57, -/*10A0*/0xE5, 0x28, 0x30, 0xE5, 0x03, 0xD3, 0x80, 0x01, - 0xC3, 0x40, 0x05, 0x7F, 0x28, 0xEF, 0x80, 0x04, -/*10B0*/0x7F, 0x14, 0xEF, 0xC3, 0x13, 0xF5, 0x54, 0xE4, - 0xF9, 0x12, 0x0E, 0x18, 0x75, 0x83, 0x8E, 0xE0, -/*10C0*/0xF5, 0x10, 0xCE, 0xEF, 0xCE, 0xEE, 0xD3, 0x94, - 0x00, 0x40, 0x26, 0xE5, 0x10, 0x54, 0xFE, 0x12, -/*10D0*/0x0E, 0x98, 0x75, 0x83, 0x8E, 0xED, 0xF0, 0xE5, - 0x10, 0x44, 0x01, 0xFD, 0xEB, 0x44, 0x07, 0xF5, -/*10E0*/0x82, 0xED, 0xF0, 0x85, 0x57, 0x82, 0x85, 0x56, - 0x83, 0xE0, 0x30, 0xE3, 0x01, 0x09, 0x1E, 0x80, -/*10F0*/0xD4, 0xC2, 0x34, 0xE9, 0xC3, 0x95, 0x54, 0x40, - 0x02, 0xD2, 0x34, 0x22, 0x02, 0x00, 0x06, 0x22, -/*1100*/0x30, 0x30, 0x11, 0x90, 0x10, 0x00, 0xE4, 0x93, - 0xF5, 0x10, 0x90, 0x10, 0x10, 0xE4, 0x93, 0xF5, -/*1110*/0x10, 0x12, 0x10, 0x90, 0x12, 0x11, 0x50, 0x22, - 0xE4, 0xFC, 0xC3, 0xED, 0x9F, 0xFA, 0xEF, 0xF5, -/*1120*/0x83, 0x75, 0x82, 0x00, 0x79, 0xFF, 0xE4, 0x93, - 0xCC, 0x6C, 0xCC, 0xA3, 0xD9, 0xF8, 0xDA, 0xF6, -/*1130*/0xE5, 0xE2, 0x30, 0xE4, 0x02, 0x8C, 0xE5, 0xED, - 0x24, 0xFF, 0xFF, 0xEF, 0x75, 0x82, 0xFF, 0xF5, -/*1140*/0x83, 0xE4, 0x93, 0x6C, 0x70, 0x03, 0x7F, 0x01, - 0x22, 0x7F, 0x00, 0x22, 0x22, 0x11, 0x00, 0x00, -/*1150*/0x22, 0x8E, 0x58, 0x8F, 0x59, 0x8C, 0x5A, 0x8D, - 0x5B, 0x8A, 0x5C, 0x8B, 0x5D, 0x75, 0x5E, 0x01, -/*1160*/0xE4, 0xF5, 0x5F, 0xF5, 0x60, 0xF5, 0x62, 0x12, - 0x07, 0x2A, 0x75, 0x83, 0xD0, 0xE0, 0xFF, 0xC4, -/*1170*/0x54, 0x0F, 0xF5, 0x61, 0x12, 0x1E, 0xA5, 0x85, - 0x59, 0x5E, 0xD3, 0xE5, 0x5E, 0x95, 0x5B, 0xE5, -/*1180*/0x5A, 0x12, 0x07, 0x6B, 0x50, 0x4B, 0x12, 0x07, - 0x03, 0x75, 0x83, 0xBC, 0xE0, 0x45, 0x5E, 0x12, -/*1190*/0x07, 0x29, 0x75, 0x83, 0xBE, 0xE0, 0x45, 0x5E, - 0x12, 0x07, 0x29, 0x75, 0x83, 0xC0, 0xE0, 0x45, -/*11A0*/0x5E, 0xF0, 0xAF, 0x5F, 0xE5, 0x60, 0x12, 0x08, - 0x78, 0x12, 0x0A, 0xFF, 0xAF, 0x62, 0x7E, 0x00, -/*11B0*/0xAD, 0x5D, 0xAC, 0x5C, 0x12, 0x04, 0x44, 0xE5, - 0x61, 0xAF, 0x5E, 0x7E, 0x00, 0xB4, 0x03, 0x05, -/*11C0*/0x12, 0x1E, 0x21, 0x80, 0x07, 0xAD, 0x5D, 0xAC, - 0x5C, 0x12, 0x13, 0x17, 0x05, 0x5E, 0x02, 0x11, -/*11D0*/0x7A, 0x12, 0x07, 0x03, 0x75, 0x83, 0xBC, 0xE0, - 0x45, 0x40, 0x12, 0x07, 0x29, 0x75, 0x83, 0xBE, -/*11E0*/0xE0, 0x45, 0x40, 0x12, 0x07, 0x29, 0x75, 0x83, - 0xC0, 0xE0, 0x45, 0x40, 0xF0, 0x22, 0x8E, 0x58, -/*11F0*/0x8F, 0x59, 0x75, 0x5A, 0x01, 0x79, 0x01, 0x75, - 0x5B, 0x01, 0xE4, 0xFB, 0x12, 0x07, 0x2A, 0x75, -/*1200*/0x83, 0xAE, 0xE0, 0x54, 0x1A, 0xFF, 0x12, 0x08, - 0x65, 0xE0, 0xC4, 0x13, 0x54, 0x07, 0xFE, 0xEF, -/*1210*/0x70, 0x0C, 0xEE, 0x65, 0x35, 0x70, 0x07, 0x90, - 0x07, 0x2F, 0xE0, 0xB4, 0x01, 0x0D, 0xAF, 0x35, -/*1220*/0x7E, 0x00, 0x12, 0x0E, 0xA9, 0xCF, 0xEB, 0xCF, - 0x02, 0x1E, 0x60, 0xE5, 0x59, 0x64, 0x02, 0x45, -/*1230*/0x58, 0x70, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, - 0x00, 0xE5, 0x59, 0x45, 0x58, 0x70, 0x04, 0x7E, -/*1240*/0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, 0x60, - 0x23, 0x85, 0x41, 0x49, 0x85, 0x40, 0x4B, 0xE5, -/*1250*/0x59, 0x45, 0x58, 0x70, 0x2C, 0xAF, 0x5A, 0xFE, - 0xCD, 0xE9, 0xCD, 0xFC, 0xAB, 0x59, 0xAA, 0x58, -/*1260*/0x12, 0x0A, 0xFF, 0xAF, 0x5B, 0x7E, 0x00, 0x12, - 0x1E, 0x60, 0x80, 0x15, 0xAF, 0x5B, 0x7E, 0x00, -/*1270*/0x12, 0x1E, 0x60, 0x90, 0x07, 0x26, 0x12, 0x07, - 0x35, 0xE5, 0x49, 0x12, 0x07, 0x31, 0xE5, 0x4B, -/*1280*/0xF0, 0xE4, 0xFD, 0xAF, 0x35, 0xFE, 0xFC, 0x12, - 0x09, 0x15, 0x22, 0x8C, 0x64, 0x8D, 0x65, 0x12, -/*1290*/0x08, 0xDA, 0x40, 0x3C, 0xE5, 0x65, 0x45, 0x64, - 0x70, 0x10, 0x12, 0x09, 0x04, 0xC3, 0xE5, 0x3E, -/*12A0*/0x12, 0x07, 0x69, 0x40, 0x3B, 0x12, 0x08, 0x95, - 0x80, 0x18, 0xE5, 0x3E, 0xC3, 0x95, 0x38, 0x40, -/*12B0*/0x1D, 0x85, 0x3E, 0x38, 0xE5, 0x3E, 0x60, 0x05, - 0x85, 0x3F, 0x39, 0x80, 0x03, 0x85, 0x39, 0x39, -/*12C0*/0x8F, 0x3A, 0x12, 0x07, 0xA8, 0xE5, 0x3E, 0x12, - 0x07, 0x53, 0xE5, 0x3F, 0xF0, 0x22, 0x80, 0x3B, -/*12D0*/0xE5, 0x65, 0x45, 0x64, 0x70, 0x11, 0x12, 0x07, - 0x5F, 0x40, 0x05, 0x12, 0x08, 0x9E, 0x80, 0x1F, -/*12E0*/0x12, 0x07, 0x3E, 0xE5, 0x41, 0xF0, 0x22, 0xE5, - 0x3C, 0xC3, 0x95, 0x38, 0x40, 0x1D, 0x85, 0x3C, -/*12F0*/0x38, 0xE5, 0x3C, 0x60, 0x05, 0x85, 0x3D, 0x39, - 0x80, 0x03, 0x85, 0x39, 0x39, 0x8F, 0x3A, 0x12, -/*1300*/0x07, 0xA8, 0xE5, 0x3C, 0x12, 0x07, 0x53, 0xE5, - 0x3D, 0xF0, 0x22, 0x12, 0x07, 0x9F, 0xE5, 0x38, -/*1310*/0x12, 0x07, 0x53, 0xE5, 0x39, 0xF0, 0x22, 0x8C, - 0x63, 0x8D, 0x64, 0x12, 0x08, 0xDA, 0x40, 0x3C, -/*1320*/0xE5, 0x64, 0x45, 0x63, 0x70, 0x10, 0x12, 0x09, - 0x04, 0xC3, 0xE5, 0x3E, 0x12, 0x07, 0x69, 0x40, -/*1330*/0x3B, 0x12, 0x08, 0x95, 0x80, 0x18, 0xE5, 0x3E, - 0xC3, 0x95, 0x38, 0x40, 0x1D, 0x85, 0x3E, 0x38, -/*1340*/0xE5, 0x3E, 0x60, 0x05, 0x85, 0x3F, 0x39, 0x80, - 0x03, 0x85, 0x39, 0x39, 0x8F, 0x3A, 0x12, 0x07, -/*1350*/0xA8, 0xE5, 0x3E, 0x12, 0x07, 0x53, 0xE5, 0x3F, - 0xF0, 0x22, 0x80, 0x3B, 0xE5, 0x64, 0x45, 0x63, -/*1360*/0x70, 0x11, 0x12, 0x07, 0x5F, 0x40, 0x05, 0x12, - 0x08, 0x9E, 0x80, 0x1F, 0x12, 0x07, 0x3E, 0xE5, -/*1370*/0x41, 0xF0, 0x22, 0xE5, 0x3C, 0xC3, 0x95, 0x38, - 0x40, 0x1D, 0x85, 0x3C, 0x38, 0xE5, 0x3C, 0x60, -/*1380*/0x05, 0x85, 0x3D, 0x39, 0x80, 0x03, 0x85, 0x39, - 0x39, 0x8F, 0x3A, 0x12, 0x07, 0xA8, 0xE5, 0x3C, -/*1390*/0x12, 0x07, 0x53, 0xE5, 0x3D, 0xF0, 0x22, 0x12, - 0x07, 0x9F, 0xE5, 0x38, 0x12, 0x07, 0x53, 0xE5, -/*13A0*/0x39, 0xF0, 0x22, 0xE5, 0x0D, 0xFE, 0xE5, 0x08, - 0x8E, 0x54, 0x44, 0x05, 0xF5, 0x55, 0x75, 0x15, -/*13B0*/0x0F, 0xF5, 0x82, 0x12, 0x0E, 0x7A, 0x12, 0x17, - 0xA3, 0x20, 0x31, 0x05, 0x75, 0x15, 0x03, 0x80, -/*13C0*/0x03, 0x75, 0x15, 0x0B, 0xE5, 0x0A, 0xC3, 0x94, - 0x01, 0x50, 0x38, 0x12, 0x14, 0x20, 0x20, 0x31, -/*13D0*/0x06, 0x05, 0x15, 0x05, 0x15, 0x80, 0x04, 0x15, - 0x15, 0x15, 0x15, 0xE5, 0x0A, 0xC3, 0x94, 0x01, -/*13E0*/0x50, 0x21, 0x12, 0x14, 0x20, 0x20, 0x31, 0x04, - 0x05, 0x15, 0x80, 0x02, 0x15, 0x15, 0xE5, 0x0A, -/*13F0*/0xC3, 0x94, 0x01, 0x50, 0x0E, 0x12, 0x0E, 0x77, - 0x12, 0x17, 0xA3, 0x20, 0x31, 0x05, 0x05, 0x15, -/*1400*/0x12, 0x0E, 0x77, 0xE5, 0x15, 0xB4, 0x08, 0x04, - 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x15, -/*1410*/0xB4, 0x07, 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, - 0x00, 0xEE, 0x4F, 0x60, 0x02, 0x05, 0x7F, 0x22, -/*1420*/0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xE5, 0x15, - 0xF0, 0x12, 0x17, 0xA3, 0x22, 0x12, 0x07, 0x2A, -/*1430*/0x75, 0x83, 0xAE, 0x74, 0xFF, 0x12, 0x07, 0x29, - 0xE0, 0x54, 0x1A, 0xF5, 0x34, 0xE0, 0xC4, 0x13, -/*1440*/0x54, 0x07, 0xF5, 0x35, 0x24, 0xFE, 0x60, 0x24, - 0x24, 0xFE, 0x60, 0x3C, 0x24, 0x04, 0x70, 0x63, -/*1450*/0x75, 0x31, 0x2D, 0xE5, 0x08, 0xFD, 0x74, 0xB6, - 0x12, 0x07, 0x92, 0x74, 0xBC, 0x90, 0x07, 0x22, -/*1460*/0x12, 0x07, 0x95, 0x74, 0x90, 0x12, 0x07, 0xB3, - 0x74, 0x92, 0x80, 0x3C, 0x75, 0x31, 0x3A, 0xE5, -/*1470*/0x08, 0xFD, 0x74, 0xBA, 0x12, 0x07, 0x92, 0x74, - 0xC0, 0x90, 0x07, 0x22, 0x12, 0x07, 0xB6, 0x74, -/*1480*/0xC4, 0x12, 0x07, 0xB3, 0x74, 0xC8, 0x80, 0x20, - 0x75, 0x31, 0x35, 0xE5, 0x08, 0xFD, 0x74, 0xB8, -/*1490*/0x12, 0x07, 0x92, 0x74, 0xBE, 0xFF, 0xED, 0x44, - 0x07, 0x90, 0x07, 0x22, 0xCF, 0xF0, 0xA3, 0xEF, -/*14A0*/0xF0, 0x74, 0xC2, 0x12, 0x07, 0xB3, 0x74, 0xC6, - 0xFF, 0xED, 0x44, 0x07, 0xA3, 0xCF, 0xF0, 0xA3, -/*14B0*/0xEF, 0xF0, 0x22, 0x75, 0x34, 0x01, 0x22, 0x8E, - 0x58, 0x8F, 0x59, 0x8C, 0x5A, 0x8D, 0x5B, 0x8A, -/*14C0*/0x5C, 0x8B, 0x5D, 0x75, 0x5E, 0x01, 0xE4, 0xF5, - 0x5F, 0x12, 0x1E, 0xA5, 0x85, 0x59, 0x5E, 0xD3, -/*14D0*/0xE5, 0x5E, 0x95, 0x5B, 0xE5, 0x5A, 0x12, 0x07, - 0x6B, 0x50, 0x57, 0xE5, 0x5D, 0x45, 0x5C, 0x70, -/*14E0*/0x30, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x92, 0xE5, - 0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC6, 0xE5, -/*14F0*/0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC8, 0xE5, - 0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0x90, 0xE5, -/*1500*/0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, 0xE5, - 0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0x80, -/*1510*/0x03, 0x12, 0x07, 0x32, 0xE5, 0x5E, 0xF0, 0xAF, - 0x5F, 0x7E, 0x00, 0xAD, 0x5D, 0xAC, 0x5C, 0x12, -/*1520*/0x04, 0x44, 0xAF, 0x5E, 0x7E, 0x00, 0xAD, 0x5D, - 0xAC, 0x5C, 0x12, 0x0B, 0xD1, 0x05, 0x5E, 0x02, -/*1530*/0x14, 0xCF, 0xAB, 0x5D, 0xAA, 0x5C, 0xAD, 0x5B, - 0xAC, 0x5A, 0xAF, 0x59, 0xAE, 0x58, 0x02, 0x1B, -/*1540*/0xFB, 0x8C, 0x5C, 0x8D, 0x5D, 0x8A, 0x5E, 0x8B, - 0x5F, 0x75, 0x60, 0x01, 0xE4, 0xF5, 0x61, 0xF5, -/*1550*/0x62, 0xF5, 0x63, 0x12, 0x1E, 0xA5, 0x8F, 0x60, - 0xD3, 0xE5, 0x60, 0x95, 0x5D, 0xE5, 0x5C, 0x12, -/*1560*/0x07, 0x6B, 0x50, 0x61, 0xE5, 0x5F, 0x45, 0x5E, - 0x70, 0x27, 0x12, 0x07, 0x2A, 0x75, 0x83, 0xB6, -/*1570*/0xE5, 0x60, 0x12, 0x07, 0x29, 0x75, 0x83, 0xB8, - 0xE5, 0x60, 0x12, 0x07, 0x29, 0x75, 0x83, 0xBA, -/*1580*/0xE5, 0x60, 0xF0, 0xAF, 0x61, 0x7E, 0x00, 0xE5, - 0x62, 0x12, 0x08, 0x7A, 0x12, 0x0A, 0xFF, 0x80, -/*1590*/0x19, 0x90, 0x07, 0x24, 0x12, 0x07, 0x35, 0xE5, - 0x60, 0x12, 0x07, 0x29, 0x75, 0x83, 0x8E, 0xE4, -/*15A0*/0x12, 0x07, 0x29, 0x74, 0x01, 0x12, 0x07, 0x29, - 0xE4, 0xF0, 0xAF, 0x63, 0x7E, 0x00, 0xAD, 0x5F, -/*15B0*/0xAC, 0x5E, 0x12, 0x04, 0x44, 0xAF, 0x60, 0x7E, - 0x00, 0xAD, 0x5F, 0xAC, 0x5E, 0x12, 0x12, 0x8B, -/*15C0*/0x05, 0x60, 0x02, 0x15, 0x58, 0x22, 0x90, 0x11, - 0x4D, 0xE4, 0x93, 0x90, 0x07, 0x2E, 0xF0, 0x12, -/*15D0*/0x08, 0x1F, 0x75, 0x83, 0xAE, 0xE0, 0x54, 0x1A, - 0xF5, 0x34, 0x70, 0x67, 0xEF, 0x44, 0x07, 0xF5, -/*15E0*/0x82, 0x75, 0x83, 0xCE, 0xE0, 0xFF, 0x13, 0x13, - 0x13, 0x54, 0x07, 0xF5, 0x36, 0x54, 0x0F, 0xD3, -/*15F0*/0x94, 0x00, 0x40, 0x06, 0x12, 0x14, 0x2D, 0x12, - 0x1B, 0xA9, 0xE5, 0x36, 0x54, 0x0F, 0x24, 0xFE, -/*1600*/0x60, 0x0C, 0x14, 0x60, 0x0C, 0x14, 0x60, 0x19, - 0x24, 0x03, 0x70, 0x37, 0x80, 0x10, 0x02, 0x1E, -/*1610*/0x91, 0x12, 0x1E, 0x91, 0x12, 0x07, 0x2A, 0x75, - 0x83, 0xCE, 0xE0, 0x54, 0xEF, 0xF0, 0x02, 0x1D, -/*1620*/0xAE, 0x12, 0x10, 0x14, 0xE4, 0xF5, 0x55, 0x12, - 0x1D, 0x85, 0x05, 0x55, 0xE5, 0x55, 0xC3, 0x94, -/*1630*/0x05, 0x40, 0xF4, 0x12, 0x07, 0x2A, 0x75, 0x83, - 0xCE, 0xE0, 0x54, 0xC7, 0x12, 0x07, 0x29, 0xE0, -/*1640*/0x44, 0x08, 0xF0, 0x22, 0xE4, 0xF5, 0x58, 0xF5, - 0x59, 0xAF, 0x08, 0xEF, 0x44, 0x07, 0xF5, 0x82, -/*1650*/0x75, 0x83, 0xD0, 0xE0, 0xFD, 0xC4, 0x54, 0x0F, - 0xF5, 0x5A, 0xEF, 0x44, 0x07, 0xF5, 0x82, 0x75, -/*1660*/0x83, 0x80, 0x74, 0x01, 0xF0, 0x12, 0x08, 0x21, - 0x75, 0x83, 0x82, 0xE5, 0x45, 0xF0, 0xEF, 0x44, -/*1670*/0x07, 0xF5, 0x82, 0x75, 0x83, 0x8A, 0x74, 0xFF, - 0xF0, 0x12, 0x1A, 0x4D, 0x12, 0x07, 0x2A, 0x75, -/*1680*/0x83, 0xBC, 0xE0, 0x54, 0xEF, 0x12, 0x07, 0x29, - 0x75, 0x83, 0xBE, 0xE0, 0x54, 0xEF, 0x12, 0x07, -/*1690*/0x29, 0x75, 0x83, 0xC0, 0xE0, 0x54, 0xEF, 0x12, - 0x07, 0x29, 0x75, 0x83, 0xBC, 0xE0, 0x44, 0x10, -/*16A0*/0x12, 0x07, 0x29, 0x75, 0x83, 0xBE, 0xE0, 0x44, - 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC0, 0xE0, -/*16B0*/0x44, 0x10, 0xF0, 0xAF, 0x58, 0xE5, 0x59, 0x12, - 0x08, 0x78, 0x02, 0x0A, 0xFF, 0xE4, 0xF5, 0x58, -/*16C0*/0x7D, 0x01, 0xF5, 0x59, 0xAF, 0x35, 0xFE, 0xFC, - 0x12, 0x09, 0x15, 0x12, 0x07, 0x2A, 0x75, 0x83, -/*16D0*/0xB6, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, - 0xB8, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, -/*16E0*/0xBA, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, - 0xBC, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, -/*16F0*/0xBE, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, - 0xC0, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, -/*1700*/0x90, 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, - 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0xE4, -/*1710*/0x12, 0x07, 0x29, 0x75, 0x83, 0x92, 0xE4, 0x12, - 0x07, 0x29, 0x75, 0x83, 0xC6, 0xE4, 0x12, 0x07, -/*1720*/0x29, 0x75, 0x83, 0xC8, 0xE4, 0xF0, 0xAF, 0x58, - 0xFE, 0xE5, 0x59, 0x12, 0x08, 0x7A, 0x02, 0x0A, -/*1730*/0xFF, 0xE5, 0xE2, 0x30, 0xE4, 0x6C, 0xE5, 0xE7, - 0x54, 0xC0, 0x64, 0x40, 0x70, 0x64, 0xE5, 0x09, -/*1740*/0xC4, 0x54, 0x30, 0xFE, 0xE5, 0x08, 0x25, 0xE0, - 0x25, 0xE0, 0x54, 0xC0, 0x4E, 0xFE, 0xEF, 0x54, -/*1750*/0x3F, 0x4E, 0xFD, 0xE5, 0x2B, 0xAE, 0x2A, 0x78, - 0x02, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9, -/*1760*/0xF5, 0x82, 0x8E, 0x83, 0xED, 0xF0, 0xE5, 0x2B, - 0xAE, 0x2A, 0x78, 0x02, 0xC3, 0x33, 0xCE, 0x33, -/*1770*/0xCE, 0xD8, 0xF9, 0xFF, 0xF5, 0x82, 0x8E, 0x83, - 0xA3, 0xE5, 0xFE, 0xF0, 0x8F, 0x82, 0x8E, 0x83, -/*1780*/0xA3, 0xA3, 0xE5, 0xFD, 0xF0, 0x8F, 0x82, 0x8E, - 0x83, 0xA3, 0xA3, 0xA3, 0xE5, 0xFC, 0xF0, 0xC3, -/*1790*/0xE5, 0x2B, 0x94, 0xFA, 0xE5, 0x2A, 0x94, 0x00, - 0x50, 0x08, 0x05, 0x2B, 0xE5, 0x2B, 0x70, 0x02, -/*17A0*/0x05, 0x2A, 0x22, 0xE4, 0xFF, 0xE4, 0xF5, 0x58, - 0xF5, 0x56, 0xF5, 0x57, 0x74, 0x82, 0xFC, 0x12, -/*17B0*/0x0E, 0x04, 0x8C, 0x83, 0xE0, 0xF5, 0x10, 0x54, - 0x7F, 0xF0, 0xE5, 0x10, 0x44, 0x80, 0x12, 0x0E, -/*17C0*/0x98, 0xED, 0xF0, 0x7E, 0x0A, 0x12, 0x0E, 0x04, - 0x75, 0x83, 0xA0, 0xE0, 0x20, 0xE0, 0x26, 0xDE, -/*17D0*/0xF4, 0x05, 0x57, 0xE5, 0x57, 0x70, 0x02, 0x05, - 0x56, 0xE5, 0x14, 0x24, 0x01, 0xFD, 0xE4, 0x33, -/*17E0*/0xFC, 0xD3, 0xE5, 0x57, 0x9D, 0xE5, 0x56, 0x9C, - 0x40, 0xD9, 0xE5, 0x0A, 0x94, 0x20, 0x50, 0x02, -/*17F0*/0x05, 0x0A, 0x43, 0xE1, 0x08, 0xC2, 0x31, 0x12, - 0x0E, 0x04, 0x75, 0x83, 0xA6, 0xE0, 0x55, 0x12, -/*1800*/0x65, 0x12, 0x70, 0x03, 0xD2, 0x31, 0x22, 0xC2, - 0x31, 0x22, 0x90, 0x07, 0x26, 0xE0, 0xFA, 0xA3, -/*1810*/0xE0, 0xF5, 0x82, 0x8A, 0x83, 0xE0, 0xF5, 0x41, - 0xE5, 0x39, 0xC3, 0x95, 0x41, 0x40, 0x26, 0xE5, -/*1820*/0x39, 0x95, 0x41, 0xC3, 0x9F, 0xEE, 0x12, 0x07, - 0x6B, 0x40, 0x04, 0x7C, 0x01, 0x80, 0x02, 0x7C, -/*1830*/0x00, 0xE5, 0x41, 0x64, 0x3F, 0x60, 0x04, 0x7B, - 0x01, 0x80, 0x02, 0x7B, 0x00, 0xEC, 0x5B, 0x60, -/*1840*/0x29, 0x05, 0x41, 0x80, 0x28, 0xC3, 0xE5, 0x41, - 0x95, 0x39, 0xC3, 0x9F, 0xEE, 0x12, 0x07, 0x6B, -/*1850*/0x40, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, - 0xE5, 0x41, 0x60, 0x04, 0x7E, 0x01, 0x80, 0x02, -/*1860*/0x7E, 0x00, 0xEF, 0x5E, 0x60, 0x04, 0x15, 0x41, - 0x80, 0x03, 0x85, 0x39, 0x41, 0x85, 0x3A, 0x40, -/*1870*/0x22, 0xE5, 0xE2, 0x30, 0xE4, 0x60, 0xE5, 0xE1, - 0x30, 0xE2, 0x5B, 0xE5, 0x09, 0x70, 0x04, 0x7F, -/*1880*/0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x08, 0x70, - 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, -/*1890*/0x5F, 0x60, 0x43, 0x53, 0xF9, 0xF8, 0xE5, 0xE2, - 0x30, 0xE4, 0x3B, 0xE5, 0xE1, 0x30, 0xE2, 0x2E, -/*18A0*/0x43, 0xFA, 0x02, 0x53, 0xFA, 0xFB, 0xE4, 0xF5, - 0x10, 0x90, 0x94, 0x70, 0xE5, 0x10, 0xF0, 0xE5, -/*18B0*/0xE1, 0x30, 0xE2, 0xE7, 0x90, 0x94, 0x70, 0xE0, - 0x65, 0x10, 0x60, 0x03, 0x43, 0xFA, 0x04, 0x05, -/*18C0*/0x10, 0x90, 0x94, 0x70, 0xE5, 0x10, 0xF0, 0x70, - 0xE6, 0x12, 0x00, 0x06, 0x80, 0xE1, 0x53, 0xFA, -/*18D0*/0xFD, 0x53, 0xFA, 0xFB, 0x80, 0xC0, 0x22, 0x8F, - 0x54, 0x12, 0x00, 0x06, 0xE5, 0xE1, 0x30, 0xE0, -/*18E0*/0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, - 0x7E, 0xD3, 0x94, 0x05, 0x40, 0x04, 0x7E, 0x01, -/*18F0*/0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, 0x60, 0x3D, - 0x85, 0x54, 0x11, 0xE5, 0xE2, 0x20, 0xE1, 0x32, -/*1900*/0x74, 0xCE, 0x12, 0x1A, 0x05, 0x30, 0xE7, 0x04, - 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00, 0x8F, 0x82, -/*1910*/0x8E, 0x83, 0xE0, 0x30, 0xE6, 0x04, 0x7F, 0x01, - 0x80, 0x02, 0x7F, 0x00, 0xEF, 0x5D, 0x70, 0x15, -/*1920*/0x12, 0x15, 0xC6, 0x74, 0xCE, 0x12, 0x1A, 0x05, - 0x30, 0xE6, 0x07, 0xE0, 0x44, 0x80, 0xF0, 0x43, -/*1930*/0xF9, 0x80, 0x12, 0x18, 0x71, 0x22, 0x12, 0x0E, - 0x44, 0xE5, 0x16, 0x25, 0xE0, 0x25, 0xE0, 0x24, -/*1940*/0xB0, 0xF5, 0x82, 0xE4, 0x34, 0x1A, 0xF5, 0x83, - 0xE4, 0x93, 0xF5, 0x0F, 0xE5, 0x16, 0x25, 0xE0, -/*1950*/0x25, 0xE0, 0x24, 0xB1, 0xF5, 0x82, 0xE4, 0x34, - 0x1A, 0xF5, 0x83, 0xE4, 0x93, 0xF5, 0x0E, 0x12, -/*1960*/0x0E, 0x65, 0xF5, 0x10, 0xE5, 0x0F, 0x54, 0xF0, - 0x12, 0x0E, 0x17, 0x75, 0x83, 0x8C, 0xEF, 0xF0, -/*1970*/0xE5, 0x0F, 0x30, 0xE0, 0x0C, 0x12, 0x0E, 0x04, - 0x75, 0x83, 0x86, 0xE0, 0x44, 0x40, 0xF0, 0x80, -/*1980*/0x0A, 0x12, 0x0E, 0x04, 0x75, 0x83, 0x86, 0xE0, - 0x54, 0xBF, 0xF0, 0x12, 0x0E, 0x91, 0x75, 0x83, -/*1990*/0x82, 0xE5, 0x0E, 0xF0, 0x22, 0x7F, 0x05, 0x12, - 0x17, 0x31, 0x12, 0x0E, 0x04, 0x12, 0x0E, 0x33, -/*19A0*/0x74, 0x02, 0xF0, 0x74, 0x8E, 0xFE, 0x12, 0x0E, - 0x04, 0x12, 0x0E, 0x0B, 0xEF, 0xF0, 0x75, 0x15, -/*19B0*/0x70, 0x12, 0x0F, 0xF7, 0x20, 0x34, 0x05, 0x75, - 0x15, 0x10, 0x80, 0x03, 0x75, 0x15, 0x50, 0x12, -/*19C0*/0x0F, 0xF7, 0x20, 0x34, 0x04, 0x74, 0x10, 0x80, - 0x02, 0x74, 0xF0, 0x25, 0x15, 0xF5, 0x15, 0x12, -/*19D0*/0x0E, 0x21, 0xEF, 0xF0, 0x12, 0x10, 0x91, 0x20, - 0x34, 0x17, 0xE5, 0x15, 0x64, 0x30, 0x60, 0x0C, -/*19E0*/0x74, 0x10, 0x25, 0x15, 0xF5, 0x15, 0xB4, 0x80, - 0x03, 0xE4, 0xF5, 0x15, 0x12, 0x0E, 0x21, 0xEF, -/*19F0*/0xF0, 0x22, 0xF0, 0xE5, 0x0B, 0x25, 0xE0, 0x25, - 0xE0, 0x24, 0x82, 0xF5, 0x82, 0xE4, 0x34, 0x07, -/*1A00*/0xF5, 0x83, 0x22, 0x74, 0x88, 0xFE, 0xE5, 0x08, - 0x44, 0x07, 0xFF, 0xF5, 0x82, 0x8E, 0x83, 0xE0, -/*1A10*/0x22, 0xF0, 0xE5, 0x08, 0x44, 0x07, 0xF5, 0x82, - 0x22, 0xF0, 0xE0, 0x54, 0xC0, 0x8F, 0x82, 0x8E, -/*1A20*/0x83, 0xF0, 0x22, 0xEF, 0x44, 0x07, 0xF5, 0x82, - 0x75, 0x83, 0x86, 0xE0, 0x54, 0x10, 0xD3, 0x94, -/*1A30*/0x00, 0x22, 0xF0, 0x90, 0x07, 0x15, 0xE0, 0x04, - 0xF0, 0x22, 0x44, 0x06, 0xF5, 0x82, 0x75, 0x83, -/*1A40*/0x9E, 0xE0, 0x22, 0xFE, 0xEF, 0x44, 0x07, 0xF5, - 0x82, 0x8E, 0x83, 0xE0, 0x22, 0xE4, 0x90, 0x07, -/*1A50*/0x2A, 0xF0, 0xA3, 0xF0, 0x12, 0x07, 0x2A, 0x75, - 0x83, 0x82, 0xE0, 0x54, 0x7F, 0x12, 0x07, 0x29, -/*1A60*/0xE0, 0x44, 0x80, 0xF0, 0x12, 0x10, 0xFC, 0x12, - 0x08, 0x1F, 0x75, 0x83, 0xA0, 0xE0, 0x20, 0xE0, -/*1A70*/0x1A, 0x90, 0x07, 0x2B, 0xE0, 0x04, 0xF0, 0x70, - 0x06, 0x90, 0x07, 0x2A, 0xE0, 0x04, 0xF0, 0x90, -/*1A80*/0x07, 0x2A, 0xE0, 0xB4, 0x10, 0xE1, 0xA3, 0xE0, - 0xB4, 0x00, 0xDC, 0xEE, 0x44, 0xA6, 0xFC, 0xEF, -/*1A90*/0x44, 0x07, 0xF5, 0x82, 0x8C, 0x83, 0xE0, 0xF5, - 0x32, 0xEE, 0x44, 0xA8, 0xFE, 0xEF, 0x44, 0x07, -/*1AA0*/0xF5, 0x82, 0x8E, 0x83, 0xE0, 0xF5, 0x33, 0x22, - 0x01, 0x20, 0x11, 0x00, 0x04, 0x20, 0x00, 0x90, -/*1AB0*/0x00, 0x20, 0x0F, 0x92, 0x00, 0x21, 0x0F, 0x94, - 0x00, 0x22, 0x0F, 0x96, 0x00, 0x23, 0x0F, 0x98, -/*1AC0*/0x00, 0x24, 0x0F, 0x9A, 0x00, 0x25, 0x0F, 0x9C, - 0x00, 0x26, 0x0F, 0x9E, 0x00, 0x27, 0x0F, 0xA0, -/*1AD0*/0x01, 0x20, 0x01, 0xA2, 0x01, 0x21, 0x01, 0xA4, - 0x01, 0x22, 0x01, 0xA6, 0x01, 0x23, 0x01, 0xA8, -/*1AE0*/0x01, 0x24, 0x01, 0xAA, 0x01, 0x25, 0x01, 0xAC, - 0x01, 0x26, 0x01, 0xAE, 0x01, 0x27, 0x01, 0xB0, -/*1AF0*/0x01, 0x28, 0x01, 0xB4, 0x00, 0x28, 0x0F, 0xB6, - 0x40, 0x28, 0x0F, 0xB8, 0x61, 0x28, 0x01, 0xCB, -/*1B00*/0xEF, 0xCB, 0xCA, 0xEE, 0xCA, 0x7F, 0x01, 0xE4, - 0xFD, 0xEB, 0x4A, 0x70, 0x24, 0xE5, 0x08, 0xF5, -/*1B10*/0x82, 0x74, 0xB6, 0x12, 0x08, 0x29, 0xE5, 0x08, - 0xF5, 0x82, 0x74, 0xB8, 0x12, 0x08, 0x29, 0xE5, -/*1B20*/0x08, 0xF5, 0x82, 0x74, 0xBA, 0x12, 0x08, 0x29, - 0x7E, 0x00, 0x7C, 0x00, 0x12, 0x0A, 0xFF, 0x80, -/*1B30*/0x12, 0x90, 0x07, 0x26, 0x12, 0x07, 0x35, 0xE5, - 0x41, 0xF0, 0x90, 0x07, 0x24, 0x12, 0x07, 0x35, -/*1B40*/0xE5, 0x40, 0xF0, 0x12, 0x07, 0x2A, 0x75, 0x83, - 0x8E, 0xE4, 0x12, 0x07, 0x29, 0x74, 0x01, 0x12, -/*1B50*/0x07, 0x29, 0xE4, 0xF0, 0x22, 0xE4, 0xF5, 0x26, - 0xF5, 0x27, 0x53, 0xE1, 0xFE, 0xF5, 0x2A, 0x75, -/*1B60*/0x2B, 0x01, 0xF5, 0x08, 0x7F, 0x01, 0x12, 0x17, - 0x31, 0x30, 0x30, 0x1C, 0x90, 0x1A, 0xA9, 0xE4, -/*1B70*/0x93, 0xF5, 0x10, 0x90, 0x1F, 0xF9, 0xE4, 0x93, - 0xF5, 0x10, 0x90, 0x00, 0x41, 0xE4, 0x93, 0xF5, -/*1B80*/0x10, 0x90, 0x1E, 0xCA, 0xE4, 0x93, 0xF5, 0x10, - 0x7F, 0x02, 0x12, 0x17, 0x31, 0x12, 0x0F, 0x54, -/*1B90*/0x7F, 0x03, 0x12, 0x17, 0x31, 0x12, 0x00, 0x06, - 0xE5, 0xE2, 0x30, 0xE7, 0x09, 0x12, 0x10, 0x00, -/*1BA0*/0x30, 0x30, 0x03, 0x12, 0x11, 0x00, 0x02, 0x00, - 0x47, 0x12, 0x08, 0x1F, 0x75, 0x83, 0xD0, 0xE0, -/*1BB0*/0xC4, 0x54, 0x0F, 0xFD, 0x75, 0x43, 0x01, 0x75, - 0x44, 0xFF, 0x12, 0x08, 0xAA, 0x74, 0x04, 0xF0, -/*1BC0*/0x75, 0x3B, 0x01, 0xED, 0x14, 0x60, 0x0C, 0x14, - 0x60, 0x0B, 0x14, 0x60, 0x0F, 0x24, 0x03, 0x70, -/*1BD0*/0x0B, 0x80, 0x09, 0x80, 0x00, 0x12, 0x08, 0xA7, - 0x04, 0xF0, 0x80, 0x06, 0x12, 0x08, 0xA7, 0x74, -/*1BE0*/0x04, 0xF0, 0xEE, 0x44, 0x82, 0xFE, 0xEF, 0x44, - 0x07, 0xF5, 0x82, 0x8E, 0x83, 0xE5, 0x45, 0x12, -/*1BF0*/0x08, 0xBE, 0x75, 0x83, 0x82, 0xE5, 0x31, 0xF0, - 0x02, 0x11, 0x4C, 0x8E, 0x60, 0x8F, 0x61, 0x12, -/*1C00*/0x1E, 0xA5, 0xE4, 0xFF, 0xCE, 0xED, 0xCE, 0xEE, - 0xD3, 0x95, 0x61, 0xE5, 0x60, 0x12, 0x07, 0x6B, -/*1C10*/0x40, 0x39, 0x74, 0x20, 0x2E, 0xF5, 0x82, 0xE4, - 0x34, 0x03, 0xF5, 0x83, 0xE0, 0x70, 0x03, 0xFF, -/*1C20*/0x80, 0x26, 0x12, 0x08, 0xE2, 0xFD, 0xC3, 0x9F, - 0x40, 0x1E, 0xCF, 0xED, 0xCF, 0xEB, 0x4A, 0x70, -/*1C30*/0x0B, 0x8D, 0x42, 0x12, 0x08, 0xEE, 0xF5, 0x41, - 0x8E, 0x40, 0x80, 0x0C, 0x12, 0x08, 0xE2, 0xF5, -/*1C40*/0x38, 0x12, 0x08, 0xEE, 0xF5, 0x39, 0x8E, 0x3A, - 0x1E, 0x80, 0xBC, 0x22, 0x75, 0x58, 0x01, 0xE5, -/*1C50*/0x35, 0x70, 0x0C, 0x12, 0x07, 0xCC, 0xE0, 0xF5, - 0x4A, 0x12, 0x07, 0xD8, 0xE0, 0xF5, 0x4C, 0xE5, -/*1C60*/0x35, 0xB4, 0x04, 0x0C, 0x12, 0x07, 0xE4, 0xE0, - 0xF5, 0x4A, 0x12, 0x07, 0xF0, 0xE0, 0xF5, 0x4C, -/*1C70*/0xE5, 0x35, 0xB4, 0x01, 0x04, 0x7F, 0x01, 0x80, - 0x02, 0x7F, 0x00, 0xE5, 0x35, 0xB4, 0x02, 0x04, -/*1C80*/0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, - 0x60, 0x0C, 0x12, 0x07, 0xFC, 0xE0, 0xF5, 0x4A, -/*1C90*/0x12, 0x08, 0x08, 0xE0, 0xF5, 0x4C, 0x85, 0x41, - 0x49, 0x85, 0x40, 0x4B, 0x22, 0x75, 0x5B, 0x01, -/*1CA0*/0x90, 0x07, 0x24, 0x12, 0x07, 0x35, 0xE0, 0x54, - 0x1F, 0xFF, 0xD3, 0x94, 0x02, 0x50, 0x04, 0x8F, -/*1CB0*/0x58, 0x80, 0x05, 0xEF, 0x24, 0xFE, 0xF5, 0x58, - 0xEF, 0xC3, 0x94, 0x18, 0x40, 0x05, 0x75, 0x59, -/*1CC0*/0x18, 0x80, 0x04, 0xEF, 0x04, 0xF5, 0x59, 0x85, - 0x43, 0x5A, 0xAF, 0x58, 0x7E, 0x00, 0xAD, 0x59, -/*1CD0*/0x7C, 0x00, 0xAB, 0x5B, 0x7A, 0x00, 0x12, 0x15, - 0x41, 0xAF, 0x5A, 0x7E, 0x00, 0x12, 0x18, 0x0A, -/*1CE0*/0xAF, 0x5B, 0x7E, 0x00, 0x02, 0x1A, 0xFF, 0xE5, - 0xE2, 0x30, 0xE7, 0x0E, 0x12, 0x10, 0x03, 0xC2, -/*1CF0*/0x30, 0x30, 0x30, 0x03, 0x12, 0x10, 0xFF, 0x20, - 0x33, 0x28, 0xE5, 0xE7, 0x30, 0xE7, 0x05, 0x12, -/*1D00*/0x0E, 0xA2, 0x80, 0x0D, 0xE5, 0xFE, 0xC3, 0x94, - 0x20, 0x50, 0x06, 0x12, 0x0E, 0xA2, 0x43, 0xF9, -/*1D10*/0x08, 0xE5, 0xF2, 0x30, 0xE7, 0x03, 0x53, 0xF9, - 0x7F, 0xE5, 0xF1, 0x54, 0x70, 0xD3, 0x94, 0x00, -/*1D20*/0x50, 0xD8, 0x22, 0x12, 0x0E, 0x04, 0x75, 0x83, - 0x80, 0xE4, 0xF0, 0xE5, 0x08, 0x44, 0x07, 0x12, -/*1D30*/0x0D, 0xFD, 0x75, 0x83, 0x84, 0x12, 0x0E, 0x02, - 0x75, 0x83, 0x86, 0x12, 0x0E, 0x02, 0x75, 0x83, -/*1D40*/0x8C, 0xE0, 0x54, 0xF3, 0x12, 0x0E, 0x03, 0x75, - 0x83, 0x8E, 0x12, 0x0E, 0x02, 0x75, 0x83, 0x94, -/*1D50*/0xE0, 0x54, 0xFB, 0xF0, 0x22, 0x12, 0x07, 0x2A, - 0x75, 0x83, 0x8E, 0xE4, 0x12, 0x07, 0x29, 0x74, -/*1D60*/0x01, 0x12, 0x07, 0x29, 0xE4, 0x12, 0x08, 0xBE, - 0x75, 0x83, 0x8C, 0xE0, 0x44, 0x20, 0x12, 0x08, -/*1D70*/0xBE, 0xE0, 0x54, 0xDF, 0xF0, 0x74, 0x84, 0x85, - 0x08, 0x82, 0xF5, 0x83, 0xE0, 0x54, 0x7F, 0xF0, -/*1D80*/0xE0, 0x44, 0x80, 0xF0, 0x22, 0x75, 0x56, 0x01, - 0xE4, 0xFD, 0xF5, 0x57, 0xAF, 0x35, 0xFE, 0xFC, -/*1D90*/0x12, 0x09, 0x15, 0x12, 0x1C, 0x9D, 0x12, 0x1E, - 0x7A, 0x12, 0x1C, 0x4C, 0xAF, 0x57, 0x7E, 0x00, -/*1DA0*/0xAD, 0x56, 0x7C, 0x00, 0x12, 0x04, 0x44, 0xAF, - 0x56, 0x7E, 0x00, 0x02, 0x11, 0xEE, 0x75, 0x56, -/*1DB0*/0x01, 0xE4, 0xFD, 0xF5, 0x57, 0xAF, 0x35, 0xFE, - 0xFC, 0x12, 0x09, 0x15, 0x12, 0x1C, 0x9D, 0x12, -/*1DC0*/0x1E, 0x7A, 0x12, 0x1C, 0x4C, 0xAF, 0x57, 0x7E, - 0x00, 0xAD, 0x56, 0x7C, 0x00, 0x12, 0x04, 0x44, -/*1DD0*/0xAF, 0x56, 0x7E, 0x00, 0x02, 0x11, 0xEE, 0xE4, - 0xF5, 0x16, 0x12, 0x0E, 0x44, 0xFE, 0xE5, 0x08, -/*1DE0*/0x44, 0x05, 0xFF, 0x12, 0x0E, 0x65, 0x8F, 0x82, - 0x8E, 0x83, 0xF0, 0x05, 0x16, 0xE5, 0x16, 0xC3, -/*1DF0*/0x94, 0x14, 0x40, 0xE6, 0xE5, 0x08, 0x12, 0x0E, - 0x2B, 0xE4, 0xF0, 0x22, 0xE4, 0xF5, 0x58, 0xF5, -/*1E00*/0x59, 0xF5, 0x5A, 0xFF, 0xFE, 0xAD, 0x58, 0xFC, - 0x12, 0x09, 0x15, 0x7F, 0x04, 0x7E, 0x00, 0xAD, -/*1E10*/0x58, 0x7C, 0x00, 0x12, 0x09, 0x15, 0x7F, 0x02, - 0x7E, 0x00, 0xAD, 0x58, 0x7C, 0x00, 0x02, 0x09, -/*1E20*/0x15, 0xE5, 0x3C, 0x25, 0x3E, 0xFC, 0xE5, 0x42, - 0x24, 0x00, 0xFB, 0xE4, 0x33, 0xFA, 0xEC, 0xC3, -/*1E30*/0x9B, 0xEA, 0x12, 0x07, 0x6B, 0x40, 0x0B, 0x8C, - 0x42, 0xE5, 0x3D, 0x25, 0x3F, 0xF5, 0x41, 0x8F, -/*1E40*/0x40, 0x22, 0x12, 0x09, 0x0B, 0x22, 0x74, 0x84, - 0xF5, 0x18, 0x85, 0x08, 0x19, 0x85, 0x19, 0x82, -/*1E50*/0x85, 0x18, 0x83, 0xE0, 0x54, 0x7F, 0xF0, 0xE0, - 0x44, 0x80, 0xF0, 0xE0, 0x44, 0x80, 0xF0, 0x22, -/*1E60*/0xEF, 0x4E, 0x70, 0x0B, 0x12, 0x07, 0x2A, 0x75, - 0x83, 0xD2, 0xE0, 0x54, 0xDF, 0xF0, 0x22, 0x12, -/*1E70*/0x07, 0x2A, 0x75, 0x83, 0xD2, 0xE0, 0x44, 0x20, - 0xF0, 0x22, 0x75, 0x58, 0x01, 0x90, 0x07, 0x26, -/*1E80*/0x12, 0x07, 0x35, 0xE0, 0x54, 0x3F, 0xF5, 0x41, - 0x12, 0x07, 0x32, 0xE0, 0x54, 0x3F, 0xF5, 0x40, -/*1E90*/0x22, 0x75, 0x56, 0x02, 0xE4, 0xF5, 0x57, 0x12, - 0x1D, 0xFC, 0xAF, 0x57, 0x7E, 0x00, 0xAD, 0x56, -/*1EA0*/0x7C, 0x00, 0x02, 0x04, 0x44, 0xE4, 0xF5, 0x42, - 0xF5, 0x41, 0xF5, 0x40, 0xF5, 0x38, 0xF5, 0x39, -/*1EB0*/0xF5, 0x3A, 0x22, 0xEF, 0x54, 0x07, 0xFF, 0xE5, - 0xF9, 0x54, 0xF8, 0x4F, 0xF5, 0xF9, 0x22, 0x7F, -/*1EC0*/0x01, 0xE4, 0xFE, 0x0F, 0x0E, 0xBE, 0xFF, 0xFB, - 0x22, 0x01, 0x20, 0x00, 0x01, 0x04, 0x20, 0x00, -/*1ED0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/*1EE0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/*1EF0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/*1F00*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/*1F10*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/*1F20*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/*1F30*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/*1F40*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/*1F50*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/*1F60*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/*1F70*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/*1F80*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/*1F90*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/*1FA0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/*1FB0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/*1FC0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/*1FD0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/*1FE0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/*1FF0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x20, 0x11, 0x00, 0x04, 0x20, 0x00, 0x81 -}; - -int qib_sd7220_ib_load(struct qib_devdata *dd) -{ - return qib_sd7220_prog_ld(dd, IB_7220_SERDES, qib_sd7220_ib_img, - sizeof(qib_sd7220_ib_img), 0); -} - -int qib_sd7220_ib_vfy(struct qib_devdata *dd) -{ - return qib_sd7220_prog_vfy(dd, IB_7220_SERDES, qib_sd7220_ib_img, - sizeof(qib_sd7220_ib_img), 0); -} diff --git a/drivers/infiniband/hw/qib/qib_tx.c b/drivers/infiniband/hw/qib/qib_tx.c index f7eb1ddff5f..af30232b683 100644 --- a/drivers/infiniband/hw/qib/qib_tx.c +++ b/drivers/infiniband/hw/qib/qib_tx.c @@ -340,9 +340,13 @@ rescan: if (i < dd->piobcnt2k) buf = (u32 __iomem *)(dd->pio2kbase + i * dd->palign); - else + else if (i < dd->piobcnt2k + dd->piobcnt4k || !dd->piovl15base) buf = (u32 __iomem *)(dd->pio4kbase + (i - dd->piobcnt2k) * dd->align4k); + else + buf = (u32 __iomem *)(dd->piovl15base + + (i - (dd->piobcnt2k + dd->piobcnt4k)) * + dd->align4k); if (pbufnum) *pbufnum = i; dd->upd_pio_shadow = 0; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index df3eb8c9fd9..b4b22576f12 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1163,7 +1163,7 @@ static ssize_t create_child(struct device *dev, return ret ? ret : count; } -static DEVICE_ATTR(create_child, S_IWUGO, NULL, create_child); +static DEVICE_ATTR(create_child, S_IWUSR, NULL, create_child); static ssize_t delete_child(struct device *dev, struct device_attribute *attr, @@ -1183,7 +1183,7 @@ static ssize_t delete_child(struct device *dev, return ret ? ret : count; } -static DEVICE_ATTR(delete_child, S_IWUGO, NULL, delete_child); +static DEVICE_ATTR(delete_child, S_IWUSR, NULL, delete_child); int ipoib_add_pkey_attr(struct net_device *dev) { diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index fbd62abb66f..0ffaf2c77a1 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -89,7 +89,6 @@ struct gc_pad { struct gc { struct pardevice *pd; struct gc_pad pads[GC_MAX_DEVICES]; - struct input_dev *dev[GC_MAX_DEVICES]; struct timer_list timer; int pad_count[GC_MAX]; int used; @@ -387,7 +386,7 @@ static void gc_nes_process_packet(struct gc *gc) for (i = 0; i < GC_MAX_DEVICES; i++) { pad = &gc->pads[i]; - dev = gc->dev[i]; + dev = pad->dev; s = gc_status_bit[i]; switch (pad->type) { @@ -579,7 +578,7 @@ static void gc_psx_command(struct gc *gc, int b, unsigned char *data) read = parport_read_status(port) ^ 0x80; for (j = 0; j < GC_MAX_DEVICES; j++) { - struct gc_pad *pad = &gc->pads[i]; + struct gc_pad *pad = &gc->pads[j]; if (pad->type == GC_PSX || pad->type == GC_DDR) data[j] |= (read & gc_status_bit[j]) ? (1 << i) : 0; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 0f9a4785d79..1ba25145b33 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -69,11 +69,11 @@ config KEYBOARD_ATARI module will be called atakbd. config KEYBOARD_ATKBD - tristate "AT keyboard" if EMBEDDED || !X86 || X86_MRST + tristate "AT keyboard" if EMBEDDED || !X86 default y select SERIO select SERIO_LIBPS2 - select SERIO_I8042 if X86 && !X86_MRST + select SERIO_I8042 if X86 select SERIO_GSCPS2 if GSC help Say Y here if you want to use a standard AT or PS/2 keyboard. Usually @@ -124,7 +124,7 @@ config KEYBOARD_ATKBD_RDI_KEYCODES right-hand column will be interpreted as the key shown in the left-hand column. -config QT2160 +config KEYBOARD_QT2160 tristate "Atmel AT42QT2160 Touch Sensor Chip" depends on I2C && EXPERIMENTAL help diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index 7aa59e07b68..fb16b5e5ea1 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c @@ -51,8 +51,12 @@ */ #define TWL4030_MAX_ROWS 8 /* TWL4030 hard limit */ #define TWL4030_MAX_COLS 8 -#define TWL4030_ROW_SHIFT 3 -#define TWL4030_KEYMAP_SIZE (TWL4030_MAX_ROWS * TWL4030_MAX_COLS) +/* + * Note that we add space for an extra column so that we can handle + * row lines connected to the gnd (see twl4030_col_xlate()). + */ +#define TWL4030_ROW_SHIFT 4 +#define TWL4030_KEYMAP_SIZE (TWL4030_MAX_ROWS << TWL4030_ROW_SHIFT) struct twl4030_keypad { unsigned short keymap[TWL4030_KEYMAP_SIZE]; @@ -182,7 +186,7 @@ static int twl4030_read_kp_matrix_state(struct twl4030_keypad *kp, u16 *state) return ret; } -static int twl4030_is_in_ghost_state(struct twl4030_keypad *kp, u16 *key_state) +static bool twl4030_is_in_ghost_state(struct twl4030_keypad *kp, u16 *key_state) { int i; u16 check = 0; @@ -191,12 +195,12 @@ static int twl4030_is_in_ghost_state(struct twl4030_keypad *kp, u16 *key_state) u16 col = key_state[i]; if ((col & check) && hweight16(col) > 1) - return 1; + return true; check |= col; } - return 0; + return false; } static void twl4030_kp_scan(struct twl4030_keypad *kp, bool release_all) @@ -225,7 +229,8 @@ static void twl4030_kp_scan(struct twl4030_keypad *kp, bool release_all) if (!changed) continue; - for (col = 0; col < kp->n_cols; col++) { + /* Extra column handles "all gnd" rows */ + for (col = 0; col < kp->n_cols + 1; col++) { int code; if (!(changed & (1 << col))) diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c index 4ef764cc493..ee2bf6bcf29 100644 --- a/drivers/input/keyboard/w90p910_keypad.c +++ b/drivers/input/keyboard/w90p910_keypad.c @@ -258,7 +258,7 @@ static struct platform_driver w90p910_keypad_driver = { .probe = w90p910_keypad_probe, .remove = __devexit_p(w90p910_keypad_remove), .driver = { - .name = "nuc900-keypad", + .name = "nuc900-kpi", .owner = THIS_MODULE, }, }; diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index eeb58c1cac1..c714ca2407f 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -17,7 +17,7 @@ config MOUSE_PS2 default y select SERIO select SERIO_LIBPS2 - select SERIO_I8042 if X86 && !X86_MRST + select SERIO_I8042 if X86 select SERIO_GSCPS2 if GSC help Say Y here if you have a PS/2 mouse connected to your system. This diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 40cea334ad1..705589dc9ac 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -141,8 +141,13 @@ static int synaptics_capability(struct psmouse *psmouse) priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2]; priv->ext_cap = priv->ext_cap_0c = 0; - if (!SYN_CAP_VALID(priv->capabilities)) + /* + * Older firmwares had submodel ID fixed to 0x47 + */ + if (SYN_ID_FULL(priv->identity) < 0x705 && + SYN_CAP_SUBMODEL_ID(priv->capabilities) != 0x47) { return -1; + } /* * Unless capExtended is set the rest of the flags should be ignored @@ -206,6 +211,7 @@ static int synaptics_resolution(struct psmouse *psmouse) unsigned char max[3]; if (SYN_ID_MAJOR(priv->identity) < 4) + return 0; if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, res) == 0) { if (res[0] != 0 && (res[1] & 0x80) && res[2] != 0) { diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 7d4d5e12c0d..b6aa7d20d8a 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -47,7 +47,7 @@ #define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3)) #define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1)) #define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0)) -#define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47) +#define SYN_CAP_SUBMODEL_ID(c) (((c) & 0x00ff00) >> 8) #define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20) #define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12) #define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16) @@ -66,6 +66,7 @@ #define SYN_ID_MODEL(i) (((i) >> 4) & 0x0f) #define SYN_ID_MAJOR(i) ((i) & 0x0f) #define SYN_ID_MINOR(i) (((i) >> 16) & 0xff) +#define SYN_ID_FULL(i) ((SYN_ID_MAJOR(i) << 8) | SYN_ID_MINOR(i)) #define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47) /* synaptics special commands */ diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index 256b9e9394d..3bfe8fafc6a 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -22,7 +22,7 @@ config SERIO_I8042 tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86 default y depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && \ - (!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN && !X86_MRST + (!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN help i8042 is the chip over which the standard AT keyboard and PS/2 mouse are connected to the computer. If you use these devices, diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 6168469ad1a..ed7ad7416b2 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -7,6 +7,10 @@ * the Free Software Foundation. */ +#ifdef CONFIG_X86 +#include <asm/x86_init.h> +#endif + /* * Names. */ @@ -166,6 +170,13 @@ static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = { }, }, { + /* Gigabyte Spring Peak - defines wrong chassis type */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), + DMI_MATCH(DMI_PRODUCT_NAME, "Spring Peak"), + }, + }, + { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv9700"), @@ -840,6 +851,12 @@ static int __init i8042_platform_init(void) { int retval; +#ifdef CONFIG_X86 + /* Just return if pre-detection shows no i8042 controller exist */ + if (!x86_platform.i8042_detect()) + return -ENODEV; +#endif + /* * On ix86 platforms touching the i8042 data register region can do really * bad things. Because of this the region is always reserved on ix86 boxes. diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c index cc18265be1a..7a45d68c351 100644 --- a/drivers/input/touchscreen/w90p910_ts.c +++ b/drivers/input/touchscreen/w90p910_ts.c @@ -233,7 +233,7 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev) w90p910_ts->state = TS_IDLE; spin_lock_init(&w90p910_ts->lock); setup_timer(&w90p910_ts->timer, w90p910_check_pen_up, - (unsigned long)&w90p910_ts); + (unsigned long)w90p910_ts); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 81bf25e67ce..e4112622e5a 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -302,6 +302,15 @@ config LEDS_MC13783 This option enable support for on-chip LED drivers found on Freescale Semiconductor MC13783 PMIC. +config LEDS_NS2 + tristate "LED support for Network Space v2 GPIO LEDs" + depends on MACH_NETSPACE_V2 || MACH_INETSPACE_V2 || MACH_NETSPACE_MAX_V2 + default y + help + This option enable support for the dual-GPIO LED found on the + Network Space v2 board (and parents). This include Internet Space v2, + Network Space (Max) v2 and d2 Network v2 boards. + config LEDS_TRIGGERS bool "LED Trigger support" help diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 2493de49937..7d6b95831f8 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_LEDS_LT3593) += leds-lt3593.o obj-$(CONFIG_LEDS_ADP5520) += leds-adp5520.o obj-$(CONFIG_LEDS_DELL_NETBOOKS) += dell-led.o obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o +obj-$(CONFIG_LEDS_NS2) += leds-ns2.o # LED SPI Drivers obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c new file mode 100644 index 00000000000..74dce4ba026 --- /dev/null +++ b/drivers/leds/leds-ns2.c @@ -0,0 +1,338 @@ +/* + * leds-ns2.c - Driver for the Network Space v2 (and parents) dual-GPIO LED + * + * Copyright (C) 2010 LaCie + * + * Author: Simon Guinot <sguinot@lacie.com> + * + * Based on leds-gpio.c by Raphael Assenat <raph@8d.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. + * + * This program is distributed in the hope that 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/leds.h> +#include <mach/leds-ns2.h> + +/* + * The Network Space v2 dual-GPIO LED is wired to a CPLD and can blink in + * relation with the SATA activity. This capability is exposed through the + * "sata" sysfs attribute. + * + * The following array detail the different LED registers and the combination + * of their possible values: + * + * cmd_led | slow_led | /SATA active | LED state + * | | | + * 1 | 0 | x | off + * - | 1 | x | on + * 0 | 0 | 1 | on + * 0 | 0 | 0 | blink (rate 300ms) + */ + +enum ns2_led_modes { + NS_V2_LED_OFF, + NS_V2_LED_ON, + NS_V2_LED_SATA, +}; + +struct ns2_led_mode_value { + enum ns2_led_modes mode; + int cmd_level; + int slow_level; +}; + +static struct ns2_led_mode_value ns2_led_modval[] = { + { NS_V2_LED_OFF , 1, 0 }, + { NS_V2_LED_ON , 0, 1 }, + { NS_V2_LED_ON , 1, 1 }, + { NS_V2_LED_SATA, 0, 0 }, +}; + +struct ns2_led_data { + struct led_classdev cdev; + unsigned cmd; + unsigned slow; + unsigned char sata; /* True when SATA mode active. */ + rwlock_t rw_lock; /* Lock GPIOs. */ +}; + +static int ns2_led_get_mode(struct ns2_led_data *led_dat, + enum ns2_led_modes *mode) +{ + int i; + int ret = -EINVAL; + int cmd_level; + int slow_level; + + read_lock(&led_dat->rw_lock); + + cmd_level = gpio_get_value(led_dat->cmd); + slow_level = gpio_get_value(led_dat->slow); + + for (i = 0; i < ARRAY_SIZE(ns2_led_modval); i++) { + if (cmd_level == ns2_led_modval[i].cmd_level && + slow_level == ns2_led_modval[i].slow_level) { + *mode = ns2_led_modval[i].mode; + ret = 0; + break; + } + } + + read_unlock(&led_dat->rw_lock); + + return ret; +} + +static void ns2_led_set_mode(struct ns2_led_data *led_dat, + enum ns2_led_modes mode) +{ + int i; + + write_lock(&led_dat->rw_lock); + + for (i = 0; i < ARRAY_SIZE(ns2_led_modval); i++) { + if (mode == ns2_led_modval[i].mode) { + gpio_set_value(led_dat->cmd, + ns2_led_modval[i].cmd_level); + gpio_set_value(led_dat->slow, + ns2_led_modval[i].slow_level); + } + } + + write_unlock(&led_dat->rw_lock); +} + +static void ns2_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct ns2_led_data *led_dat = + container_of(led_cdev, struct ns2_led_data, cdev); + enum ns2_led_modes mode; + + if (value == LED_OFF) + mode = NS_V2_LED_OFF; + else if (led_dat->sata) + mode = NS_V2_LED_SATA; + else + mode = NS_V2_LED_ON; + + ns2_led_set_mode(led_dat, mode); +} + +static ssize_t ns2_led_sata_store(struct device *dev, + struct device_attribute *attr, + const char *buff, size_t count) +{ + int ret; + unsigned long enable; + enum ns2_led_modes mode; + struct ns2_led_data *led_dat = dev_get_drvdata(dev); + + ret = strict_strtoul(buff, 10, &enable); + if (ret < 0) + return ret; + + enable = !!enable; + + if (led_dat->sata == enable) + return count; + + ret = ns2_led_get_mode(led_dat, &mode); + if (ret < 0) + return ret; + + if (enable && mode == NS_V2_LED_ON) + ns2_led_set_mode(led_dat, NS_V2_LED_SATA); + if (!enable && mode == NS_V2_LED_SATA) + ns2_led_set_mode(led_dat, NS_V2_LED_ON); + + led_dat->sata = enable; + + return count; +} + +static ssize_t ns2_led_sata_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ns2_led_data *led_dat = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", led_dat->sata); +} + +static DEVICE_ATTR(sata, 0644, ns2_led_sata_show, ns2_led_sata_store); + +static int __devinit +create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, + const struct ns2_led *template) +{ + int ret; + enum ns2_led_modes mode; + + ret = gpio_request(template->cmd, template->name); + if (ret == 0) { + ret = gpio_direction_output(template->cmd, + gpio_get_value(template->cmd)); + if (ret) + gpio_free(template->cmd); + } + if (ret) { + dev_err(&pdev->dev, "%s: failed to setup command GPIO\n", + template->name); + } + + ret = gpio_request(template->slow, template->name); + if (ret == 0) { + ret = gpio_direction_output(template->slow, + gpio_get_value(template->slow)); + if (ret) + gpio_free(template->slow); + } + if (ret) { + dev_err(&pdev->dev, "%s: failed to setup slow GPIO\n", + template->name); + goto err_free_cmd; + } + + rwlock_init(&led_dat->rw_lock); + + led_dat->cdev.name = template->name; + led_dat->cdev.default_trigger = template->default_trigger; + led_dat->cdev.blink_set = NULL; + led_dat->cdev.brightness_set = ns2_led_set; + led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; + led_dat->cmd = template->cmd; + led_dat->slow = template->slow; + + ret = ns2_led_get_mode(led_dat, &mode); + if (ret < 0) + goto err_free_slow; + + /* Set LED initial state. */ + led_dat->sata = (mode == NS_V2_LED_SATA) ? 1 : 0; + led_dat->cdev.brightness = + (mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL; + + ret = led_classdev_register(&pdev->dev, &led_dat->cdev); + if (ret < 0) + goto err_free_slow; + + dev_set_drvdata(led_dat->cdev.dev, led_dat); + ret = device_create_file(led_dat->cdev.dev, &dev_attr_sata); + if (ret < 0) + goto err_free_cdev; + + return 0; + +err_free_cdev: + led_classdev_unregister(&led_dat->cdev); +err_free_slow: + gpio_free(led_dat->slow); +err_free_cmd: + gpio_free(led_dat->cmd); + + return ret; +} + +static void __devexit delete_ns2_led(struct ns2_led_data *led_dat) +{ + device_remove_file(led_dat->cdev.dev, &dev_attr_sata); + led_classdev_unregister(&led_dat->cdev); + gpio_free(led_dat->cmd); + gpio_free(led_dat->slow); +} + +static int __devinit ns2_led_probe(struct platform_device *pdev) +{ + struct ns2_led_platform_data *pdata = pdev->dev.platform_data; + struct ns2_led_data *leds_data; + int i; + int ret; + + if (!pdata) + return -EINVAL; + + leds_data = kzalloc(sizeof(struct ns2_led_data) * + pdata->num_leds, GFP_KERNEL); + if (!leds_data) + return -ENOMEM; + + for (i = 0; i < pdata->num_leds; i++) { + ret = create_ns2_led(pdev, &leds_data[i], &pdata->leds[i]); + if (ret < 0) + goto err; + + } + + platform_set_drvdata(pdev, leds_data); + + return 0; + +err: + for (i = i - 1; i >= 0; i--) + delete_ns2_led(&leds_data[i]); + + kfree(leds_data); + + return ret; +} + +static int __devexit ns2_led_remove(struct platform_device *pdev) +{ + int i; + struct ns2_led_platform_data *pdata = pdev->dev.platform_data; + struct ns2_led_data *leds_data; + + leds_data = platform_get_drvdata(pdev); + + for (i = 0; i < pdata->num_leds; i++) + delete_ns2_led(&leds_data[i]); + + kfree(leds_data); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver ns2_led_driver = { + .probe = ns2_led_probe, + .remove = __devexit_p(ns2_led_remove), + .driver = { + .name = "leds-ns2", + .owner = THIS_MODULE, + }, +}; +MODULE_ALIAS("platform:leds-ns2"); + +static int __init ns2_led_init(void) +{ + return platform_driver_register(&ns2_led_driver); +} + +static void __exit ns2_led_exit(void) +{ + platform_driver_unregister(&ns2_led_driver); +} + +module_init(ns2_led_init); +module_exit(ns2_led_exit); + +MODULE_AUTHOR("Simon Guinot <sguinot@lacie.com>"); +MODULE_DESCRIPTION("Network Space v2 LED driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c index 8abbcc5fcf9..8cf2ab609d5 100644 --- a/drivers/media/common/tuners/tuner-simple.c +++ b/drivers/media/common/tuners/tuner-simple.c @@ -524,6 +524,7 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer) buffer[3] = 0x39; break; case TUNER_PHILIPS_FQ1216LME_MK3: + case TUNER_PHILIPS_FQ1236_MK5: tuner_err("This tuner doesn't have FM\n"); /* Set the low band for sanity, since it covers 88-108 MHz */ buffer[3] = 0x01; diff --git a/drivers/media/common/tuners/tuner-types.c b/drivers/media/common/tuners/tuner-types.c index d9aaaca620c..58a513bcd74 100644 --- a/drivers/media/common/tuners/tuner-types.c +++ b/drivers/media/common/tuners/tuner-types.c @@ -1353,6 +1353,17 @@ static struct tuner_params tuner_sony_btf_pxn01z_params[] = { }, }; +/* ------------ TUNER_PHILIPS_FQ1236_MK5 - Philips NTSC ------------ */ + +static struct tuner_params tuner_philips_fq1236_mk5_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_fm1236_mk3_ntsc_ranges, + .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), + .has_tda9887 = 1, /* TDA9885, no FM radio */ + }, +}; + /* --------------------------------------------------------------------- */ struct tunertype tuners[] = { @@ -1826,6 +1837,11 @@ struct tunertype tuners[] = { .params = tuner_sony_btf_pxn01z_params, .count = ARRAY_SIZE(tuner_sony_btf_pxn01z_params), }, + [TUNER_PHILIPS_FQ1236_MK5] = { /* NTSC, TDA9885, no FM radio */ + .name = "Philips FQ1236 MK5", + .params = tuner_philips_fq1236_mk5_params, + .count = ARRAY_SIZE(tuner_philips_fq1236_mk5_params), + }, }; EXPORT_SYMBOL(tuners); diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index bdbc9d30541..27e2acce3c3 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -969,6 +969,19 @@ config VIDEO_OMAP2 ---help--- This is a v4l2 driver for the TI OMAP2 camera capture interface +config VIDEO_MX2_HOSTSUPPORT + bool + +config VIDEO_MX2 + tristate "i.MX27/i.MX25 Camera Sensor Interface driver" + depends on VIDEO_DEV && SOC_CAMERA && (MACH_MX27 || ARCH_MX25) + select VIDEOBUF_DMA_CONTIG + select VIDEO_MX2_HOSTSUPPORT + ---help--- + This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor + Interface + + # # USB Multimedia device configuration # diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index cc93859d316..b08bd2b65cd 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -162,6 +162,7 @@ obj-$(CONFIG_SOC_CAMERA) += soc_camera.o soc_mediabus.o obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o # soc-camera host drivers have to be linked after camera drivers obj-$(CONFIG_VIDEO_MX1) += mx1_camera.o +obj-$(CONFIG_VIDEO_MX2) += mx2_camera.o obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 9ecacab4b89..a937e2ff9b6 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -912,6 +912,9 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts) clear_bit(IVTV_F_S_STREAMING, &s->s_flags); ivtv_flush_queues(s); + /* decoder needs time to settle */ + ivtv_msleep_timeout(40, 0); + /* decrement decoding */ atomic_dec(&itv->decoding); diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c index 554eaf14012..10ddeccc70e 100644 --- a/drivers/media/video/mem2mem_testdev.c +++ b/drivers/media/video/mem2mem_testdev.c @@ -988,6 +988,9 @@ static int m2mtest_probe(struct platform_device *pdev) goto err_m2m; } + q_data[V4L2_M2M_SRC].fmt = &formats[0]; + q_data[V4L2_M2M_DST].fmt = &formats[0]; + return 0; err_m2m: diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c new file mode 100644 index 00000000000..026bef0ba40 --- /dev/null +++ b/drivers/media/video/mx2_camera.c @@ -0,0 +1,1513 @@ +/* + * V4L2 Driver for i.MX27/i.MX25 camera host + * + * Copyright (C) 2008, Sascha Hauer, Pengutronix + * Copyright (C) 2010, Baruch Siach, Orex Computed Radiography + * + * 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/init.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/dma-mapping.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/moduleparam.h> +#include <linux/time.h> +#include <linux/version.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/mutex.h> +#include <linux/clk.h> + +#include <media/v4l2-common.h> +#include <media/v4l2-dev.h> +#include <media/videobuf-dma-contig.h> +#include <media/soc_camera.h> +#include <media/soc_mediabus.h> + +#include <linux/videodev2.h> + +#include <mach/mx2_cam.h> +#ifdef CONFIG_MACH_MX27 +#include <mach/dma-mx1-mx2.h> +#endif +#include <mach/hardware.h> + +#include <asm/dma.h> + +#define MX2_CAM_DRV_NAME "mx2-camera" +#define MX2_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5) +#define MX2_CAM_DRIVER_DESCRIPTION "i.MX2x_Camera" + +/* reset values */ +#define CSICR1_RESET_VAL 0x40000800 +#define CSICR2_RESET_VAL 0x0 +#define CSICR3_RESET_VAL 0x0 + +/* csi control reg 1 */ +#define CSICR1_SWAP16_EN (1 << 31) +#define CSICR1_EXT_VSYNC (1 << 30) +#define CSICR1_EOF_INTEN (1 << 29) +#define CSICR1_PRP_IF_EN (1 << 28) +#define CSICR1_CCIR_MODE (1 << 27) +#define CSICR1_COF_INTEN (1 << 26) +#define CSICR1_SF_OR_INTEN (1 << 25) +#define CSICR1_RF_OR_INTEN (1 << 24) +#define CSICR1_STATFF_LEVEL (3 << 22) +#define CSICR1_STATFF_INTEN (1 << 21) +#define CSICR1_RXFF_LEVEL(l) (((l) & 3) << 19) /* MX27 */ +#define CSICR1_FB2_DMA_INTEN (1 << 20) /* MX25 */ +#define CSICR1_FB1_DMA_INTEN (1 << 19) /* MX25 */ +#define CSICR1_RXFF_INTEN (1 << 18) +#define CSICR1_SOF_POL (1 << 17) +#define CSICR1_SOF_INTEN (1 << 16) +#define CSICR1_MCLKDIV(d) (((d) & 0xF) << 12) +#define CSICR1_HSYNC_POL (1 << 11) +#define CSICR1_CCIR_EN (1 << 10) +#define CSICR1_MCLKEN (1 << 9) +#define CSICR1_FCC (1 << 8) +#define CSICR1_PACK_DIR (1 << 7) +#define CSICR1_CLR_STATFIFO (1 << 6) +#define CSICR1_CLR_RXFIFO (1 << 5) +#define CSICR1_GCLK_MODE (1 << 4) +#define CSICR1_INV_DATA (1 << 3) +#define CSICR1_INV_PCLK (1 << 2) +#define CSICR1_REDGE (1 << 1) + +#define SHIFT_STATFF_LEVEL 22 +#define SHIFT_RXFF_LEVEL 19 +#define SHIFT_MCLKDIV 12 + +/* control reg 3 */ +#define CSICR3_FRMCNT (0xFFFF << 16) +#define CSICR3_FRMCNT_RST (1 << 15) +#define CSICR3_DMA_REFLASH_RFF (1 << 14) +#define CSICR3_DMA_REFLASH_SFF (1 << 13) +#define CSICR3_DMA_REQ_EN_RFF (1 << 12) +#define CSICR3_DMA_REQ_EN_SFF (1 << 11) +#define CSICR3_RXFF_LEVEL(l) (((l) & 7) << 4) /* MX25 */ +#define CSICR3_CSI_SUP (1 << 3) +#define CSICR3_ZERO_PACK_EN (1 << 2) +#define CSICR3_ECC_INT_EN (1 << 1) +#define CSICR3_ECC_AUTO_EN (1 << 0) + +#define SHIFT_FRMCNT 16 + +/* csi status reg */ +#define CSISR_SFF_OR_INT (1 << 25) +#define CSISR_RFF_OR_INT (1 << 24) +#define CSISR_STATFF_INT (1 << 21) +#define CSISR_DMA_TSF_FB2_INT (1 << 20) /* MX25 */ +#define CSISR_DMA_TSF_FB1_INT (1 << 19) /* MX25 */ +#define CSISR_RXFF_INT (1 << 18) +#define CSISR_EOF_INT (1 << 17) +#define CSISR_SOF_INT (1 << 16) +#define CSISR_F2_INT (1 << 15) +#define CSISR_F1_INT (1 << 14) +#define CSISR_COF_INT (1 << 13) +#define CSISR_ECC_INT (1 << 1) +#define CSISR_DRDY (1 << 0) + +#define CSICR1 0x00 +#define CSICR2 0x04 +#define CSISR (cpu_is_mx27() ? 0x08 : 0x18) +#define CSISTATFIFO 0x0c +#define CSIRFIFO 0x10 +#define CSIRXCNT 0x14 +#define CSICR3 (cpu_is_mx27() ? 0x1C : 0x08) +#define CSIDMASA_STATFIFO 0x20 +#define CSIDMATA_STATFIFO 0x24 +#define CSIDMASA_FB1 0x28 +#define CSIDMASA_FB2 0x2c +#define CSIFBUF_PARA 0x30 +#define CSIIMAG_PARA 0x34 + +/* EMMA PrP */ +#define PRP_CNTL 0x00 +#define PRP_INTR_CNTL 0x04 +#define PRP_INTRSTATUS 0x08 +#define PRP_SOURCE_Y_PTR 0x0c +#define PRP_SOURCE_CB_PTR 0x10 +#define PRP_SOURCE_CR_PTR 0x14 +#define PRP_DEST_RGB1_PTR 0x18 +#define PRP_DEST_RGB2_PTR 0x1c +#define PRP_DEST_Y_PTR 0x20 +#define PRP_DEST_CB_PTR 0x24 +#define PRP_DEST_CR_PTR 0x28 +#define PRP_SRC_FRAME_SIZE 0x2c +#define PRP_DEST_CH1_LINE_STRIDE 0x30 +#define PRP_SRC_PIXEL_FORMAT_CNTL 0x34 +#define PRP_CH1_PIXEL_FORMAT_CNTL 0x38 +#define PRP_CH1_OUT_IMAGE_SIZE 0x3c +#define PRP_CH2_OUT_IMAGE_SIZE 0x40 +#define PRP_SRC_LINE_STRIDE 0x44 +#define PRP_CSC_COEF_012 0x48 +#define PRP_CSC_COEF_345 0x4c +#define PRP_CSC_COEF_678 0x50 +#define PRP_CH1_RZ_HORI_COEF1 0x54 +#define PRP_CH1_RZ_HORI_COEF2 0x58 +#define PRP_CH1_RZ_HORI_VALID 0x5c +#define PRP_CH1_RZ_VERT_COEF1 0x60 +#define PRP_CH1_RZ_VERT_COEF2 0x64 +#define PRP_CH1_RZ_VERT_VALID 0x68 +#define PRP_CH2_RZ_HORI_COEF1 0x6c +#define PRP_CH2_RZ_HORI_COEF2 0x70 +#define PRP_CH2_RZ_HORI_VALID 0x74 +#define PRP_CH2_RZ_VERT_COEF1 0x78 +#define PRP_CH2_RZ_VERT_COEF2 0x7c +#define PRP_CH2_RZ_VERT_VALID 0x80 + +#define PRP_CNTL_CH1EN (1 << 0) +#define PRP_CNTL_CH2EN (1 << 1) +#define PRP_CNTL_CSIEN (1 << 2) +#define PRP_CNTL_DATA_IN_YUV420 (0 << 3) +#define PRP_CNTL_DATA_IN_YUV422 (1 << 3) +#define PRP_CNTL_DATA_IN_RGB16 (2 << 3) +#define PRP_CNTL_DATA_IN_RGB32 (3 << 3) +#define PRP_CNTL_CH1_OUT_RGB8 (0 << 5) +#define PRP_CNTL_CH1_OUT_RGB16 (1 << 5) +#define PRP_CNTL_CH1_OUT_RGB32 (2 << 5) +#define PRP_CNTL_CH1_OUT_YUV422 (3 << 5) +#define PRP_CNTL_CH2_OUT_YUV420 (0 << 7) +#define PRP_CNTL_CH2_OUT_YUV422 (1 << 7) +#define PRP_CNTL_CH2_OUT_YUV444 (2 << 7) +#define PRP_CNTL_CH1_LEN (1 << 9) +#define PRP_CNTL_CH2_LEN (1 << 10) +#define PRP_CNTL_SKIP_FRAME (1 << 11) +#define PRP_CNTL_SWRST (1 << 12) +#define PRP_CNTL_CLKEN (1 << 13) +#define PRP_CNTL_WEN (1 << 14) +#define PRP_CNTL_CH1BYP (1 << 15) +#define PRP_CNTL_IN_TSKIP(x) ((x) << 16) +#define PRP_CNTL_CH1_TSKIP(x) ((x) << 19) +#define PRP_CNTL_CH2_TSKIP(x) ((x) << 22) +#define PRP_CNTL_INPUT_FIFO_LEVEL(x) ((x) << 25) +#define PRP_CNTL_RZ_FIFO_LEVEL(x) ((x) << 27) +#define PRP_CNTL_CH2B1EN (1 << 29) +#define PRP_CNTL_CH2B2EN (1 << 30) +#define PRP_CNTL_CH2FEN (1 << 31) + +/* IRQ Enable and status register */ +#define PRP_INTR_RDERR (1 << 0) +#define PRP_INTR_CH1WERR (1 << 1) +#define PRP_INTR_CH2WERR (1 << 2) +#define PRP_INTR_CH1FC (1 << 3) +#define PRP_INTR_CH2FC (1 << 5) +#define PRP_INTR_LBOVF (1 << 7) +#define PRP_INTR_CH2OVF (1 << 8) + +#define mx27_camera_emma(pcdev) (cpu_is_mx27() && pcdev->use_emma) + +#define MAX_VIDEO_MEM 16 + +struct mx2_camera_dev { + struct device *dev; + struct soc_camera_host soc_host; + struct soc_camera_device *icd; + struct clk *clk_csi, *clk_emma; + + unsigned int irq_csi, irq_emma; + void __iomem *base_csi, *base_emma; + unsigned long base_dma; + + struct mx2_camera_platform_data *pdata; + struct resource *res_csi, *res_emma; + unsigned long platform_flags; + + struct list_head capture; + struct list_head active_bufs; + + spinlock_t lock; + + int dma; + struct mx2_buffer *active; + struct mx2_buffer *fb1_active; + struct mx2_buffer *fb2_active; + + int use_emma; + + u32 csicr1; + + void *discard_buffer; + dma_addr_t discard_buffer_dma; + size_t discard_size; +}; + +/* buffer for one video frame */ +struct mx2_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + enum v4l2_mbus_pixelcode code; + + int bufnum; +}; + +static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev) +{ + unsigned long flags; + + clk_disable(pcdev->clk_csi); + writel(0, pcdev->base_csi + CSICR1); + if (mx27_camera_emma(pcdev)) { + writel(0, pcdev->base_emma + PRP_CNTL); + } else if (cpu_is_mx25()) { + spin_lock_irqsave(&pcdev->lock, flags); + pcdev->fb1_active = NULL; + pcdev->fb2_active = NULL; + writel(0, pcdev->base_csi + CSIDMASA_FB1); + writel(0, pcdev->base_csi + CSIDMASA_FB2); + spin_unlock_irqrestore(&pcdev->lock, flags); + } +} + +/* + * The following two functions absolutely depend on the fact, that + * there can be only one camera on mx2 camera sensor interface + */ +static int mx2_camera_add_device(struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx2_camera_dev *pcdev = ici->priv; + int ret; + u32 csicr1; + + if (pcdev->icd) + return -EBUSY; + + ret = clk_enable(pcdev->clk_csi); + if (ret < 0) + return ret; + + csicr1 = CSICR1_MCLKEN; + + if (mx27_camera_emma(pcdev)) { + csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC | + CSICR1_RXFF_LEVEL(0); + } else if (cpu_is_mx27()) + csicr1 |= CSICR1_SOF_INTEN | CSICR1_RXFF_LEVEL(2); + + pcdev->csicr1 = csicr1; + writel(pcdev->csicr1, pcdev->base_csi + CSICR1); + + pcdev->icd = icd; + + dev_info(icd->dev.parent, "Camera driver attached to camera %d\n", + icd->devnum); + + return 0; +} + +static void mx2_camera_remove_device(struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx2_camera_dev *pcdev = ici->priv; + + BUG_ON(icd != pcdev->icd); + + dev_info(icd->dev.parent, "Camera driver detached from camera %d\n", + icd->devnum); + + mx2_camera_deactivate(pcdev); + + if (pcdev->discard_buffer) { + dma_free_coherent(ici->v4l2_dev.dev, pcdev->discard_size, + pcdev->discard_buffer, + pcdev->discard_buffer_dma); + pcdev->discard_buffer = NULL; + } + + pcdev->icd = NULL; +} + +#ifdef CONFIG_MACH_MX27 +static void mx27_camera_dma_enable(struct mx2_camera_dev *pcdev) +{ + u32 tmp; + + imx_dma_enable(pcdev->dma); + + tmp = readl(pcdev->base_csi + CSICR1); + tmp |= CSICR1_RF_OR_INTEN; + writel(tmp, pcdev->base_csi + CSICR1); +} + +static irqreturn_t mx27_camera_irq(int irq_csi, void *data) +{ + struct mx2_camera_dev *pcdev = data; + u32 status = readl(pcdev->base_csi + CSISR); + + if (status & CSISR_SOF_INT && pcdev->active) { + u32 tmp; + + tmp = readl(pcdev->base_csi + CSICR1); + writel(tmp | CSICR1_CLR_RXFIFO, pcdev->base_csi + CSICR1); + mx27_camera_dma_enable(pcdev); + } + + writel(CSISR_SOF_INT | CSISR_RFF_OR_INT, pcdev->base_csi + CSISR); + + return IRQ_HANDLED; +} +#else +static irqreturn_t mx27_camera_irq(int irq_csi, void *data) +{ + return IRQ_NONE; +} +#endif /* CONFIG_MACH_MX27 */ + +static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb, + int state) +{ + struct videobuf_buffer *vb; + struct mx2_buffer *buf; + struct mx2_buffer **fb_active = fb == 1 ? &pcdev->fb1_active : + &pcdev->fb2_active; + u32 fb_reg = fb == 1 ? CSIDMASA_FB1 : CSIDMASA_FB2; + unsigned long flags; + + spin_lock_irqsave(&pcdev->lock, flags); + + vb = &(*fb_active)->vb; + dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + vb, vb->baddr, vb->bsize); + + vb->state = state; + do_gettimeofday(&vb->ts); + vb->field_count++; + + wake_up(&vb->done); + + if (list_empty(&pcdev->capture)) { + buf = NULL; + writel(0, pcdev->base_csi + fb_reg); + } else { + buf = list_entry(pcdev->capture.next, struct mx2_buffer, + vb.queue); + vb = &buf->vb; + list_del(&vb->queue); + vb->state = VIDEOBUF_ACTIVE; + writel(videobuf_to_dma_contig(vb), pcdev->base_csi + fb_reg); + } + + *fb_active = buf; + + spin_unlock_irqrestore(&pcdev->lock, flags); +} + +static irqreturn_t mx25_camera_irq(int irq_csi, void *data) +{ + struct mx2_camera_dev *pcdev = data; + u32 status = readl(pcdev->base_csi + CSISR); + + if (status & CSISR_DMA_TSF_FB1_INT) + mx25_camera_frame_done(pcdev, 1, VIDEOBUF_DONE); + else if (status & CSISR_DMA_TSF_FB2_INT) + mx25_camera_frame_done(pcdev, 2, VIDEOBUF_DONE); + + /* FIXME: handle CSISR_RFF_OR_INT */ + + writel(status, pcdev->base_csi + CSISR); + + return IRQ_HANDLED; +} + +/* + * Videobuf operations + */ +static int mx2_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, + unsigned int *size) +{ + struct soc_camera_device *icd = vq->priv_data; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size); + + if (bytes_per_line < 0) + return bytes_per_line; + + *size = bytes_per_line * icd->user_height; + + if (0 == *count) + *count = 32; + if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024) + *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size; + + return 0; +} + +static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf) +{ + struct soc_camera_device *icd = vq->priv_data; + struct videobuf_buffer *vb = &buf->vb; + + dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + vb, vb->baddr, vb->bsize); + + /* + * This waits until this buffer is out of danger, i.e., until it is no + * longer in STATE_QUEUED or STATE_ACTIVE + */ + videobuf_waiton(vb, 0, 0); + + videobuf_dma_contig_free(vq, vb); + dev_dbg(&icd->dev, "%s freed\n", __func__); + + vb->state = VIDEOBUF_NEEDS_INIT; +} + +static int mx2_videobuf_prepare(struct videobuf_queue *vq, + struct videobuf_buffer *vb, enum v4l2_field field) +{ + struct soc_camera_device *icd = vq->priv_data; + struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + int ret = 0; + + dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + vb, vb->baddr, vb->bsize); + + if (bytes_per_line < 0) + return bytes_per_line; + +#ifdef DEBUG + /* + * This can be useful if you want to see if we actually fill + * the buffer with something + */ + memset((void *)vb->baddr, 0xaa, vb->bsize); +#endif + + if (buf->code != icd->current_fmt->code || + vb->width != icd->user_width || + vb->height != icd->user_height || + vb->field != field) { + buf->code = icd->current_fmt->code; + vb->width = icd->user_width; + vb->height = icd->user_height; + vb->field = field; + vb->state = VIDEOBUF_NEEDS_INIT; + } + + vb->size = bytes_per_line * vb->height; + if (vb->baddr && vb->bsize < vb->size) { + ret = -EINVAL; + goto out; + } + + if (vb->state == VIDEOBUF_NEEDS_INIT) { + ret = videobuf_iolock(vq, vb, NULL); + if (ret) + goto fail; + + vb->state = VIDEOBUF_PREPARED; + } + + return 0; + +fail: + free_buffer(vq, buf); +out: + return ret; +} + +static void mx2_videobuf_queue(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + struct soc_camera_device *icd = vq->priv_data; + struct soc_camera_host *ici = + to_soc_camera_host(icd->dev.parent); + struct mx2_camera_dev *pcdev = ici->priv; + struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); + unsigned long flags; + + dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + vb, vb->baddr, vb->bsize); + + spin_lock_irqsave(&pcdev->lock, flags); + + vb->state = VIDEOBUF_QUEUED; + list_add_tail(&vb->queue, &pcdev->capture); + + if (mx27_camera_emma(pcdev)) { + goto out; +#ifdef CONFIG_MACH_MX27 + } else if (cpu_is_mx27()) { + int ret; + + if (pcdev->active == NULL) { + ret = imx_dma_setup_single(pcdev->dma, + videobuf_to_dma_contig(vb), vb->size, + (u32)pcdev->base_dma + 0x10, + DMA_MODE_READ); + if (ret) { + vb->state = VIDEOBUF_ERROR; + wake_up(&vb->done); + goto out; + } + + vb->state = VIDEOBUF_ACTIVE; + pcdev->active = buf; + } +#endif + } else { /* cpu_is_mx25() */ + u32 csicr3, dma_inten = 0; + + if (pcdev->fb1_active == NULL) { + writel(videobuf_to_dma_contig(vb), + pcdev->base_csi + CSIDMASA_FB1); + pcdev->fb1_active = buf; + dma_inten = CSICR1_FB1_DMA_INTEN; + } else if (pcdev->fb2_active == NULL) { + writel(videobuf_to_dma_contig(vb), + pcdev->base_csi + CSIDMASA_FB2); + pcdev->fb2_active = buf; + dma_inten = CSICR1_FB2_DMA_INTEN; + } + + if (dma_inten) { + list_del(&vb->queue); + vb->state = VIDEOBUF_ACTIVE; + + csicr3 = readl(pcdev->base_csi + CSICR3); + + /* Reflash DMA */ + writel(csicr3 | CSICR3_DMA_REFLASH_RFF, + pcdev->base_csi + CSICR3); + + /* clear & enable interrupts */ + writel(dma_inten, pcdev->base_csi + CSISR); + pcdev->csicr1 |= dma_inten; + writel(pcdev->csicr1, pcdev->base_csi + CSICR1); + + /* enable DMA */ + csicr3 |= CSICR3_DMA_REQ_EN_RFF | CSICR3_RXFF_LEVEL(1); + writel(csicr3, pcdev->base_csi + CSICR3); + } + } + +out: + spin_unlock_irqrestore(&pcdev->lock, flags); +} + +static void mx2_videobuf_release(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + struct soc_camera_device *icd = vq->priv_data; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx2_camera_dev *pcdev = ici->priv; + struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); + unsigned long flags; + +#ifdef DEBUG + dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + vb, vb->baddr, vb->bsize); + + switch (vb->state) { + case VIDEOBUF_ACTIVE: + dev_info(&icd->dev, "%s (active)\n", __func__); + break; + case VIDEOBUF_QUEUED: + dev_info(&icd->dev, "%s (queued)\n", __func__); + break; + case VIDEOBUF_PREPARED: + dev_info(&icd->dev, "%s (prepared)\n", __func__); + break; + default: + dev_info(&icd->dev, "%s (unknown) %d\n", __func__, + vb->state); + break; + } +#endif + + /* + * Terminate only queued but inactive buffers. Active buffers are + * released when they become inactive after videobuf_waiton(). + * + * FIXME: implement forced termination of active buffers, so that the + * user won't get stuck in an uninterruptible state. This requires a + * specific handling for each of the three DMA types that this driver + * supports. + */ + spin_lock_irqsave(&pcdev->lock, flags); + if (vb->state == VIDEOBUF_QUEUED) { + list_del(&vb->queue); + vb->state = VIDEOBUF_ERROR; + } + spin_unlock_irqrestore(&pcdev->lock, flags); + + free_buffer(vq, buf); +} + +static struct videobuf_queue_ops mx2_videobuf_ops = { + .buf_setup = mx2_videobuf_setup, + .buf_prepare = mx2_videobuf_prepare, + .buf_queue = mx2_videobuf_queue, + .buf_release = mx2_videobuf_release, +}; + +static void mx2_camera_init_videobuf(struct videobuf_queue *q, + struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx2_camera_dev *pcdev = ici->priv; + + videobuf_queue_dma_contig_init(q, &mx2_videobuf_ops, pcdev->dev, + &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_NONE, sizeof(struct mx2_buffer), icd); +} + +#define MX2_BUS_FLAGS (SOCAM_DATAWIDTH_8 | \ + SOCAM_MASTER | \ + SOCAM_VSYNC_ACTIVE_HIGH | \ + SOCAM_VSYNC_ACTIVE_LOW | \ + SOCAM_HSYNC_ACTIVE_HIGH | \ + SOCAM_HSYNC_ACTIVE_LOW | \ + SOCAM_PCLK_SAMPLE_RISING | \ + SOCAM_PCLK_SAMPLE_FALLING | \ + SOCAM_DATA_ACTIVE_HIGH | \ + SOCAM_DATA_ACTIVE_LOW) + +static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev) +{ + u32 cntl; + int count = 0; + + cntl = readl(pcdev->base_emma + PRP_CNTL); + writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL); + while (count++ < 100) { + if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST)) + return 0; + barrier(); + udelay(1); + } + + return -ETIMEDOUT; +} + +static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, + int bytesperline) +{ + struct soc_camera_host *ici = + to_soc_camera_host(icd->dev.parent); + struct mx2_camera_dev *pcdev = ici->priv; + + writel(pcdev->discard_buffer_dma, + pcdev->base_emma + PRP_DEST_RGB1_PTR); + writel(pcdev->discard_buffer_dma, + pcdev->base_emma + PRP_DEST_RGB2_PTR); + + /* + * We only use the EMMA engine to get rid of the broken + * DMA Engine. No color space consversion at the moment. + * We adjust incoming and outgoing pixelformat to rgb16 + * and adjust the bytesperline accordingly. + */ + writel(PRP_CNTL_CH1EN | + PRP_CNTL_CSIEN | + PRP_CNTL_DATA_IN_RGB16 | + PRP_CNTL_CH1_OUT_RGB16 | + PRP_CNTL_CH1_LEN | + PRP_CNTL_CH1BYP | + PRP_CNTL_CH1_TSKIP(0) | + PRP_CNTL_IN_TSKIP(0), + pcdev->base_emma + PRP_CNTL); + + writel(((bytesperline >> 1) << 16) | icd->user_height, + pcdev->base_emma + PRP_SRC_FRAME_SIZE); + writel(((bytesperline >> 1) << 16) | icd->user_height, + pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE); + writel(bytesperline, + pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE); + writel(0x2ca00565, /* RGB565 */ + pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); + writel(0x2ca00565, /* RGB565 */ + pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL); + + /* Enable interrupts */ + writel(PRP_INTR_RDERR | + PRP_INTR_CH1WERR | + PRP_INTR_CH2WERR | + PRP_INTR_CH1FC | + PRP_INTR_CH2FC | + PRP_INTR_LBOVF | + PRP_INTR_CH2OVF, + pcdev->base_emma + PRP_INTR_CNTL); +} + +static int mx2_camera_set_bus_param(struct soc_camera_device *icd, + __u32 pixfmt) +{ + struct soc_camera_host *ici = + to_soc_camera_host(icd->dev.parent); + struct mx2_camera_dev *pcdev = ici->priv; + unsigned long camera_flags, common_flags; + int ret = 0; + int bytesperline; + u32 csicr1 = pcdev->csicr1; + + camera_flags = icd->ops->query_bus_param(icd); + + common_flags = soc_camera_bus_param_compatible(camera_flags, + MX2_BUS_FLAGS); + if (!common_flags) + return -EINVAL; + + if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && + (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { + if (pcdev->platform_flags & MX2_CAMERA_HSYNC_HIGH) + common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; + else + common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; + } + + if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && + (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { + if (pcdev->platform_flags & MX2_CAMERA_PCLK_SAMPLE_RISING) + common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; + else + common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; + } + + ret = icd->ops->set_bus_param(icd, common_flags); + if (ret < 0) + return ret; + + if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) + csicr1 |= CSICR1_INV_PCLK; + if (common_flags & SOCAM_VSYNC_ACTIVE_HIGH) + csicr1 |= CSICR1_SOF_POL; + if (common_flags & SOCAM_HSYNC_ACTIVE_HIGH) + csicr1 |= CSICR1_HSYNC_POL; + if (pcdev->platform_flags & MX2_CAMERA_SWAP16) + csicr1 |= CSICR1_SWAP16_EN; + if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC) + csicr1 |= CSICR1_EXT_VSYNC; + if (pcdev->platform_flags & MX2_CAMERA_CCIR) + csicr1 |= CSICR1_CCIR_EN; + if (pcdev->platform_flags & MX2_CAMERA_CCIR_INTERLACE) + csicr1 |= CSICR1_CCIR_MODE; + if (pcdev->platform_flags & MX2_CAMERA_GATED_CLOCK) + csicr1 |= CSICR1_GCLK_MODE; + if (pcdev->platform_flags & MX2_CAMERA_INV_DATA) + csicr1 |= CSICR1_INV_DATA; + if (pcdev->platform_flags & MX2_CAMERA_PACK_DIR_MSB) + csicr1 |= CSICR1_PACK_DIR; + + pcdev->csicr1 = csicr1; + + bytesperline = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + if (bytesperline < 0) + return bytesperline; + + if (mx27_camera_emma(pcdev)) { + ret = mx27_camera_emma_prp_reset(pcdev); + if (ret) + return ret; + + if (pcdev->discard_buffer) + dma_free_coherent(ici->v4l2_dev.dev, + pcdev->discard_size, pcdev->discard_buffer, + pcdev->discard_buffer_dma); + + /* + * I didn't manage to properly enable/disable the prp + * on a per frame basis during running transfers, + * thus we allocate a buffer here and use it to + * discard frames when no buffer is available. + * Feel free to work on this ;) + */ + pcdev->discard_size = icd->user_height * bytesperline; + pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev, + pcdev->discard_size, &pcdev->discard_buffer_dma, + GFP_KERNEL); + if (!pcdev->discard_buffer) + return -ENOMEM; + + mx27_camera_emma_buf_init(icd, bytesperline); + } else if (cpu_is_mx25()) { + writel((bytesperline * icd->user_height) >> 2, + pcdev->base_csi + CSIRXCNT); + writel((bytesperline << 16) | icd->user_height, + pcdev->base_csi + CSIIMAG_PARA); + } + + writel(pcdev->csicr1, pcdev->base_csi + CSICR1); + + return 0; +} + +static int mx2_camera_set_crop(struct soc_camera_device *icd, + struct v4l2_crop *a) +{ + struct v4l2_rect *rect = &a->c; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct v4l2_mbus_framefmt mf; + int ret; + + soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096); + soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096); + + ret = v4l2_subdev_call(sd, video, s_crop, a); + if (ret < 0) + return ret; + + /* The capture device might have changed its output */ + ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); + if (ret < 0) + return ret; + + dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n", + mf.width, mf.height); + + icd->user_width = mf.width; + icd->user_height = mf.height; + + return ret; +} + +static int mx2_camera_set_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx2_camera_dev *pcdev = ici->priv; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + const struct soc_camera_format_xlate *xlate; + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_mbus_framefmt mf; + int ret; + + xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); + if (!xlate) { + dev_warn(icd->dev.parent, "Format %x not found\n", + pix->pixelformat); + return -EINVAL; + } + + /* eMMA can only do RGB565 */ + if (mx27_camera_emma(pcdev) && pix->pixelformat != V4L2_PIX_FMT_RGB565) + return -EINVAL; + + mf.width = pix->width; + mf.height = pix->height; + mf.field = pix->field; + mf.colorspace = pix->colorspace; + mf.code = xlate->code; + + ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + if (ret < 0 && ret != -ENOIOCTLCMD) + return ret; + + if (mf.code != xlate->code) + return -EINVAL; + + pix->width = mf.width; + pix->height = mf.height; + pix->field = mf.field; + pix->colorspace = mf.colorspace; + icd->current_fmt = xlate; + + return 0; +} + +static int mx2_camera_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx2_camera_dev *pcdev = ici->priv; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + const struct soc_camera_format_xlate *xlate; + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_mbus_framefmt mf; + __u32 pixfmt = pix->pixelformat; + unsigned int width_limit; + int ret; + + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); + if (pixfmt && !xlate) { + dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt); + return -EINVAL; + } + + /* FIXME: implement MX27 limits */ + + /* eMMA can only do RGB565 */ + if (mx27_camera_emma(pcdev) && pixfmt != V4L2_PIX_FMT_RGB565) + return -EINVAL; + + /* limit to MX25 hardware capabilities */ + if (cpu_is_mx25()) { + if (xlate->host_fmt->bits_per_sample <= 8) + width_limit = 0xffff * 4; + else + width_limit = 0xffff * 2; + /* CSIIMAG_PARA limit */ + if (pix->width > width_limit) + pix->width = width_limit; + if (pix->height > 0xffff) + pix->height = 0xffff; + + pix->bytesperline = soc_mbus_bytes_per_line(pix->width, + xlate->host_fmt); + if (pix->bytesperline < 0) + return pix->bytesperline; + pix->sizeimage = pix->height * pix->bytesperline; + if (pix->sizeimage > (4 * 0x3ffff)) { /* CSIRXCNT limit */ + dev_warn(icd->dev.parent, + "Image size (%u) above limit\n", + pix->sizeimage); + return -EINVAL; + } + } + + /* limit to sensor capabilities */ + mf.width = pix->width; + mf.height = pix->height; + mf.field = pix->field; + mf.colorspace = pix->colorspace; + mf.code = xlate->code; + + ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); + if (ret < 0) + return ret; + + if (mf.field == V4L2_FIELD_ANY) + mf.field = V4L2_FIELD_NONE; + if (mf.field != V4L2_FIELD_NONE) { + dev_err(icd->dev.parent, "Field type %d unsupported.\n", + mf.field); + return -EINVAL; + } + + pix->width = mf.width; + pix->height = mf.height; + pix->field = mf.field; + pix->colorspace = mf.colorspace; + + return 0; +} + +static int mx2_camera_querycap(struct soc_camera_host *ici, + struct v4l2_capability *cap) +{ + /* cap->name is set by the friendly caller:-> */ + strlcpy(cap->card, MX2_CAM_DRIVER_DESCRIPTION, sizeof(cap->card)); + cap->version = MX2_CAM_VERSION_CODE; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + + return 0; +} + +static int mx2_camera_reqbufs(struct soc_camera_file *icf, + struct v4l2_requestbuffers *p) +{ + int i; + + for (i = 0; i < p->count; i++) { + struct mx2_buffer *buf = container_of(icf->vb_vidq.bufs[i], + struct mx2_buffer, vb); + INIT_LIST_HEAD(&buf->vb.queue); + } + + return 0; +} + +#ifdef CONFIG_MACH_MX27 +static void mx27_camera_frame_done(struct mx2_camera_dev *pcdev, int state) +{ + struct videobuf_buffer *vb; + struct mx2_buffer *buf; + unsigned long flags; + int ret; + + spin_lock_irqsave(&pcdev->lock, flags); + + if (!pcdev->active) { + dev_err(pcdev->dev, "%s called with no active buffer!\n", + __func__); + goto out; + } + + vb = &pcdev->active->vb; + buf = container_of(vb, struct mx2_buffer, vb); + WARN_ON(list_empty(&vb->queue)); + dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + vb, vb->baddr, vb->bsize); + + /* _init is used to debug races, see comment in pxa_camera_reqbufs() */ + list_del_init(&vb->queue); + vb->state = state; + do_gettimeofday(&vb->ts); + vb->field_count++; + + wake_up(&vb->done); + + if (list_empty(&pcdev->capture)) { + pcdev->active = NULL; + goto out; + } + + pcdev->active = list_entry(pcdev->capture.next, + struct mx2_buffer, vb.queue); + + vb = &pcdev->active->vb; + vb->state = VIDEOBUF_ACTIVE; + + ret = imx_dma_setup_single(pcdev->dma, videobuf_to_dma_contig(vb), + vb->size, (u32)pcdev->base_dma + 0x10, DMA_MODE_READ); + + if (ret) { + vb->state = VIDEOBUF_ERROR; + pcdev->active = NULL; + wake_up(&vb->done); + } + +out: + spin_unlock_irqrestore(&pcdev->lock, flags); +} + +static void mx27_camera_dma_err_callback(int channel, void *data, int err) +{ + struct mx2_camera_dev *pcdev = data; + + mx27_camera_frame_done(pcdev, VIDEOBUF_ERROR); +} + +static void mx27_camera_dma_callback(int channel, void *data) +{ + struct mx2_camera_dev *pcdev = data; + + mx27_camera_frame_done(pcdev, VIDEOBUF_DONE); +} + +#define DMA_REQ_CSI_RX 31 /* FIXME: Add this to a resource */ + +static int __devinit mx27_camera_dma_init(struct platform_device *pdev, + struct mx2_camera_dev *pcdev) +{ + int err; + + pcdev->dma = imx_dma_request_by_prio("CSI RX DMA", DMA_PRIO_HIGH); + if (pcdev->dma < 0) { + dev_err(&pdev->dev, "%s failed to request DMA channel\n", + __func__); + return pcdev->dma; + } + + err = imx_dma_setup_handlers(pcdev->dma, mx27_camera_dma_callback, + mx27_camera_dma_err_callback, pcdev); + if (err) { + dev_err(&pdev->dev, "%s failed to set DMA callback\n", + __func__); + goto err_out; + } + + err = imx_dma_config_channel(pcdev->dma, + IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_FIFO, + IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, + DMA_REQ_CSI_RX, 1); + if (err) { + dev_err(&pdev->dev, "%s failed to config DMA channel\n", + __func__); + goto err_out; + } + + imx_dma_config_burstlen(pcdev->dma, 64); + + return 0; + +err_out: + imx_dma_free(pcdev->dma); + + return err; +} +#endif /* CONFIG_MACH_MX27 */ + +static unsigned int mx2_camera_poll(struct file *file, poll_table *pt) +{ + struct soc_camera_file *icf = file->private_data; + + return videobuf_poll_stream(file, &icf->vb_vidq, pt); +} + +static struct soc_camera_host_ops mx2_soc_camera_host_ops = { + .owner = THIS_MODULE, + .add = mx2_camera_add_device, + .remove = mx2_camera_remove_device, + .set_fmt = mx2_camera_set_fmt, + .set_crop = mx2_camera_set_crop, + .try_fmt = mx2_camera_try_fmt, + .init_videobuf = mx2_camera_init_videobuf, + .reqbufs = mx2_camera_reqbufs, + .poll = mx2_camera_poll, + .querycap = mx2_camera_querycap, + .set_bus_param = mx2_camera_set_bus_param, +}; + +static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, + int bufnum, int state) +{ + struct mx2_buffer *buf; + struct videobuf_buffer *vb; + unsigned long phys; + + if (!list_empty(&pcdev->active_bufs)) { + buf = list_entry(pcdev->active_bufs.next, + struct mx2_buffer, vb.queue); + + BUG_ON(buf->bufnum != bufnum); + + vb = &buf->vb; +#ifdef DEBUG + phys = videobuf_to_dma_contig(vb); + if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum) + != phys) { + dev_err(pcdev->dev, "%p != %p\n", phys, + readl(pcdev->base_emma + + PRP_DEST_RGB1_PTR + + 4 * bufnum)); + } +#endif + dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, + vb->baddr, vb->bsize); + + list_del(&vb->queue); + vb->state = state; + do_gettimeofday(&vb->ts); + vb->field_count++; + + wake_up(&vb->done); + } + + if (list_empty(&pcdev->capture)) { + writel(pcdev->discard_buffer_dma, pcdev->base_emma + + PRP_DEST_RGB1_PTR + 4 * bufnum); + return; + } + + buf = list_entry(pcdev->capture.next, + struct mx2_buffer, vb.queue); + + buf->bufnum = bufnum; + + list_move_tail(pcdev->capture.next, &pcdev->active_bufs); + + vb = &buf->vb; + vb->state = VIDEOBUF_ACTIVE; + + phys = videobuf_to_dma_contig(vb); + writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum); +} + +static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) +{ + struct mx2_camera_dev *pcdev = data; + unsigned int status = readl(pcdev->base_emma + PRP_INTRSTATUS); + struct mx2_buffer *buf; + + if (status & (1 << 7)) { /* overflow */ + u32 cntl; + /* + * We only disable channel 1 here since this is the only + * enabled channel + * + * FIXME: the correct DMA overflow handling should be resetting + * the buffer, returning an error frame, and continuing with + * the next one. + */ + cntl = readl(pcdev->base_emma + PRP_CNTL); + writel(cntl & ~PRP_CNTL_CH1EN, pcdev->base_emma + PRP_CNTL); + writel(cntl, pcdev->base_emma + PRP_CNTL); + } + if ((status & (3 << 5)) == (3 << 5) + && !list_empty(&pcdev->active_bufs)) { + /* + * Both buffers have triggered, process the one we're expecting + * to first + */ + buf = list_entry(pcdev->active_bufs.next, + struct mx2_buffer, vb.queue); + mx27_camera_frame_done_emma(pcdev, buf->bufnum, VIDEOBUF_DONE); + status &= ~(1 << (6 - buf->bufnum)); /* mark processed */ + } + if (status & (1 << 6)) + mx27_camera_frame_done_emma(pcdev, 0, VIDEOBUF_DONE); + if (status & (1 << 5)) + mx27_camera_frame_done_emma(pcdev, 1, VIDEOBUF_DONE); + + writel(status, pcdev->base_emma + PRP_INTRSTATUS); + + return IRQ_HANDLED; +} + +static int __devinit mx27_camera_emma_init(struct mx2_camera_dev *pcdev) +{ + struct resource *res_emma = pcdev->res_emma; + int err = 0; + + if (!request_mem_region(res_emma->start, resource_size(res_emma), + MX2_CAM_DRV_NAME)) { + err = -EBUSY; + goto out; + } + + pcdev->base_emma = ioremap(res_emma->start, resource_size(res_emma)); + if (!pcdev->base_emma) { + err = -ENOMEM; + goto exit_release; + } + + err = request_irq(pcdev->irq_emma, mx27_camera_emma_irq, 0, + MX2_CAM_DRV_NAME, pcdev); + if (err) { + dev_err(pcdev->dev, "Camera EMMA interrupt register failed \n"); + goto exit_iounmap; + } + + pcdev->clk_emma = clk_get(NULL, "emma"); + if (IS_ERR(pcdev->clk_emma)) { + err = PTR_ERR(pcdev->clk_emma); + goto exit_free_irq; + } + + clk_enable(pcdev->clk_emma); + + err = mx27_camera_emma_prp_reset(pcdev); + if (err) + goto exit_clk_emma_put; + + return err; + +exit_clk_emma_put: + clk_disable(pcdev->clk_emma); + clk_put(pcdev->clk_emma); +exit_free_irq: + free_irq(pcdev->irq_emma, pcdev); +exit_iounmap: + iounmap(pcdev->base_emma); +exit_release: + release_mem_region(res_emma->start, resource_size(res_emma)); +out: + return err; +} + +static int __devinit mx2_camera_probe(struct platform_device *pdev) +{ + struct mx2_camera_dev *pcdev; + struct resource *res_csi, *res_emma; + void __iomem *base_csi; + int irq_csi, irq_emma; + irq_handler_t mx2_cam_irq_handler = cpu_is_mx25() ? mx25_camera_irq + : mx27_camera_irq; + int err = 0; + + dev_dbg(&pdev->dev, "initialising\n"); + + res_csi = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq_csi = platform_get_irq(pdev, 0); + if (res_csi == NULL || irq_csi < 0) { + dev_err(&pdev->dev, "Missing platform resources data\n"); + err = -ENODEV; + goto exit; + } + + pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL); + if (!pcdev) { + dev_err(&pdev->dev, "Could not allocate pcdev\n"); + err = -ENOMEM; + goto exit; + } + + pcdev->clk_csi = clk_get(&pdev->dev, NULL); + if (IS_ERR(pcdev->clk_csi)) { + err = PTR_ERR(pcdev->clk_csi); + goto exit_kfree; + } + + dev_dbg(&pdev->dev, "Camera clock frequency: %ld\n", + clk_get_rate(pcdev->clk_csi)); + + /* Initialize DMA */ +#ifdef CONFIG_MACH_MX27 + if (cpu_is_mx27()) { + err = mx27_camera_dma_init(pdev, pcdev); + if (err) + goto exit_clk_put; + } +#endif /* CONFIG_MACH_MX27 */ + + pcdev->res_csi = res_csi; + pcdev->pdata = pdev->dev.platform_data; + if (pcdev->pdata) { + long rate; + + pcdev->platform_flags = pcdev->pdata->flags; + + rate = clk_round_rate(pcdev->clk_csi, pcdev->pdata->clk * 2); + if (rate <= 0) { + err = -ENODEV; + goto exit_dma_free; + } + err = clk_set_rate(pcdev->clk_csi, rate); + if (err < 0) + goto exit_dma_free; + } + + INIT_LIST_HEAD(&pcdev->capture); + INIT_LIST_HEAD(&pcdev->active_bufs); + spin_lock_init(&pcdev->lock); + + /* + * Request the regions. + */ + if (!request_mem_region(res_csi->start, resource_size(res_csi), + MX2_CAM_DRV_NAME)) { + err = -EBUSY; + goto exit_dma_free; + } + + base_csi = ioremap(res_csi->start, resource_size(res_csi)); + if (!base_csi) { + err = -ENOMEM; + goto exit_release; + } + pcdev->irq_csi = irq_csi; + pcdev->base_csi = base_csi; + pcdev->base_dma = res_csi->start; + pcdev->dev = &pdev->dev; + + err = request_irq(pcdev->irq_csi, mx2_cam_irq_handler, 0, + MX2_CAM_DRV_NAME, pcdev); + if (err) { + dev_err(pcdev->dev, "Camera interrupt register failed \n"); + goto exit_iounmap; + } + + if (cpu_is_mx27()) { + /* EMMA support */ + res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 1); + irq_emma = platform_get_irq(pdev, 1); + + if (res_emma && irq_emma >= 0) { + dev_info(&pdev->dev, "Using EMMA\n"); + pcdev->use_emma = 1; + pcdev->res_emma = res_emma; + pcdev->irq_emma = irq_emma; + if (mx27_camera_emma_init(pcdev)) + goto exit_free_irq; + } + } + + pcdev->soc_host.drv_name = MX2_CAM_DRV_NAME, + pcdev->soc_host.ops = &mx2_soc_camera_host_ops, + pcdev->soc_host.priv = pcdev; + pcdev->soc_host.v4l2_dev.dev = &pdev->dev; + pcdev->soc_host.nr = pdev->id; + err = soc_camera_host_register(&pcdev->soc_host); + if (err) + goto exit_free_emma; + + return 0; + +exit_free_emma: + if (mx27_camera_emma(pcdev)) { + free_irq(pcdev->irq_emma, pcdev); + clk_disable(pcdev->clk_emma); + clk_put(pcdev->clk_emma); + iounmap(pcdev->base_emma); + release_mem_region(res_emma->start, resource_size(res_emma)); + } +exit_free_irq: + free_irq(pcdev->irq_csi, pcdev); +exit_iounmap: + iounmap(base_csi); +exit_release: + release_mem_region(res_csi->start, resource_size(res_csi)); +exit_dma_free: +#ifdef CONFIG_MACH_MX27 + if (cpu_is_mx27()) + imx_dma_free(pcdev->dma); +exit_clk_put: + clk_put(pcdev->clk_csi); +#endif /* CONFIG_MACH_MX27 */ +exit_kfree: + kfree(pcdev); +exit: + return err; +} + +static int __devexit mx2_camera_remove(struct platform_device *pdev) +{ + struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); + struct mx2_camera_dev *pcdev = container_of(soc_host, + struct mx2_camera_dev, soc_host); + struct resource *res; + + clk_put(pcdev->clk_csi); +#ifdef CONFIG_MACH_MX27 + if (cpu_is_mx27()) + imx_dma_free(pcdev->dma); +#endif /* CONFIG_MACH_MX27 */ + free_irq(pcdev->irq_csi, pcdev); + if (mx27_camera_emma(pcdev)) + free_irq(pcdev->irq_emma, pcdev); + + soc_camera_host_unregister(&pcdev->soc_host); + + iounmap(pcdev->base_csi); + + if (mx27_camera_emma(pcdev)) { + clk_disable(pcdev->clk_emma); + clk_put(pcdev->clk_emma); + iounmap(pcdev->base_emma); + res = pcdev->res_emma; + release_mem_region(res->start, resource_size(res)); + } + + res = pcdev->res_csi; + release_mem_region(res->start, resource_size(res)); + + kfree(pcdev); + + dev_info(&pdev->dev, "MX2 Camera driver unloaded\n"); + + return 0; +} + +static struct platform_driver mx2_camera_driver = { + .driver = { + .name = MX2_CAM_DRV_NAME, + }, + .remove = __devexit_p(mx2_camera_remove), +}; + + +static int __init mx2_camera_init(void) +{ + return platform_driver_probe(&mx2_camera_driver, &mx2_camera_probe); +} + +static void __exit mx2_camera_exit(void) +{ + return platform_driver_unregister(&mx2_camera_driver); +} + +module_init(mx2_camera_init); +module_exit(mx2_camera_exit); + +MODULE_DESCRIPTION("i.MX27/i.MX25 SoC Camera Host driver"); +MODULE_AUTHOR("Sascha Hauer <sha@pengutronix.de>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/omap/Kconfig b/drivers/media/video/omap/Kconfig index 97c53949ca8..e63233fd2aa 100644 --- a/drivers/media/video/omap/Kconfig +++ b/drivers/media/video/omap/Kconfig @@ -1,8 +1,8 @@ config VIDEO_OMAP2_VOUT tristate "OMAP2/OMAP3 V4L2-Display driver" - depends on ARCH_OMAP24XX || ARCH_OMAP34XX + depends on ARCH_OMAP2 || ARCH_OMAP3 select VIDEOBUF_GEN - select VIDEOBUF_DMA_SG + select VIDEOBUF_DMA_CONTIG select OMAP2_DSS select OMAP2_VRAM select OMAP2_VRFB diff --git a/drivers/media/video/omap/Makefile b/drivers/media/video/omap/Makefile index b8bab00ad01..b28788070ae 100644 --- a/drivers/media/video/omap/Makefile +++ b/drivers/media/video/omap/Makefile @@ -3,5 +3,5 @@ # # OMAP2/3 Display driver -omap-vout-mod-objs := omap_vout.o omap_voutlib.o -obj-$(CONFIG_VIDEO_OMAP2_VOUT) += omap-vout-mod.o +omap-vout-y := omap_vout.o omap_voutlib.o +obj-$(CONFIG_VIDEO_OMAP2_VOUT) += omap-vout.o diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index e7db0554949..929073e792c 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c @@ -38,8 +38,9 @@ #include <linux/dma-mapping.h> #include <linux/irq.h> #include <linux/videodev2.h> +#include <linux/slab.h> -#include <media/videobuf-dma-sg.h> +#include <media/videobuf-dma-contig.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> @@ -1053,9 +1054,9 @@ static int omap_vout_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, enum v4l2_field field) { + dma_addr_t dmabuf; struct vid_vrfb_dma *tx; enum dss_rotation rotation; - struct videobuf_dmabuf *dmabuf = NULL; struct omap_vout_device *vout = q->priv_data; u32 dest_frame_index = 0, src_element_index = 0; u32 dest_element_index = 0, src_frame_index = 0; @@ -1074,24 +1075,17 @@ static int omap_vout_buffer_prepare(struct videobuf_queue *q, if (V4L2_MEMORY_USERPTR == vb->memory) { if (0 == vb->baddr) return -EINVAL; - /* Virtual address */ - /* priv points to struct videobuf_pci_sg_memory. But we went - * pointer to videobuf_dmabuf, which is member of - * videobuf_pci_sg_memory */ - dmabuf = videobuf_to_dma(q->bufs[vb->i]); - dmabuf->vmalloc = (void *) vb->baddr; - /* Physical address */ - dmabuf->bus_addr = - (dma_addr_t) omap_vout_uservirt_to_phys(vb->baddr); + vout->queued_buf_addr[vb->i] = (u8 *) + omap_vout_uservirt_to_phys(vb->baddr); + } else { + vout->queued_buf_addr[vb->i] = (u8 *)vout->buf_phy_addr[vb->i]; } - if (!rotation_enabled(vout)) { - dmabuf = videobuf_to_dma(q->bufs[vb->i]); - vout->queued_buf_addr[vb->i] = (u8 *) dmabuf->bus_addr; + if (!rotation_enabled(vout)) return 0; - } - dmabuf = videobuf_to_dma(q->bufs[vb->i]); + + dmabuf = vout->buf_phy_addr[vb->i]; /* If rotation is enabled, copy input buffer into VRFB * memory space using DMA. We are copying input buffer * into VRFB memory space of desired angle and DSS will @@ -1120,7 +1114,7 @@ static int omap_vout_buffer_prepare(struct videobuf_queue *q, tx->dev_id, 0x0); /* src_port required only for OMAP1 */ omap_set_dma_src_params(tx->dma_ch, 0, OMAP_DMA_AMODE_POST_INC, - dmabuf->bus_addr, src_element_index, src_frame_index); + dmabuf, src_element_index, src_frame_index); /*set dma source burst mode for VRFB */ omap_set_dma_src_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16); rotation = calc_rotation(vout); @@ -1211,7 +1205,6 @@ static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma) void *pos; unsigned long start = vma->vm_start; unsigned long size = (vma->vm_end - vma->vm_start); - struct videobuf_dmabuf *dmabuf = NULL; struct omap_vout_device *vout = file->private_data; struct videobuf_queue *q = &vout->vbq; @@ -1241,8 +1234,7 @@ static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); vma->vm_ops = &omap_vout_vm_ops; vma->vm_private_data = (void *) vout; - dmabuf = videobuf_to_dma(q->bufs[i]); - pos = dmabuf->vmalloc; + pos = (void *)vout->buf_virt_addr[i]; vma->vm_pgoff = virt_to_phys((void *)pos) >> PAGE_SHIFT; while (size > 0) { unsigned long pfn; @@ -1347,8 +1339,8 @@ static int omap_vout_open(struct file *file) video_vbq_ops.buf_queue = omap_vout_buffer_queue; spin_lock_init(&vout->vbq_lock); - videobuf_queue_sg_init(q, &video_vbq_ops, NULL, &vout->vbq_lock, - vout->type, V4L2_FIELD_NONE, + videobuf_queue_dma_contig_init(q, &video_vbq_ops, q->dev, + &vout->vbq_lock, vout->type, V4L2_FIELD_NONE, sizeof(struct videobuf_buffer), vout); v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__); @@ -1799,7 +1791,6 @@ static int vidioc_reqbufs(struct file *file, void *fh, unsigned int i, num_buffers = 0; struct omap_vout_device *vout = fh; struct videobuf_queue *q = &vout->vbq; - struct videobuf_dmabuf *dmabuf = NULL; if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || (req->count < 0)) return -EINVAL; @@ -1825,8 +1816,7 @@ static int vidioc_reqbufs(struct file *file, void *fh, num_buffers = (vout->vid == OMAP_VIDEO1) ? video1_numbuffers : video2_numbuffers; for (i = num_buffers; i < vout->buffer_allocated; i++) { - dmabuf = videobuf_to_dma(q->bufs[i]); - omap_vout_free_buffer((u32)dmabuf->vmalloc, + omap_vout_free_buffer(vout->buf_virt_addr[i], vout->buffer_size); vout->buf_virt_addr[i] = 0; vout->buf_phy_addr[i] = 0; @@ -1855,12 +1845,7 @@ static int vidioc_reqbufs(struct file *file, void *fh, goto reqbuf_err; vout->buffer_allocated = req->count; - for (i = 0; i < req->count; i++) { - dmabuf = videobuf_to_dma(q->bufs[i]); - dmabuf->vmalloc = (void *) vout->buf_virt_addr[i]; - dmabuf->bus_addr = (dma_addr_t) vout->buf_phy_addr[i]; - dmabuf->sglen = 1; - } + reqbuf_err: mutex_unlock(&vout->lock); return ret; @@ -2488,7 +2473,7 @@ static int omap_vout_remove(struct platform_device *pdev) for (k = 0; k < vid_dev->num_displays; k++) { if (vid_dev->displays[k]->state != OMAP_DSS_DISPLAY_DISABLED) - vid_dev->displays[k]->disable(vid_dev->displays[k]); + vid_dev->displays[k]->driver->disable(vid_dev->displays[k]); omap_dss_put_device(vid_dev->displays[k]); } @@ -2545,7 +2530,9 @@ static int __init omap_vout_probe(struct platform_device *pdev) def_display = NULL; } if (def_display) { - ret = def_display->enable(def_display); + struct omap_dss_driver *dssdrv = def_display->driver; + + ret = dssdrv->enable(def_display); if (ret) { /* Here we are not considering a error * as display may be enabled by frame @@ -2559,21 +2546,21 @@ static int __init omap_vout_probe(struct platform_device *pdev) if (def_display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { #ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE - if (def_display->enable_te) - def_display->enable_te(def_display, 1); - if (def_display->set_update_mode) - def_display->set_update_mode(def_display, + if (dssdrv->enable_te) + dssdrv->enable_te(def_display, 1); + if (dssdrv->set_update_mode) + dssdrv->set_update_mode(def_display, OMAP_DSS_UPDATE_AUTO); #else /* MANUAL_UPDATE */ - if (def_display->enable_te) - def_display->enable_te(def_display, 0); - if (def_display->set_update_mode) - def_display->set_update_mode(def_display, + if (dssdrv->enable_te) + dssdrv->enable_te(def_display, 0); + if (dssdrv->set_update_mode) + dssdrv->set_update_mode(def_display, OMAP_DSS_UPDATE_MANUAL); #endif } else { - if (def_display->set_update_mode) - def_display->set_update_mode(def_display, + if (dssdrv->set_update_mode) + dssdrv->set_update_mode(def_display, OMAP_DSS_UPDATE_AUTO); } } @@ -2592,8 +2579,8 @@ static int __init omap_vout_probe(struct platform_device *pdev) for (i = 0; i < vid_dev->num_displays; i++) { struct omap_dss_device *display = vid_dev->displays[i]; - if (display->update) - display->update(display, 0, 0, + if (display->driver->update) + display->driver->update(display, 0, 0, display->panel.timings.x_res, display->panel.timings.y_res); } @@ -2608,8 +2595,8 @@ probe_err1: if (ovl->manager && ovl->manager->device) def_display = ovl->manager->device; - if (def_display) - def_display->disable(def_display); + if (def_display && def_display->driver) + def_display->driver->disable(def_display); } probe_err0: kfree(vid_dev); diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 0a877497b93..07fabdd9b46 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -267,6 +267,21 @@ hauppauge_tuner[] = { TUNER_ABSENT, "Xceive XC4000"}, { TUNER_ABSENT, "Dibcom 7070"}, { TUNER_PHILIPS_TDA8290, "NXP 18271C2"}, + { TUNER_ABSENT, "unknown"}, + { TUNER_ABSENT, "unknown"}, + { TUNER_ABSENT, "unknown"}, + { TUNER_ABSENT, "unknown"}, + /* 160-169 */ + { TUNER_ABSENT, "unknown"}, + { TUNER_ABSENT, "unknown"}, + { TUNER_ABSENT, "unknown"}, + { TUNER_ABSENT, "unknown"}, + { TUNER_ABSENT, "unknown"}, + { TUNER_ABSENT, "unknown"}, + { TUNER_ABSENT, "unknown"}, + { TUNER_ABSENT, "unknown"}, + { TUNER_PHILIPS_FQ1236_MK5, "TCL M30WTP-4N-E"}, + { TUNER_ABSENT, "unknown"}, }; /* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index aa0720af07a..27a79f087b1 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c @@ -122,8 +122,8 @@ static struct uvc_control_info uvc_ctrls[] = { .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, .index = 10, .size = 1, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE - | UVC_CONTROL_RESTORE, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR + | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, }, { .entity = UVC_GUID_UVC_PROCESSING, diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 26386a92f5a..9b089dfb173 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -353,6 +353,16 @@ config VMWARE_BALLOON To compile this driver as a module, choose M here: the module will be called vmware_balloon. +config ARM_CHARLCD + bool "ARM Ltd. Character LCD Driver" + depends on PLAT_VERSATILE + help + This is a driver for the character LCD found on the ARM Ltd. + Versatile and RealView Platform Baseboards. It doesn't do + very much more than display the text "ARM Linux" on the first + line and the Linux version on the second line, but that's + still useful. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 6ed06a19474..67552d6e932 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_IWMC3200TOP) += iwmc3200top/ obj-y += eeprom/ obj-y += cb710/ obj-$(CONFIG_VMWARE_BALLOON) += vmware_balloon.o +obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o diff --git a/drivers/misc/arm-charlcd.c b/drivers/misc/arm-charlcd.c new file mode 100644 index 00000000000..9e3879ef58f --- /dev/null +++ b/drivers/misc/arm-charlcd.c @@ -0,0 +1,396 @@ +/* + * Driver for the on-board character LCD found on some ARM reference boards + * This is basically an Hitachi HD44780 LCD with a custom IP block to drive it + * http://en.wikipedia.org/wiki/HD44780_Character_LCD + * Currently it will just display the text "ARM Linux" and the linux version + * + * License terms: GNU General Public License (GPL) version 2 + * Author: Linus Walleij <triad@df.lth.se> + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <generated/utsrelease.h> + +#define DRIVERNAME "arm-charlcd" +#define CHARLCD_TIMEOUT (msecs_to_jiffies(1000)) + +/* Offsets to registers */ +#define CHAR_COM 0x00U +#define CHAR_DAT 0x04U +#define CHAR_RD 0x08U +#define CHAR_RAW 0x0CU +#define CHAR_MASK 0x10U +#define CHAR_STAT 0x14U + +#define CHAR_RAW_CLEAR 0x00000000U +#define CHAR_RAW_VALID 0x00000100U + +/* Hitachi HD44780 display commands */ +#define HD_CLEAR 0x01U +#define HD_HOME 0x02U +#define HD_ENTRYMODE 0x04U +#define HD_ENTRYMODE_INCREMENT 0x02U +#define HD_ENTRYMODE_SHIFT 0x01U +#define HD_DISPCTRL 0x08U +#define HD_DISPCTRL_ON 0x04U +#define HD_DISPCTRL_CURSOR_ON 0x02U +#define HD_DISPCTRL_CURSOR_BLINK 0x01U +#define HD_CRSR_SHIFT 0x10U +#define HD_CRSR_SHIFT_DISPLAY 0x08U +#define HD_CRSR_SHIFT_DISPLAY_RIGHT 0x04U +#define HD_FUNCSET 0x20U +#define HD_FUNCSET_8BIT 0x10U +#define HD_FUNCSET_2_LINES 0x08U +#define HD_FUNCSET_FONT_5X10 0x04U +#define HD_SET_CGRAM 0x40U +#define HD_SET_DDRAM 0x80U +#define HD_BUSY_FLAG 0x80U + +/** + * @dev: a pointer back to containing device + * @phybase: the offset to the controller in physical memory + * @physize: the size of the physical page + * @virtbase: the offset to the controller in virtual memory + * @irq: reserved interrupt number + * @complete: completion structure for the last LCD command + */ +struct charlcd { + struct device *dev; + u32 phybase; + u32 physize; + void __iomem *virtbase; + int irq; + struct completion complete; + struct delayed_work init_work; +}; + +static irqreturn_t charlcd_interrupt(int irq, void *data) +{ + struct charlcd *lcd = data; + u8 status; + + status = readl(lcd->virtbase + CHAR_STAT) & 0x01; + /* Clear IRQ */ + writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW); + if (status) + complete(&lcd->complete); + else + dev_info(lcd->dev, "Spurious IRQ (%02x)\n", status); + return IRQ_HANDLED; +} + + +static void charlcd_wait_complete_irq(struct charlcd *lcd) +{ + int ret; + + ret = wait_for_completion_interruptible_timeout(&lcd->complete, + CHARLCD_TIMEOUT); + /* Disable IRQ after completion */ + writel(0x00, lcd->virtbase + CHAR_MASK); + + if (ret < 0) { + dev_err(lcd->dev, + "wait_for_completion_interruptible_timeout() " + "returned %d waiting for ready\n", ret); + return; + } + + if (ret == 0) { + dev_err(lcd->dev, "charlcd controller timed out " + "waiting for ready\n"); + return; + } +} + +static u8 charlcd_4bit_read_char(struct charlcd *lcd) +{ + u8 data; + u32 val; + int i; + + /* If we can, use an IRQ to wait for the data, else poll */ + if (lcd->irq >= 0) + charlcd_wait_complete_irq(lcd); + else { + i = 0; + val = 0; + while (!(val & CHAR_RAW_VALID) && i < 10) { + udelay(100); + val = readl(lcd->virtbase + CHAR_RAW); + i++; + } + + writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW); + } + msleep(1); + + /* Read the 4 high bits of the data */ + data = readl(lcd->virtbase + CHAR_RD) & 0xf0; + + /* + * The second read for the low bits does not trigger an IRQ + * so in this case we have to poll for the 4 lower bits + */ + i = 0; + val = 0; + while (!(val & CHAR_RAW_VALID) && i < 10) { + udelay(100); + val = readl(lcd->virtbase + CHAR_RAW); + i++; + } + writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW); + msleep(1); + + /* Read the 4 low bits of the data */ + data |= (readl(lcd->virtbase + CHAR_RD) >> 4) & 0x0f; + + return data; +} + +static bool charlcd_4bit_read_bf(struct charlcd *lcd) +{ + if (lcd->irq >= 0) { + /* + * If we'll use IRQs to wait for the busyflag, clear any + * pending flag and enable IRQ + */ + writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW); + init_completion(&lcd->complete); + writel(0x01, lcd->virtbase + CHAR_MASK); + } + readl(lcd->virtbase + CHAR_COM); + return charlcd_4bit_read_char(lcd) & HD_BUSY_FLAG ? true : false; +} + +static void charlcd_4bit_wait_busy(struct charlcd *lcd) +{ + int retries = 50; + + udelay(100); + while (charlcd_4bit_read_bf(lcd) && retries) + retries--; + if (!retries) + dev_err(lcd->dev, "timeout waiting for busyflag\n"); +} + +static void charlcd_4bit_command(struct charlcd *lcd, u8 cmd) +{ + u32 cmdlo = (cmd << 4) & 0xf0; + u32 cmdhi = (cmd & 0xf0); + + writel(cmdhi, lcd->virtbase + CHAR_COM); + udelay(10); + writel(cmdlo, lcd->virtbase + CHAR_COM); + charlcd_4bit_wait_busy(lcd); +} + +static void charlcd_4bit_char(struct charlcd *lcd, u8 ch) +{ + u32 chlo = (ch << 4) & 0xf0; + u32 chhi = (ch & 0xf0); + + writel(chhi, lcd->virtbase + CHAR_DAT); + udelay(10); + writel(chlo, lcd->virtbase + CHAR_DAT); + charlcd_4bit_wait_busy(lcd); +} + +static void charlcd_4bit_print(struct charlcd *lcd, int line, const char *str) +{ + u8 offset; + int i; + + /* + * We support line 0, 1 + * Line 1 runs from 0x00..0x27 + * Line 2 runs from 0x28..0x4f + */ + if (line == 0) + offset = 0; + else if (line == 1) + offset = 0x28; + else + return; + + /* Set offset */ + charlcd_4bit_command(lcd, HD_SET_DDRAM | offset); + + /* Send string */ + for (i = 0; i < strlen(str) && i < 0x28; i++) + charlcd_4bit_char(lcd, str[i]); +} + +static void charlcd_4bit_init(struct charlcd *lcd) +{ + /* These commands cannot be checked with the busy flag */ + writel(HD_FUNCSET | HD_FUNCSET_8BIT, lcd->virtbase + CHAR_COM); + msleep(5); + writel(HD_FUNCSET | HD_FUNCSET_8BIT, lcd->virtbase + CHAR_COM); + udelay(100); + writel(HD_FUNCSET | HD_FUNCSET_8BIT, lcd->virtbase + CHAR_COM); + udelay(100); + /* Go to 4bit mode */ + writel(HD_FUNCSET, lcd->virtbase + CHAR_COM); + udelay(100); + /* + * 4bit mode, 2 lines, 5x8 font, after this the number of lines + * and the font cannot be changed until the next initialization sequence + */ + charlcd_4bit_command(lcd, HD_FUNCSET | HD_FUNCSET_2_LINES); + charlcd_4bit_command(lcd, HD_DISPCTRL | HD_DISPCTRL_ON); + charlcd_4bit_command(lcd, HD_ENTRYMODE | HD_ENTRYMODE_INCREMENT); + charlcd_4bit_command(lcd, HD_CLEAR); + charlcd_4bit_command(lcd, HD_HOME); + /* Put something useful in the display */ + charlcd_4bit_print(lcd, 0, "ARM Linux"); + charlcd_4bit_print(lcd, 1, UTS_RELEASE); +} + +static void charlcd_init_work(struct work_struct *work) +{ + struct charlcd *lcd = + container_of(work, struct charlcd, init_work.work); + + charlcd_4bit_init(lcd); +} + +static int __init charlcd_probe(struct platform_device *pdev) +{ + int ret; + struct charlcd *lcd; + struct resource *res; + + lcd = kzalloc(sizeof(struct charlcd), GFP_KERNEL); + if (!lcd) + return -ENOMEM; + + lcd->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENOENT; + goto out_no_resource; + } + lcd->phybase = res->start; + lcd->physize = resource_size(res); + + if (request_mem_region(lcd->phybase, lcd->physize, + DRIVERNAME) == NULL) { + ret = -EBUSY; + goto out_no_memregion; + } + + lcd->virtbase = ioremap(lcd->phybase, lcd->physize); + if (!lcd->virtbase) { + ret = -ENOMEM; + goto out_no_remap; + } + + lcd->irq = platform_get_irq(pdev, 0); + /* If no IRQ is supplied, we'll survive without it */ + if (lcd->irq >= 0) { + if (request_irq(lcd->irq, charlcd_interrupt, IRQF_DISABLED, + DRIVERNAME, lcd)) { + ret = -EIO; + goto out_no_irq; + } + } + + platform_set_drvdata(pdev, lcd); + + /* + * Initialize the display in a delayed work, because + * it is VERY slow and would slow down the boot of the system. + */ + INIT_DELAYED_WORK(&lcd->init_work, charlcd_init_work); + schedule_delayed_work(&lcd->init_work, 0); + + dev_info(&pdev->dev, "initalized ARM character LCD at %08x\n", + lcd->phybase); + + return 0; + +out_no_irq: + iounmap(lcd->virtbase); +out_no_remap: + platform_set_drvdata(pdev, NULL); +out_no_memregion: + release_mem_region(lcd->phybase, SZ_4K); +out_no_resource: + kfree(lcd); + return ret; +} + +static int __exit charlcd_remove(struct platform_device *pdev) +{ + struct charlcd *lcd = platform_get_drvdata(pdev); + + if (lcd) { + free_irq(lcd->irq, lcd); + iounmap(lcd->virtbase); + release_mem_region(lcd->phybase, lcd->physize); + platform_set_drvdata(pdev, NULL); + kfree(lcd); + } + + return 0; +} + +static int charlcd_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct charlcd *lcd = platform_get_drvdata(pdev); + + /* Power the display off */ + charlcd_4bit_command(lcd, HD_DISPCTRL); + return 0; +} + +static int charlcd_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct charlcd *lcd = platform_get_drvdata(pdev); + + /* Turn the display back on */ + charlcd_4bit_command(lcd, HD_DISPCTRL | HD_DISPCTRL_ON); + return 0; +} + +static const struct dev_pm_ops charlcd_pm_ops = { + .suspend = charlcd_suspend, + .resume = charlcd_resume, +}; + +static struct platform_driver charlcd_driver = { + .driver = { + .name = DRIVERNAME, + .owner = THIS_MODULE, + .pm = &charlcd_pm_ops, + }, + .remove = __exit_p(charlcd_remove), +}; + +static int __init charlcd_init(void) +{ + return platform_driver_probe(&charlcd_driver, charlcd_probe); +} + +static void __exit charlcd_exit(void) +{ + platform_driver_unregister(&charlcd_driver); +} + +module_init(charlcd_init); +module_exit(charlcd_exit); + +MODULE_AUTHOR("Linus Walleij <triad@df.lth.se>"); +MODULE_DESCRIPTION("ARM Character LCD Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c index 9bec24db4d4..2d44b330010 100644 --- a/drivers/misc/cs5535-mfgpt.c +++ b/drivers/misc/cs5535-mfgpt.c @@ -366,6 +366,6 @@ static int __init cs5535_mfgpt_init(void) module_init(cs5535_mfgpt_init); -MODULE_AUTHOR("Andres Salomon <dilinger@collabora.co.uk>"); +MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>"); MODULE_DESCRIPTION("CS5535/CS5536 MFGPT timer driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 4917af96bae..840b301b567 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -26,7 +26,6 @@ #include <linux/amba/mmci.h> #include <linux/regulator/consumer.h> -#include <asm/cacheflush.h> #include <asm/div64.h> #include <asm/io.h> #include <asm/sizes.h> @@ -37,12 +36,39 @@ static unsigned int fmax = 515633; +/** + * struct variant_data - MMCI variant-specific quirks + * @clkreg: default value for MCICLOCK register + * @clkreg_enable: enable value for MMCICLOCK register + * @datalength_bits: number of bits in the MMCIDATALENGTH register + */ +struct variant_data { + unsigned int clkreg; + unsigned int clkreg_enable; + unsigned int datalength_bits; +}; + +static struct variant_data variant_arm = { + .datalength_bits = 16, +}; + +static struct variant_data variant_u300 = { + .clkreg_enable = 1 << 13, /* HWFCEN */ + .datalength_bits = 16, +}; + +static struct variant_data variant_ux500 = { + .clkreg = MCI_CLK_ENABLE, + .clkreg_enable = 1 << 14, /* HWFCEN */ + .datalength_bits = 24, +}; /* * This must be called with host->lock held */ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) { - u32 clk = 0; + struct variant_data *variant = host->variant; + u32 clk = variant->clkreg; if (desired) { if (desired >= host->mclk) { @@ -54,8 +80,8 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) clk = 255; host->cclk = host->mclk / (2 * (clk + 1)); } - if (host->hw_designer == AMBA_VENDOR_ST) - clk |= MCI_ST_FCEN; /* Bug fix in ST IP block */ + + clk |= variant->clkreg_enable; clk |= MCI_CLK_ENABLE; /* This hasn't proven to be worthwhile */ /* clk |= MCI_CLK_PWRSAVE; */ @@ -98,6 +124,18 @@ static void mmci_stop_data(struct mmci_host *host) host->data = NULL; } +static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) +{ + unsigned int flags = SG_MITER_ATOMIC; + + if (data->flags & MMC_DATA_READ) + flags |= SG_MITER_TO_SG; + else + flags |= SG_MITER_FROM_SG; + + sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); +} + static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) { unsigned int datactrl, timeout, irqmask; @@ -109,7 +147,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) data->blksz, data->blocks, data->flags); host->data = data; - host->size = data->blksz; + host->size = data->blksz * data->blocks; host->data_xfered = 0; mmci_init_sg(host, data); @@ -210,8 +248,17 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, * We hit an error condition. Ensure that any data * partially written to a page is properly coherent. */ - if (host->sg_len && data->flags & MMC_DATA_READ) - flush_dcache_page(sg_page(host->sg_ptr)); + if (data->flags & MMC_DATA_READ) { + struct sg_mapping_iter *sg_miter = &host->sg_miter; + unsigned long flags; + + local_irq_save(flags); + if (sg_miter_next(sg_miter)) { + flush_dcache_page(sg_miter->page); + sg_miter_stop(sg_miter); + } + local_irq_restore(flags); + } } if (status & MCI_DATAEND) { mmci_stop_data(host); @@ -314,15 +361,18 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem static irqreturn_t mmci_pio_irq(int irq, void *dev_id) { struct mmci_host *host = dev_id; + struct sg_mapping_iter *sg_miter = &host->sg_miter; void __iomem *base = host->base; + unsigned long flags; u32 status; status = readl(base + MMCISTATUS); dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status); + local_irq_save(flags); + do { - unsigned long flags; unsigned int remain, len; char *buffer; @@ -336,11 +386,11 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL))) break; - /* - * Map the current scatter buffer. - */ - buffer = mmci_kmap_atomic(host, &flags) + host->sg_off; - remain = host->sg_ptr->length - host->sg_off; + if (!sg_miter_next(sg_miter)) + break; + + buffer = sg_miter->addr; + remain = sg_miter->length; len = 0; if (status & MCI_RXACTIVE) @@ -348,31 +398,24 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) if (status & MCI_TXACTIVE) len = mmci_pio_write(host, buffer, remain, status); - /* - * Unmap the buffer. - */ - mmci_kunmap_atomic(host, buffer, &flags); + sg_miter->consumed = len; - host->sg_off += len; host->size -= len; remain -= len; if (remain) break; - /* - * If we were reading, and we have completed this - * page, ensure that the data cache is coherent. - */ if (status & MCI_RXACTIVE) - flush_dcache_page(sg_page(host->sg_ptr)); - - if (!mmci_next_sg(host)) - break; + flush_dcache_page(sg_miter->page); status = readl(base + MMCISTATUS); } while (1); + sg_miter_stop(sg_miter); + + local_irq_restore(flags); + /* * If we're nearing the end of the read, switch to * "any data available" mode. @@ -477,16 +520,9 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) /* This implicitly enables the regulator */ mmc_regulator_set_ocr(host->vcc, ios->vdd); #endif - /* - * The translate_vdd function is not used if you have - * an external regulator, or your design is really weird. - * Using it would mean sending in power control BOTH using - * a regulator AND the 4 MMCIPWR bits. If we don't have - * a regulator, we might have some other platform specific - * power control behind this translate function. - */ - if (!host->vcc && host->plat->translate_vdd) - pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd); + if (host->plat->vdd_handler) + pwr |= host->plat->vdd_handler(mmc_dev(mmc), ios->vdd, + ios->power_mode); /* The ST version does not have this, fall through to POWER_ON */ if (host->hw_designer != AMBA_VENDOR_ST) { pwr |= MCI_PWR_UP; @@ -539,9 +575,13 @@ static int mmci_get_cd(struct mmc_host *mmc) if (host->gpio_cd == -ENOSYS) status = host->plat->status(mmc_dev(host->mmc)); else - status = gpio_get_value(host->gpio_cd); + status = !gpio_get_value(host->gpio_cd); - return !status; + /* + * Use positive logic throughout - status is zero for no card, + * non-zero for card inserted. + */ + return status; } static const struct mmc_host_ops mmci_ops = { @@ -551,21 +591,10 @@ static const struct mmc_host_ops mmci_ops = { .get_cd = mmci_get_cd, }; -static void mmci_check_status(unsigned long data) -{ - struct mmci_host *host = (struct mmci_host *)data; - unsigned int status = mmci_get_cd(host->mmc); - - if (status ^ host->oldstat) - mmc_detect_change(host->mmc, 0); - - host->oldstat = status; - mod_timer(&host->timer, jiffies + HZ); -} - static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) { struct mmci_platform_data *plat = dev->dev.platform_data; + struct variant_data *variant = id->data; struct mmci_host *host; struct mmc_host *mmc; int ret; @@ -609,6 +638,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) goto clk_free; host->plat = plat; + host->variant = variant; host->mclk = clk_get_rate(host->clk); /* * According to the spec, mclk is max 100 MHz, @@ -669,6 +699,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) if (host->vcc == NULL) mmc->ocr_avail = plat->ocr_mask; mmc->caps = plat->capabilities; + mmc->caps |= MMC_CAP_NEEDS_POLL; /* * We can do SGIO @@ -677,10 +708,11 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) mmc->max_phys_segs = NR_SG; /* - * Since we only have a 16-bit data length register, we must - * ensure that we don't exceed 2^16-1 bytes in a single request. + * Since only a certain number of bits are valid in the data length + * register, we must ensure that we don't exceed 2^num-1 bytes in a + * single request. */ - mmc->max_req_size = 65535; + mmc->max_req_size = (1 << variant->datalength_bits) - 1; /* * Set the maximum segment size. Since we aren't doing DMA @@ -734,7 +766,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) writel(MCI_IRQENABLE, host->base + MMCIMASK0); amba_set_drvdata(dev, mmc); - host->oldstat = mmci_get_cd(host->mmc); mmc_add_host(mmc); @@ -742,12 +773,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) mmc_hostname(mmc), amba_rev(dev), amba_config(dev), (unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]); - init_timer(&host->timer); - host->timer.data = (unsigned long)host; - host->timer.function = mmci_check_status; - host->timer.expires = jiffies + HZ; - add_timer(&host->timer); - return 0; irq0_free: @@ -781,8 +806,6 @@ static int __devexit mmci_remove(struct amba_device *dev) if (mmc) { struct mmci_host *host = mmc_priv(mmc); - del_timer_sync(&host->timer); - mmc_remove_host(mmc); writel(0, host->base + MMCIMASK0); @@ -856,19 +879,28 @@ static struct amba_id mmci_ids[] = { { .id = 0x00041180, .mask = 0x000fffff, + .data = &variant_arm, }, { .id = 0x00041181, .mask = 0x000fffff, + .data = &variant_arm, }, /* ST Micro variants */ { .id = 0x00180180, .mask = 0x00ffffff, + .data = &variant_u300, }, { .id = 0x00280180, .mask = 0x00ffffff, + .data = &variant_u300, + }, + { + .id = 0x00480180, + .mask = 0x00ffffff, + .data = &variant_ux500, }, { 0, 0 }, }; diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index d77062e5e3a..68970cfb81e 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -28,8 +28,6 @@ #define MCI_4BIT_BUS (1 << 11) /* 8bit wide buses supported in ST Micro versions */ #define MCI_ST_8BIT_BUS (1 << 12) -/* HW flow control on the ST Micro version */ -#define MCI_ST_FCEN (1 << 13) #define MMCIARGUMENT 0x008 #define MMCICOMMAND 0x00c @@ -145,6 +143,7 @@ #define NR_SG 16 struct clk; +struct variant_data; struct mmci_host { void __iomem *base; @@ -164,6 +163,7 @@ struct mmci_host { unsigned int cclk; u32 pwr; struct mmci_platform_data *plat; + struct variant_data *variant; u8 hw_designer; u8 hw_revision:4; @@ -171,42 +171,9 @@ struct mmci_host { struct timer_list timer; unsigned int oldstat; - unsigned int sg_len; - /* pio stuff */ - struct scatterlist *sg_ptr; - unsigned int sg_off; + struct sg_mapping_iter sg_miter; unsigned int size; struct regulator *vcc; }; -static inline void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) -{ - /* - * Ideally, we want the higher levels to pass us a scatter list. - */ - host->sg_len = data->sg_len; - host->sg_ptr = data->sg; - host->sg_off = 0; -} - -static inline int mmci_next_sg(struct mmci_host *host) -{ - host->sg_ptr++; - host->sg_off = 0; - return --host->sg_len; -} - -static inline char *mmci_kmap_atomic(struct mmci_host *host, unsigned long *flags) -{ - struct scatterlist *sg = host->sg_ptr; - - local_irq_save(*flags); - return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; -} - -static inline void mmci_kunmap_atomic(struct mmci_host *host, void *buffer, unsigned long *flags) -{ - kunmap_atomic(buffer, KM_BIO_SRC_IRQ); - local_irq_restore(*flags); -} diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index d9d4a72e0ec..350f78e8624 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -119,6 +119,7 @@ struct mxcmci_host { int detect_irq; int dma; int do_dma; + int default_irq_mask; int use_sdio; unsigned int power_mode; struct imxmmc_platform_data *pdata; @@ -228,7 +229,7 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, unsigned int cmdat) { - u32 int_cntr; + u32 int_cntr = host->default_irq_mask; unsigned long flags; WARN_ON(host->cmd != NULL); @@ -275,7 +276,7 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, static void mxcmci_finish_request(struct mxcmci_host *host, struct mmc_request *req) { - u32 int_cntr = 0; + u32 int_cntr = host->default_irq_mask; unsigned long flags; spin_lock_irqsave(&host->lock, flags); @@ -585,6 +586,9 @@ static irqreturn_t mxcmci_irq(int irq, void *devid) (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) mxcmci_data_done(host, stat); #endif + if (host->default_irq_mask && + (stat & (STATUS_CARD_INSERTION | STATUS_CARD_REMOVAL))) + mmc_detect_change(host->mmc, msecs_to_jiffies(200)); return IRQ_HANDLED; } @@ -809,6 +813,12 @@ static int mxcmci_probe(struct platform_device *pdev) else mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + if (host->pdata && host->pdata->dat3_card_detect) + host->default_irq_mask = + INT_CARD_INSERTION_EN | INT_CARD_REMOVAL_EN; + else + host->default_irq_mask = 0; + host->res = r; host->irq = irq; @@ -835,7 +845,7 @@ static int mxcmci_probe(struct platform_device *pdev) /* recommended in data sheet */ writew(0x2db4, host->base + MMC_REG_READ_TO); - writel(0, host->base + MMC_REG_INT_CNTR); + writel(host->default_irq_mask, host->base + MMC_REG_INT_CNTR); #ifdef HAS_DMA host->dma = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_LOW); @@ -926,43 +936,47 @@ static int mxcmci_remove(struct platform_device *pdev) } #ifdef CONFIG_PM -static int mxcmci_suspend(struct platform_device *dev, pm_message_t state) +static int mxcmci_suspend(struct device *dev) { - struct mmc_host *mmc = platform_get_drvdata(dev); + struct mmc_host *mmc = dev_get_drvdata(dev); + struct mxcmci_host *host = mmc_priv(mmc); int ret = 0; if (mmc) ret = mmc_suspend_host(mmc); + clk_disable(host->clk); return ret; } -static int mxcmci_resume(struct platform_device *dev) +static int mxcmci_resume(struct device *dev) { - struct mmc_host *mmc = platform_get_drvdata(dev); - struct mxcmci_host *host; + struct mmc_host *mmc = dev_get_drvdata(dev); + struct mxcmci_host *host = mmc_priv(mmc); int ret = 0; - if (mmc) { - host = mmc_priv(mmc); + clk_enable(host->clk); + if (mmc) ret = mmc_resume_host(mmc); - } return ret; } -#else -#define mxcmci_suspend NULL -#define mxcmci_resume NULL -#endif /* CONFIG_PM */ + +static const struct dev_pm_ops mxcmci_pm_ops = { + .suspend = mxcmci_suspend, + .resume = mxcmci_resume, +}; +#endif static struct platform_driver mxcmci_driver = { .probe = mxcmci_probe, .remove = mxcmci_remove, - .suspend = mxcmci_suspend, - .resume = mxcmci_resume, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &mxcmci_pm_ops, +#endif } }; diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index af217924a76..ad30f074ee1 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -365,6 +365,26 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) static int __devexit sdhci_s3c_remove(struct platform_device *pdev) { + struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_s3c *sc = sdhci_priv(host); + int ptr; + + sdhci_remove_host(host, 1); + + for (ptr = 0; ptr < 3; ptr++) { + clk_disable(sc->clk_bus[ptr]); + clk_put(sc->clk_bus[ptr]); + } + clk_disable(sc->clk_io); + clk_put(sc->clk_io); + + iounmap(host->ioaddr); + release_resource(sc->ioarea); + kfree(sc->ioarea); + + sdhci_free_host(host); + platform_set_drvdata(pdev, NULL); + return 0; } diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 82e94389824..0d76b169482 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -623,8 +623,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, else host->buf_start = column + mtd->writesize; - if (mtd->writesize > 512) - command = NAND_CMD_READ0; /* only READ0 is valid */ + command = NAND_CMD_READ0; /* only READ0 is valid */ send_cmd(host, command, false); mxc_do_addr_cycle(mtd, column, page_addr); @@ -639,31 +638,11 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, break; case NAND_CMD_SEQIN: - if (column >= mtd->writesize) { - /* - * FIXME: before send SEQIN command for write OOB, - * We must read one page out. - * For K9F1GXX has no READ1 command to set current HW - * pointer to spare area, we must write the whole page - * including OOB together. - */ - if (mtd->writesize > 512) - /* call ourself to read a page */ - mxc_nand_command(mtd, NAND_CMD_READ0, 0, - page_addr); - - host->buf_start = column; - - /* Set program pointer to spare region */ - if (mtd->writesize == 512) - send_cmd(host, NAND_CMD_READOOB, false); - } else { - host->buf_start = column; + if (column >= mtd->writesize) + /* call ourself to read a page */ + mxc_nand_command(mtd, NAND_CMD_READ0, 0, page_addr); - /* Set program pointer to page start */ - if (mtd->writesize == 512) - send_cmd(host, NAND_CMD_READ0, false); - } + host->buf_start = column; send_cmd(host, command, false); mxc_do_addr_cycle(mtd, column, page_addr); @@ -853,6 +832,8 @@ static int __init mxcnd_probe(struct platform_device *pdev) parse_mtd_partitions(mtd, part_probes, &host->parts, 0); if (nr_parts > 0) add_mtd_partitions(mtd, host->parts, nr_parts); + else if (pdata->parts) + add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts); else #endif { diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 13b05cb33b0..78ae89488a4 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -593,6 +593,7 @@ static int attach_by_scanning(struct ubi_device *ubi) ubi->good_peb_count = ubi->peb_count - ubi->bad_peb_count; ubi->max_ec = si->max_ec; ubi->mean_ec = si->mean_ec; + ubi_msg("max. sequence number: %llu", si->max_sqnum); err = ubi_read_volume_table(ubi, si); if (err) @@ -981,7 +982,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) ubi_msg("number of PEBs reserved for bad PEB handling: %d", ubi->beb_rsvd_pebs); ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec); - ubi_msg("image sequence number: %d", ubi->image_seq); + ubi_msg("image sequence number: %d", ubi->image_seq); /* * The below lock makes sure we do not race with 'ubi_thread()' which diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 9f87c99189a..fe74749e0da 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -418,7 +418,8 @@ retry: * may try to recover data. FIXME: but this is * not implemented. */ - if (err == UBI_IO_BAD_VID_HDR) { + if (err == UBI_IO_BAD_HDR_READ || + err == UBI_IO_BAD_HDR) { ubi_warn("corrupted VID header at PEB " "%d, LEB %d:%d", pnum, vol_id, lnum); @@ -961,8 +962,8 @@ write_error: */ static int is_error_sane(int err) { - if (err == -EIO || err == -ENOMEM || err == UBI_IO_BAD_VID_HDR || - err == -ETIMEDOUT) + if (err == -EIO || err == -ENOMEM || err == UBI_IO_BAD_HDR || + err == UBI_IO_BAD_HDR_READ || err == -ETIMEDOUT) return 0; return 1; } @@ -1165,6 +1166,44 @@ out_unlock_leb: } /** + * print_rsvd_warning - warn about not having enough reserved PEBs. + * @ubi: UBI device description object + * + * This is a helper function for 'ubi_eba_init_scan()' which is called when UBI + * cannot reserve enough PEBs for bad block handling. This function makes a + * decision whether we have to print a warning or not. The algorithm is as + * follows: + * o if this is a new UBI image, then just print the warning + * o if this is an UBI image which has already been used for some time, print + * a warning only if we can reserve less than 10% of the expected amount of + * the reserved PEB. + * + * The idea is that when UBI is used, PEBs become bad, and the reserved pool + * of PEBs becomes smaller, which is normal and we do not want to scare users + * with a warning every time they attach the MTD device. This was an issue + * reported by real users. + */ +static void print_rsvd_warning(struct ubi_device *ubi, + struct ubi_scan_info *si) +{ + /* + * The 1 << 18 (256KiB) number is picked randomly, just a reasonably + * large number to distinguish between newly flashed and used images. + */ + if (si->max_sqnum > (1 << 18)) { + int min = ubi->beb_rsvd_level / 10; + + if (!min) + min = 1; + if (ubi->beb_rsvd_pebs > min) + return; + } + + ubi_warn("cannot reserve enough PEBs for bad PEB handling, reserved %d," + " need %d", ubi->beb_rsvd_pebs, ubi->beb_rsvd_level); +} + +/** * ubi_eba_init_scan - initialize the EBA sub-system using scanning information. * @ubi: UBI device description object * @si: scanning information @@ -1236,9 +1275,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) if (ubi->avail_pebs < ubi->beb_rsvd_level) { /* No enough free physical eraseblocks */ ubi->beb_rsvd_pebs = ubi->avail_pebs; - ubi_warn("cannot reserve enough PEBs for bad PEB " - "handling, reserved %d, need %d", - ubi->beb_rsvd_pebs, ubi->beb_rsvd_level); + print_rsvd_warning(ubi, si); } else ubi->beb_rsvd_pebs = ubi->beb_rsvd_level; diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 4b979e34b15..332f992f13d 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -150,6 +150,8 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, retry: err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf); if (err) { + const char *errstr = (err == -EBADMSG) ? " (ECC error)" : ""; + if (err == -EUCLEAN) { /* * -EUCLEAN is reported if there was a bit-flip which @@ -165,15 +167,15 @@ retry: } if (read != len && retries++ < UBI_IO_RETRIES) { - dbg_io("error %d while reading %d bytes from PEB %d:%d," + dbg_io("error %d%s while reading %d bytes from PEB %d:%d," " read only %zd bytes, retry", - err, len, pnum, offset, read); + err, errstr, len, pnum, offset, read); yield(); goto retry; } - ubi_err("error %d while reading %d bytes from PEB %d:%d, " - "read %zd bytes", err, len, pnum, offset, read); + ubi_err("error %d%s while reading %d bytes from PEB %d:%d, " + "read %zd bytes", err, errstr, len, pnum, offset, read); ubi_dbg_dump_stack(); /* @@ -515,7 +517,7 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum) * In this case we probably anyway have garbage in this PEB. */ err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0); - if (err1 == UBI_IO_BAD_VID_HDR) + if (err1 == UBI_IO_BAD_HDR_READ || err1 == UBI_IO_BAD_HDR) /* * The VID header is corrupted, so we can safely erase this * PEB and not afraid that it will be treated as a valid PEB in @@ -709,7 +711,7 @@ bad: * o %UBI_IO_BITFLIPS if the CRC is correct, but bit-flips were detected * and corrected by the flash driver; this is harmless but may indicate that * this eraseblock may become bad soon (but may be not); - * o %UBI_IO_BAD_EC_HDR if the erase counter header is corrupted (a CRC error); + * o %UBI_IO_BAD_HDR if the erase counter header is corrupted (a CRC error); * o %UBI_IO_PEB_EMPTY if the physical eraseblock is empty; * o a negative error code in case of failure. */ @@ -736,23 +738,21 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, * header is still OK, we just report this as there was a * bit-flip. */ - read_err = err; + if (err == -EBADMSG) + read_err = UBI_IO_BAD_HDR_READ; } magic = be32_to_cpu(ec_hdr->magic); if (magic != UBI_EC_HDR_MAGIC) { + if (read_err) + return read_err; + /* * The magic field is wrong. Let's check if we have read all * 0xFF. If yes, this physical eraseblock is assumed to be * empty. - * - * But if there was a read error, we do not test it for all - * 0xFFs. Even if it does contain all 0xFFs, this error - * indicates that something is still wrong with this physical - * eraseblock and we anyway cannot treat it as empty. */ - if (read_err != -EBADMSG && - check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) { + if (check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) { /* The physical eraseblock is supposedly empty */ if (verbose) ubi_warn("no EC header found at PEB %d, " @@ -774,7 +774,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, } else if (UBI_IO_DEBUG) dbg_msg("bad magic number at PEB %d: %08x instead of " "%08x", pnum, magic, UBI_EC_HDR_MAGIC); - return UBI_IO_BAD_EC_HDR; + return UBI_IO_BAD_HDR; } crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); @@ -788,7 +788,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, } else if (UBI_IO_DEBUG) dbg_msg("bad EC header CRC at PEB %d, calculated " "%#08x, read %#08x", pnum, crc, hdr_crc); - return UBI_IO_BAD_EC_HDR; + return read_err ?: UBI_IO_BAD_HDR; } /* And of course validate what has just been read from the media */ @@ -798,6 +798,10 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, return -EINVAL; } + /* + * If there was %-EBADMSG, but the header CRC is still OK, report about + * a bit-flip to force scrubbing on this PEB. + */ return read_err ? UBI_IO_BITFLIPS : 0; } @@ -977,7 +981,7 @@ bad: * o %UBI_IO_BITFLIPS if the CRC is correct, but bit-flips were detected * and corrected by the flash driver; this is harmless but may indicate that * this eraseblock may become bad soon; - * o %UBI_IO_BAD_VID_HDR if the volume identifier header is corrupted (a CRC + * o %UBI_IO_BAD_HDR if the volume identifier header is corrupted (a CRC * error detected); * o %UBI_IO_PEB_FREE if the physical eraseblock is free (i.e., there is no VID * header there); @@ -1008,22 +1012,20 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, * CRC check-sum and we will identify this. If the VID header is * still OK, we just report this as there was a bit-flip. */ - read_err = err; + if (err == -EBADMSG) + read_err = UBI_IO_BAD_HDR_READ; } magic = be32_to_cpu(vid_hdr->magic); if (magic != UBI_VID_HDR_MAGIC) { + if (read_err) + return read_err; + /* * If we have read all 0xFF bytes, the VID header probably does * not exist and the physical eraseblock is assumed to be free. - * - * But if there was a read error, we do not test the data for - * 0xFFs. Even if it does contain all 0xFFs, this error - * indicates that something is still wrong with this physical - * eraseblock and it cannot be regarded as free. */ - if (read_err != -EBADMSG && - check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) { + if (check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) { /* The physical eraseblock is supposedly free */ if (verbose) ubi_warn("no VID header found at PEB %d, " @@ -1045,7 +1047,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, } else if (UBI_IO_DEBUG) dbg_msg("bad magic number at PEB %d: %08x instead of " "%08x", pnum, magic, UBI_VID_HDR_MAGIC); - return UBI_IO_BAD_VID_HDR; + return UBI_IO_BAD_HDR; } crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC); @@ -1059,7 +1061,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, } else if (UBI_IO_DEBUG) dbg_msg("bad CRC at PEB %d, calculated %#08x, " "read %#08x", pnum, crc, hdr_crc); - return UBI_IO_BAD_VID_HDR; + return read_err ?: UBI_IO_BAD_HDR; } /* Validate the VID header that we have just read */ @@ -1069,6 +1071,10 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, return -EINVAL; } + /* + * If there was a read error (%-EBADMSG), but the header CRC is still + * OK, report about a bit-flip to force scrubbing on this PEB. + */ return read_err ? UBI_IO_BITFLIPS : 0; } diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index aed19f33b8f..372a15ac999 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -44,6 +44,7 @@ #include <linux/slab.h> #include <linux/crc32.h> #include <linux/math64.h> +#include <linux/random.h> #include "ubi.h" #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID @@ -72,16 +73,19 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec, { struct ubi_scan_leb *seb; - if (list == &si->free) + if (list == &si->free) { dbg_bld("add to free: PEB %d, EC %d", pnum, ec); - else if (list == &si->erase) + si->free_peb_count += 1; + } else if (list == &si->erase) { dbg_bld("add to erase: PEB %d, EC %d", pnum, ec); - else if (list == &si->corr) { + si->erase_peb_count += 1; + } else if (list == &si->corr) { dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec); - si->corr_count += 1; - } else if (list == &si->alien) + si->corr_peb_count += 1; + } else if (list == &si->alien) { dbg_bld("add to alien: PEB %d, EC %d", pnum, ec); - else + si->alien_peb_count += 1; + } else BUG(); seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL); @@ -517,6 +521,7 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, sv->leb_count += 1; rb_link_node(&seb->u.rb, parent, p); rb_insert_color(&seb->u.rb, &sv->root); + si->used_peb_count += 1; return 0; } @@ -745,19 +750,17 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, bitflips = 1; else if (err == UBI_IO_PEB_EMPTY) return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase); - else if (err == UBI_IO_BAD_EC_HDR) { + else if (err == UBI_IO_BAD_HDR_READ || err == UBI_IO_BAD_HDR) { /* * We have to also look at the VID header, possibly it is not * corrupted. Set %bitflips flag in order to make this PEB be * moved and EC be re-created. */ - ec_corr = 1; + ec_corr = err; ec = UBI_SCAN_UNKNOWN_EC; bitflips = 1; } - si->is_empty = 0; - if (!ec_corr) { int image_seq; @@ -813,9 +816,12 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, return err; else if (err == UBI_IO_BITFLIPS) bitflips = 1; - else if (err == UBI_IO_BAD_VID_HDR || + else if (err == UBI_IO_BAD_HDR_READ || err == UBI_IO_BAD_HDR || (err == UBI_IO_PEB_FREE && ec_corr)) { /* VID header is corrupted */ + if (err == UBI_IO_BAD_HDR_READ || + ec_corr == UBI_IO_BAD_HDR_READ) + si->read_err_count += 1; err = add_to_list(si, pnum, ec, &si->corr); if (err) return err; @@ -836,11 +842,11 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, switch (vidh->compat) { case UBI_COMPAT_DELETE: ubi_msg("\"delete\" compatible internal volume %d:%d" - " found, remove it", vol_id, lnum); + " found, will remove it", vol_id, lnum); err = add_to_list(si, pnum, ec, &si->corr); if (err) return err; - break; + return 0; case UBI_COMPAT_RO: ubi_msg("read-only compatible internal volume %d:%d" @@ -855,7 +861,6 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, err = add_to_list(si, pnum, ec, &si->alien); if (err) return err; - si->alien_peb_count += 1; return 0; case UBI_COMPAT_REJECT: @@ -886,6 +891,85 @@ adjust_mean_ec: } /** + * check_what_we_have - check what PEB were found by scanning. + * @ubi: UBI device description object + * @si: scanning information + * + * This is a helper function which takes a look what PEBs were found by + * scanning, and decides whether the flash is empty and should be formatted and + * whether there are too many corrupted PEBs and we should not attach this + * MTD device. Returns zero if we should proceed with attaching the MTD device, + * and %-EINVAL if we should not. + */ +static int check_what_we_have(struct ubi_device *ubi, struct ubi_scan_info *si) +{ + struct ubi_scan_leb *seb; + int max_corr; + + max_corr = ubi->peb_count - si->bad_peb_count - si->alien_peb_count; + max_corr = max_corr / 20 ?: 8; + + /* + * Few corrupted PEBs are not a problem and may be just a result of + * unclean reboots. However, many of them may indicate some problems + * with the flash HW or driver. + */ + if (si->corr_peb_count >= 8) { + ubi_warn("%d PEBs are corrupted", si->corr_peb_count); + printk(KERN_WARNING "corrupted PEBs are:"); + list_for_each_entry(seb, &si->corr, u.list) + printk(KERN_CONT " %d", seb->pnum); + printk(KERN_CONT "\n"); + + /* + * If too many PEBs are corrupted, we refuse attaching, + * otherwise, only print a warning. + */ + if (si->corr_peb_count >= max_corr) { + ubi_err("too many corrupted PEBs, refusing this device"); + return -EINVAL; + } + } + + if (si->free_peb_count + si->used_peb_count + + si->alien_peb_count == 0) { + /* No UBI-formatted eraseblocks were found */ + if (si->corr_peb_count == si->read_err_count && + si->corr_peb_count < 8) { + /* No or just few corrupted PEBs, and all of them had a + * read error. We assume that those are bad PEBs, which + * were just not marked as bad so far. + * + * This piece of code basically tries to distinguish + * between the following 2 situations: + * + * 1. Flash is empty, but there are few bad PEBs, which + * are not marked as bad so far, and which were read + * with error. We want to go ahead and format this + * flash. While formating, the faulty PEBs will + * probably be marked as bad. + * + * 2. Flash probably contains non-UBI data and we do + * not want to format it and destroy possibly needed + * data (e.g., consider the case when the bootloader + * MTD partition was accidentally fed to UBI). + */ + si->is_empty = 1; + ubi_msg("empty MTD device detected"); + get_random_bytes(&ubi->image_seq, sizeof(ubi->image_seq)); + } else { + ubi_err("MTD device possibly contains non-UBI data, " + "refusing it"); + return -EINVAL; + } + } + + if (si->corr_peb_count > 0) + ubi_msg("corrupted PEBs will be formatted"); + return 0; +} + +/** * ubi_scan - scan an MTD device. * @ubi: UBI device description object * @@ -909,7 +993,6 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) INIT_LIST_HEAD(&si->erase); INIT_LIST_HEAD(&si->alien); si->volumes = RB_ROOT; - si->is_empty = 1; err = -ENOMEM; ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); @@ -935,21 +1018,9 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) if (si->ec_count) si->mean_ec = div_u64(si->ec_sum, si->ec_count); - if (si->is_empty) - ubi_msg("empty MTD device detected"); - - /* - * Few corrupted PEBs are not a problem and may be just a result of - * unclean reboots. However, many of them may indicate some problems - * with the flash HW or driver. Print a warning in this case. - */ - if (si->corr_count >= 8 || si->corr_count >= ubi->peb_count / 4) { - ubi_warn("%d PEBs are corrupted", si->corr_count); - printk(KERN_WARNING "corrupted PEBs are:"); - list_for_each_entry(seb, &si->corr, u.list) - printk(KERN_CONT " %d", seb->pnum); - printk(KERN_CONT "\n"); - } + err = check_what_we_have(ubi, si); + if (err) + goto out_vidh; /* * In case of unknown erase counter we use the mean erase counter diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h index ff179ad7ca5..2576a8d1532 100644 --- a/drivers/mtd/ubi/scan.h +++ b/drivers/mtd/ubi/scan.h @@ -91,10 +91,16 @@ struct ubi_scan_volume { * @erase: list of physical eraseblocks which have to be erased * @alien: list of physical eraseblocks which should not be used by UBI (e.g., * those belonging to "preserve"-compatible internal volumes) + * @used_peb_count: count of used PEBs + * @corr_peb_count: count of PEBs in the @corr list + * @read_err_count: count of PEBs read with error (%UBI_IO_BAD_HDR_READ was + * returned) + * @free_peb_count: count of PEBs in the @free list + * @erase_peb_count: count of PEBs in the @erase list + * @alien_peb_count: count of PEBs in the @alien list * @bad_peb_count: count of bad physical eraseblocks * @vols_found: number of volumes found during scanning * @highest_vol_id: highest volume ID - * @alien_peb_count: count of physical eraseblocks in the @alien list * @is_empty: flag indicating whether the MTD device is empty or not * @min_ec: lowest erase counter value * @max_ec: highest erase counter value @@ -102,7 +108,6 @@ struct ubi_scan_volume { * @mean_ec: mean erase counter value * @ec_sum: a temporary variable used when calculating @mean_ec * @ec_count: a temporary variable used when calculating @mean_ec - * @corr_count: count of corrupted PEBs * * This data structure contains the result of scanning and may be used by other * UBI sub-systems to build final UBI data structures, further error-recovery @@ -114,10 +119,15 @@ struct ubi_scan_info { struct list_head free; struct list_head erase; struct list_head alien; + int used_peb_count; + int corr_peb_count; + int read_err_count; + int free_peb_count; + int erase_peb_count; + int alien_peb_count; int bad_peb_count; int vols_found; int highest_vol_id; - int alien_peb_count; int is_empty; int min_ec; int max_ec; @@ -125,7 +135,6 @@ struct ubi_scan_info { int mean_ec; uint64_t ec_sum; int ec_count; - int corr_count; }; struct ubi_device; @@ -135,7 +144,7 @@ struct ubi_vid_hdr; * ubi_scan_move_to_list - move a PEB from the volume tree to a list. * * @sv: volume scanning information - * @seb: scanning eraseblock infprmation + * @seb: scanning eraseblock information * @list: the list to move to */ static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv, diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index a637f0283ad..0359e0cce48 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -89,16 +89,16 @@ * %0xFF bytes * UBI_IO_PEB_FREE: the physical eraseblock is free, i.e. it contains only a * valid erase counter header, and the rest are %0xFF bytes - * UBI_IO_BAD_EC_HDR: the erase counter header is corrupted (bad magic or CRC) - * UBI_IO_BAD_VID_HDR: the volume identifier header is corrupted (bad magic or - * CRC) + * UBI_IO_BAD_HDR: the EC or VID header is corrupted (bad magic or CRC) + * UBI_IO_BAD_HDR_READ: the same as %UBI_IO_BAD_HDR, but also there was a read + * error reported by the flash driver * UBI_IO_BITFLIPS: bit-flips were detected and corrected */ enum { UBI_IO_PEB_EMPTY = 1, UBI_IO_PEB_FREE, - UBI_IO_BAD_EC_HDR, - UBI_IO_BAD_VID_HDR, + UBI_IO_BAD_HDR, + UBI_IO_BAD_HDR_READ, UBI_IO_BITFLIPS }; diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 8bd23687c53..bb0872a6331 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -1062,6 +1062,10 @@ struct bnx2x { /* used to synchronize stats collecting */ int stats_state; + + /* used for synchronization of concurrent threads statistics handling */ + spinlock_t stats_lock; + /* used by dmae command loader */ struct dmae_command stats_dmae; int executer_idx; diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 57ff5b3bcce..46167c08172 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -57,8 +57,8 @@ #include "bnx2x_init_ops.h" #include "bnx2x_dump.h" -#define DRV_MODULE_VERSION "1.52.53-1" -#define DRV_MODULE_RELDATE "2010/18/04" +#define DRV_MODULE_VERSION "1.52.53-2" +#define DRV_MODULE_RELDATE "2010/21/07" #define BNX2X_BC_VER 0x040200 #include <linux/firmware.h> @@ -3789,6 +3789,8 @@ static void bnx2x_storm_stats_post(struct bnx2x *bp) struct eth_query_ramrod_data ramrod_data = {0}; int i, rc; + spin_lock_bh(&bp->stats_lock); + ramrod_data.drv_counter = bp->stats_counter++; ramrod_data.collect_port = bp->port.pmf ? 1 : 0; for_each_queue(bp, i) @@ -3802,6 +3804,8 @@ static void bnx2x_storm_stats_post(struct bnx2x *bp) bp->spq_left++; bp->stats_pending = 1; } + + spin_unlock_bh(&bp->stats_lock); } } @@ -4367,6 +4371,14 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp) struct host_func_stats *fstats = bnx2x_sp(bp, func_stats); struct bnx2x_eth_stats *estats = &bp->eth_stats; int i; + u16 cur_stats_counter; + + /* Make sure we use the value of the counter + * used for sending the last stats ramrod. + */ + spin_lock_bh(&bp->stats_lock); + cur_stats_counter = bp->stats_counter - 1; + spin_unlock_bh(&bp->stats_lock); memcpy(&(fstats->total_bytes_received_hi), &(bnx2x_sp(bp, func_stats_base)->total_bytes_received_hi), @@ -4394,25 +4406,22 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp) u32 diff; /* are storm stats valid? */ - if ((u16)(le16_to_cpu(xclient->stats_counter) + 1) != - bp->stats_counter) { + if (le16_to_cpu(xclient->stats_counter) != cur_stats_counter) { DP(BNX2X_MSG_STATS, "[%d] stats not updated by xstorm" " xstorm counter (0x%x) != stats_counter (0x%x)\n", - i, xclient->stats_counter, bp->stats_counter); + i, xclient->stats_counter, cur_stats_counter + 1); return -1; } - if ((u16)(le16_to_cpu(tclient->stats_counter) + 1) != - bp->stats_counter) { + if (le16_to_cpu(tclient->stats_counter) != cur_stats_counter) { DP(BNX2X_MSG_STATS, "[%d] stats not updated by tstorm" " tstorm counter (0x%x) != stats_counter (0x%x)\n", - i, tclient->stats_counter, bp->stats_counter); + i, tclient->stats_counter, cur_stats_counter + 1); return -2; } - if ((u16)(le16_to_cpu(uclient->stats_counter) + 1) != - bp->stats_counter) { + if (le16_to_cpu(uclient->stats_counter) != cur_stats_counter) { DP(BNX2X_MSG_STATS, "[%d] stats not updated by ustorm" " ustorm counter (0x%x) != stats_counter (0x%x)\n", - i, uclient->stats_counter, bp->stats_counter); + i, uclient->stats_counter, cur_stats_counter + 1); return -4; } @@ -4849,16 +4858,18 @@ static const struct { static void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event) { - enum bnx2x_stats_state state = bp->stats_state; + enum bnx2x_stats_state state; if (unlikely(bp->panic)) return; - bnx2x_stats_stm[state][event].action(bp); + /* Protect a state change flow */ + spin_lock_bh(&bp->stats_lock); + state = bp->stats_state; bp->stats_state = bnx2x_stats_stm[state][event].next_state; + spin_unlock_bh(&bp->stats_lock); - /* Make sure the state has been "changed" */ - smp_wmb(); + bnx2x_stats_stm[state][event].action(bp); if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp)) DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n", @@ -9908,6 +9919,7 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp) mutex_init(&bp->port.phy_mutex); mutex_init(&bp->fw_mb_mutex); + spin_lock_init(&bp->stats_lock); #ifdef BCM_CNIC mutex_init(&bp->cnic_mutex); #endif diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 40fdc41446c..8d7dfd2f1e9 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -340,7 +340,8 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) if ((client_info->assigned) && (client_info->ip_src == arp->ip_dst) && - (client_info->ip_dst == arp->ip_src)) { + (client_info->ip_dst == arp->ip_src) && + (compare_ether_addr_64bits(client_info->mac_dst, arp->mac_src))) { /* update the clients MAC address */ memcpy(client_info->mac_dst, arp->mac_src, ETH_ALEN); client_info->ntt = 1; @@ -821,7 +822,7 @@ static int rlb_initialize(struct bonding *bond) /*initialize packet type*/ pk_type->type = cpu_to_be16(ETH_P_ARP); - pk_type->dev = NULL; + pk_type->dev = bond->dev; pk_type->func = rlb_arp_recv; /* register to receive ARPs */ diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 5e12462a9d5..c3d98dde2f8 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -168,7 +168,7 @@ static int arp_ip_count; static int bond_mode = BOND_MODE_ROUNDROBIN; static int xmit_hashtype = BOND_XMIT_POLICY_LAYER2; static int lacp_fast; - +static int disable_netpoll = 1; const struct bond_parm_tbl bond_lacp_tbl[] = { { "slow", AD_LACP_SLOW}, @@ -1742,15 +1742,23 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_set_carrier(bond); #ifdef CONFIG_NET_POLL_CONTROLLER - if (slaves_support_netpoll(bond_dev)) { - bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL; - if (bond_dev->npinfo) - slave_dev->npinfo = bond_dev->npinfo; - } else if (!(bond_dev->priv_flags & IFF_DISABLE_NETPOLL)) { + /* + * Netpoll and bonding is broken, make sure it is not initialized + * until it is fixed. + */ + if (disable_netpoll) { bond_dev->priv_flags |= IFF_DISABLE_NETPOLL; - pr_info("New slave device %s does not support netpoll\n", - slave_dev->name); - pr_info("Disabling netpoll support for %s\n", bond_dev->name); + } else { + if (slaves_support_netpoll(bond_dev)) { + bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL; + if (bond_dev->npinfo) + slave_dev->npinfo = bond_dev->npinfo; + } else if (!(bond_dev->priv_flags & IFF_DISABLE_NETPOLL)) { + bond_dev->priv_flags |= IFF_DISABLE_NETPOLL; + pr_info("New slave device %s does not support netpoll\n", + slave_dev->name); + pr_info("Disabling netpoll support for %s\n", bond_dev->name); + } } #endif read_unlock(&bond->lock); @@ -1950,8 +1958,11 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) #ifdef CONFIG_NET_POLL_CONTROLLER read_lock_bh(&bond->lock); - if (slaves_support_netpoll(bond_dev)) - bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL; + + /* Make sure netpoll over stays disabled until fixed. */ + if (!disable_netpoll) + if (slaves_support_netpoll(bond_dev)) + bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL; read_unlock_bh(&bond->lock); if (slave_dev->netdev_ops->ndo_netpoll_cleanup) slave_dev->netdev_ops->ndo_netpoll_cleanup(slave_dev); diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 1d973db27c3..d7de376d717 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -1022,7 +1022,7 @@ static const struct net_device_ops lance_netdev_ops = { .ndo_set_mac_address = eth_mac_addr, }; -static int __init dec_lance_probe(struct device *bdev, const int type) +static int __devinit dec_lance_probe(struct device *bdev, const int type) { static unsigned version_printed; static const char fmt[] = "declance%d"; @@ -1326,7 +1326,7 @@ static void __exit dec_lance_platform_remove(void) } #ifdef CONFIG_TC -static int __init dec_lance_tc_probe(struct device *dev); +static int __devinit dec_lance_tc_probe(struct device *dev); static int __exit dec_lance_tc_remove(struct device *dev); static const struct tc_device_id dec_lance_tc_table[] = { @@ -1345,7 +1345,7 @@ static struct tc_driver dec_lance_tc_driver = { }, }; -static int __init dec_lance_tc_probe(struct device *dev) +static int __devinit dec_lance_tc_probe(struct device *dev) { int status = dec_lance_probe(dev, PMAD_LANCE); if (!status) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 7acb3edc47e..2602852cc55 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -677,7 +677,7 @@ static int ibmveth_close(struct net_device *netdev) if (!adapter->pool_config) netif_stop_queue(netdev); - free_irq(netdev->irq, netdev); + h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE); do { lpar_rc = h_free_logical_lan(adapter->vdev->unit_address); @@ -689,6 +689,8 @@ static int ibmveth_close(struct net_device *netdev) lpar_rc); } + free_irq(netdev->irq, netdev); + adapter->rx_no_buffer = *(u64*)(((char*)adapter->buffer_list_addr) + 4096 - 8); ibmveth_cleanup(adapter); diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 3881918f538..cea37e0837f 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -1722,6 +1722,15 @@ static int __devinit igb_probe(struct pci_dev *pdev, u16 eeprom_apme_mask = IGB_EEPROM_APME; u32 part_num; + /* Catch broken hardware that put the wrong VF device ID in + * the PCIe SR-IOV capability. + */ + if (pdev->is_virtfn) { + WARN(1, KERN_ERR "%s (%hx:%hx) should not be a VF!\n", + pci_name(pdev), pdev->vendor, pdev->device); + return -EINVAL; + } + err = pci_enable_device_mem(pdev); if (err) return err; diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index ce30c62a97f..74d9b6df302 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3684,10 +3684,6 @@ void ixgbe_down(struct ixgbe_adapter *adapter) /* signal that we are down to the interrupt handler */ set_bit(__IXGBE_DOWN, &adapter->state); - /* power down the optics */ - if (hw->phy.multispeed_fiber) - hw->mac.ops.disable_tx_laser(hw); - /* disable receive for all VFs and wait one second */ if (adapter->num_vfs) { /* ping all the active vfs to let them know we are going down */ @@ -3742,6 +3738,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter) (IXGBE_READ_REG(hw, IXGBE_DMATXCTL) & ~IXGBE_DMATXCTL_TE)); + /* power down the optics */ + if (hw->phy.multispeed_fiber) + hw->mac.ops.disable_tx_laser(hw); + /* clear n-tuple filters that are cached */ ethtool_ntuple_flush(netdev); @@ -4001,7 +4001,7 @@ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter) done: /* Notify the stack of the (possibly) reduced Tx Queue count. */ - adapter->netdev->real_num_tx_queues = adapter->num_tx_queues; + netif_set_real_num_tx_queues(adapter->netdev, adapter->num_tx_queues); } static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter, @@ -5195,7 +5195,6 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake) ixgbe_free_all_tx_resources(adapter); ixgbe_free_all_rx_resources(adapter); } - ixgbe_clear_interrupt_scheme(adapter); #ifdef CONFIG_PM retval = pci_save_state(pdev); @@ -5230,6 +5229,8 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake) *enable_wake = !!wufc; + ixgbe_clear_interrupt_scheme(adapter); + ixgbe_release_hw_control(adapter); pci_disable_device(pdev); @@ -6023,7 +6024,6 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter, static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb, int queue, u32 tx_flags) { - /* Right now, we support IPv4 only */ struct ixgbe_atr_input atr_input; struct tcphdr *th; struct iphdr *iph = ip_hdr(skb); @@ -6032,6 +6032,9 @@ static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb, u32 src_ipv4_addr, dst_ipv4_addr; u8 l4type = 0; + /* Right now, we support IPv4 only */ + if (skb->protocol != htons(ETH_P_IP)) + return; /* check if we're UDP or TCP */ if (iph->protocol == IPPROTO_TCP) { th = tcp_hdr(skb); @@ -6489,6 +6492,15 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, #endif u32 part_num, eec; + /* Catch broken hardware that put the wrong VF device ID in + * the PCIe SR-IOV capability. + */ + if (pdev->is_virtfn) { + WARN(1, KERN_ERR "%s (%hx:%hx) should not be a VF!\n", + pci_name(pdev), pdev->vendor, pdev->device); + return -EINVAL; + } + err = pci_enable_device_mem(pdev); if (err) return err; diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index 52dcc849564..6474c4973d3 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c @@ -964,7 +964,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match) np = of_parse_phandle(op->dev.of_node, "llink-connected", 0); if (!np) { dev_err(&op->dev, "could not find DMA node\n"); - goto nodev; + goto err_iounmap; } /* Setup the DMA register accesses, could be DCR or memory mapped */ @@ -978,7 +978,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match) dev_dbg(&op->dev, "MEM base: %p\n", lp->sdma_regs); } else { dev_err(&op->dev, "unable to map DMA registers\n"); - goto nodev; + goto err_iounmap; } } @@ -987,7 +987,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match) if ((lp->rx_irq == NO_IRQ) || (lp->tx_irq == NO_IRQ)) { dev_err(&op->dev, "could not determine irqs\n"); rc = -ENOMEM; - goto nodev; + goto err_iounmap_2; } of_node_put(np); /* Finished with the DMA node; drop the reference */ @@ -997,7 +997,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match) if ((!addr) || (size != 6)) { dev_err(&op->dev, "could not find MAC address\n"); rc = -ENODEV; - goto nodev; + goto err_iounmap_2; } temac_set_mac_address(ndev, (void *)addr); @@ -1013,7 +1013,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match) rc = sysfs_create_group(&lp->dev->kobj, &temac_attr_group); if (rc) { dev_err(lp->dev, "Error creating sysfs files\n"); - goto nodev; + goto err_iounmap_2; } rc = register_netdev(lp->ndev); @@ -1026,6 +1026,11 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match) err_register_ndev: sysfs_remove_group(&lp->dev->kobj, &temac_attr_group); + err_iounmap_2: + if (lp->sdma_regs) + iounmap(lp->sdma_regs); + err_iounmap: + iounmap(lp->regs); nodev: free_netdev(ndev); ndev = NULL; @@ -1044,6 +1049,9 @@ static int __devexit temac_of_remove(struct of_device *op) of_node_put(lp->phy_node); lp->phy_node = NULL; dev_set_drvdata(&op->dev, NULL); + iounmap(lp->regs); + if (lp->sdma_regs) + iounmap(lp->sdma_regs); free_netdev(ndev); return 0; } diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 87e8d4cb405..f15fe2cf72a 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -499,7 +499,7 @@ static const struct net_device_ops macvlan_netdev_ops = { .ndo_validate_addr = eth_validate_addr, }; -static void macvlan_setup(struct net_device *dev) +void macvlan_common_setup(struct net_device *dev) { ether_setup(dev); @@ -508,6 +508,12 @@ static void macvlan_setup(struct net_device *dev) dev->destructor = free_netdev; dev->header_ops = &macvlan_hard_header_ops, dev->ethtool_ops = &macvlan_ethtool_ops; +} +EXPORT_SYMBOL_GPL(macvlan_common_setup); + +static void macvlan_setup(struct net_device *dev) +{ + macvlan_common_setup(dev); dev->tx_queue_len = 0; } @@ -705,7 +711,6 @@ int macvlan_link_register(struct rtnl_link_ops *ops) /* common fields */ ops->priv_size = sizeof(struct macvlan_dev); ops->get_tx_queues = macvlan_get_tx_queues; - ops->setup = macvlan_setup; ops->validate = macvlan_validate; ops->maxtype = IFLA_MACVLAN_MAX; ops->policy = macvlan_policy; @@ -719,6 +724,7 @@ EXPORT_SYMBOL_GPL(macvlan_link_register); static struct rtnl_link_ops macvlan_link_ops = { .kind = "macvlan", + .setup = macvlan_setup, .newlink = macvlan_newlink, .dellink = macvlan_dellink, }; diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index a8a94e2f6dd..ff02b836c3c 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -180,11 +180,18 @@ static int macvtap_forward(struct net_device *dev, struct sk_buff *skb) { struct macvtap_queue *q = macvtap_get_queue(dev, skb); if (!q) - return -ENOLINK; + goto drop; + + if (skb_queue_len(&q->sk.sk_receive_queue) >= dev->tx_queue_len) + goto drop; skb_queue_tail(&q->sk.sk_receive_queue, skb); wake_up_interruptible_poll(sk_sleep(&q->sk), POLLIN | POLLRDNORM | POLLRDBAND); - return 0; + return NET_RX_SUCCESS; + +drop: + kfree_skb(skb); + return NET_RX_DROP; } /* @@ -235,8 +242,15 @@ static void macvtap_dellink(struct net_device *dev, macvlan_dellink(dev, head); } +static void macvtap_setup(struct net_device *dev) +{ + macvlan_common_setup(dev); + dev->tx_queue_len = TUN_READQ_SIZE; +} + static struct rtnl_link_ops macvtap_link_ops __read_mostly = { .kind = "macvtap", + .setup = macvtap_setup, .newlink = macvtap_newlink, .dellink = macvtap_dellink, }; diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index e345ec8cb47..73bb8ea6f54 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -289,6 +289,7 @@ struct mv643xx_eth_shared_private { unsigned int t_clk; int extended_rx_coal_limit; int tx_bw_control; + int tx_csum_limit; }; #define TX_BW_CONTROL_ABSENT 0 @@ -776,13 +777,16 @@ static int txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb) l4i_chk = 0; if (skb->ip_summed == CHECKSUM_PARTIAL) { + int hdr_len; int tag_bytes; BUG_ON(skb->protocol != htons(ETH_P_IP) && skb->protocol != htons(ETH_P_8021Q)); - tag_bytes = (void *)ip_hdr(skb) - (void *)skb->data - ETH_HLEN; - if (unlikely(tag_bytes & ~12)) { + hdr_len = (void *)ip_hdr(skb) - (void *)skb->data; + tag_bytes = hdr_len - ETH_HLEN; + if (skb->len - hdr_len > mp->shared->tx_csum_limit || + unlikely(tag_bytes & ~12)) { if (skb_checksum_help(skb) == 0) goto no_csum; kfree_skb(skb); @@ -2666,6 +2670,7 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev) * Detect hardware parameters. */ msp->t_clk = (pd != NULL && pd->t_clk != 0) ? pd->t_clk : 133000000; + msp->tx_csum_limit = pd->tx_csum_limit ? pd->tx_csum_limit : 9 * 1024; infer_hw_params(msp); platform_set_drvdata(pdev, msp); diff --git a/drivers/net/ne.c b/drivers/net/ne.c index b8e2923a1d6..1063093b3af 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -806,8 +806,10 @@ static int __init ne_drv_probe(struct platform_device *pdev) dev->base_addr = res->start; dev->irq = platform_get_irq(pdev, 0); } else { - if (this_dev < 0 || this_dev >= MAX_NE_CARDS) + if (this_dev < 0 || this_dev >= MAX_NE_CARDS) { + free_netdev(dev); return -EINVAL; + } dev->base_addr = io[this_dev]; dev->irq = irq[this_dev]; dev->mem_end = bad[this_dev]; diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 5b3dfb4ab27..33525bf2a3d 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -1168,6 +1168,7 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id) int interrupts, nr_serviced = 0, i; struct ei_device *ei_local; int handled = 0; + unsigned long flags; e8390_base = dev->base_addr; ei_local = netdev_priv(dev); @@ -1176,7 +1177,7 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id) * Protect the irq test too. */ - spin_lock(&ei_local->page_lock); + spin_lock_irqsave(&ei_local->page_lock, flags); if (ei_local->irqlock) { @@ -1188,7 +1189,7 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id) dev->name, inb_p(e8390_base + EN0_ISR), inb_p(e8390_base + EN0_IMR)); #endif - spin_unlock(&ei_local->page_lock); + spin_unlock_irqrestore(&ei_local->page_lock, flags); return IRQ_NONE; } @@ -1261,7 +1262,7 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id) ei_local->irqlock = 0; outb_p(ENISR_ALL, e8390_base + EN0_IMR); - spin_unlock(&ei_local->page_lock); + spin_unlock_irqrestore(&ei_local->page_lock, flags); return IRQ_RETVAL(handled); } diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 78b74e83ce5..5a1bd5db2a9 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -29,6 +29,7 @@ #include <linux/mii.h> #include <linux/ethtool.h> #include <linux/phy.h> +#include <linux/marvell_phy.h> #include <asm/io.h> #include <asm/irq.h> @@ -48,8 +49,6 @@ #define MII_M1145_RGMII_RX_DELAY 0x0080 #define MII_M1145_RGMII_TX_DELAY 0x0002 -#define M1145_DEV_FLAGS_RESISTANCE 0x00000001 - #define MII_M1111_PHY_LED_CONTROL 0x18 #define MII_M1111_PHY_LED_DIRECT 0x4100 #define MII_M1111_PHY_LED_COMBINE 0x411c @@ -350,7 +349,10 @@ static int m88e1118_config_init(struct phy_device *phydev) return err; /* Adjust LED Control */ - err = phy_write(phydev, 0x10, 0x021e); + if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS) + err = phy_write(phydev, 0x10, 0x1100); + else + err = phy_write(phydev, 0x10, 0x021e); if (err < 0) return err; @@ -398,7 +400,7 @@ static int m88e1145_config_init(struct phy_device *phydev) if (err < 0) return err; - if (phydev->dev_flags & M1145_DEV_FLAGS_RESISTANCE) { + if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) { err = phy_write(phydev, 0x1d, 0x0012); if (err < 0) return err; @@ -529,8 +531,8 @@ static int m88e1121_did_interrupt(struct phy_device *phydev) static struct phy_driver marvell_drivers[] = { { - .phy_id = 0x01410c60, - .phy_id_mask = 0xfffffff0, + .phy_id = MARVELL_PHY_ID_88E1101, + .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "Marvell 88E1101", .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, @@ -541,8 +543,8 @@ static struct phy_driver marvell_drivers[] = { .driver = { .owner = THIS_MODULE }, }, { - .phy_id = 0x01410c90, - .phy_id_mask = 0xfffffff0, + .phy_id = MARVELL_PHY_ID_88E1112, + .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "Marvell 88E1112", .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, @@ -554,8 +556,8 @@ static struct phy_driver marvell_drivers[] = { .driver = { .owner = THIS_MODULE }, }, { - .phy_id = 0x01410cc0, - .phy_id_mask = 0xfffffff0, + .phy_id = MARVELL_PHY_ID_88E1111, + .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "Marvell 88E1111", .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, @@ -567,8 +569,8 @@ static struct phy_driver marvell_drivers[] = { .driver = { .owner = THIS_MODULE }, }, { - .phy_id = 0x01410e10, - .phy_id_mask = 0xfffffff0, + .phy_id = MARVELL_PHY_ID_88E1118, + .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "Marvell 88E1118", .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, @@ -580,8 +582,8 @@ static struct phy_driver marvell_drivers[] = { .driver = {.owner = THIS_MODULE,}, }, { - .phy_id = 0x01410cb0, - .phy_id_mask = 0xfffffff0, + .phy_id = MARVELL_PHY_ID_88E1121R, + .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "Marvell 88E1121R", .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, @@ -593,8 +595,8 @@ static struct phy_driver marvell_drivers[] = { .driver = { .owner = THIS_MODULE }, }, { - .phy_id = 0x01410cd0, - .phy_id_mask = 0xfffffff0, + .phy_id = MARVELL_PHY_ID_88E1145, + .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "Marvell 88E1145", .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, @@ -606,8 +608,8 @@ static struct phy_driver marvell_drivers[] = { .driver = { .owner = THIS_MODULE }, }, { - .phy_id = 0x01410e30, - .phy_id_mask = 0xfffffff0, + .phy_id = MARVELL_PHY_ID_88E1240, + .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "Marvell 88E1240", .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index fa4b24c49f4..d10bcefc0e4 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -4611,8 +4611,7 @@ static void ql_timer(unsigned long data) return; } - qdev->timer.expires = jiffies + (5*HZ); - add_timer(&qdev->timer); + mod_timer(&qdev->timer, jiffies + (5*HZ)); } static int __devinit qlge_probe(struct pci_dev *pdev, @@ -4713,6 +4712,8 @@ static void ql_eeh_close(struct net_device *ndev) netif_stop_queue(ndev); } + /* Disabling the timer */ + del_timer_sync(&qdev->timer); if (test_bit(QL_ADAPTER_UP, &qdev->flags)) cancel_delayed_work_sync(&qdev->asic_reset_work); cancel_delayed_work_sync(&qdev->mpi_reset_work); @@ -4808,8 +4809,7 @@ static void qlge_io_resume(struct pci_dev *pdev) netif_err(qdev, ifup, qdev->ndev, "Device was not running prior to EEH.\n"); } - qdev->timer.expires = jiffies + (5*HZ); - add_timer(&qdev->timer); + mod_timer(&qdev->timer, jiffies + (5*HZ)); netif_device_attach(ndev); } @@ -4871,8 +4871,7 @@ static int qlge_resume(struct pci_dev *pdev) return err; } - qdev->timer.expires = jiffies + (5*HZ); - add_timer(&qdev->timer); + mod_timer(&qdev->timer, jiffies + (5*HZ)); netif_device_attach(ndev); return 0; diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 96b6cfbf0a3..cdc6a5c2e70 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1316,7 +1316,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, { 0x7c800000, 0x28000000, RTL_GIGA_MAC_VER_26 }, /* 8168C family. */ - { 0x7cf00000, 0x3ca00000, RTL_GIGA_MAC_VER_24 }, + { 0x7cf00000, 0x3cb00000, RTL_GIGA_MAC_VER_24 }, { 0x7cf00000, 0x3c900000, RTL_GIGA_MAC_VER_23 }, { 0x7cf00000, 0x3c800000, RTL_GIGA_MAC_VER_18 }, { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_24 }, diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 668327ccd8d..1d37f0c310c 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -3130,7 +3130,6 @@ static void tx_intr_handler(struct fifo_info *fifo_data) pkt_cnt++; /* Updating the statistics block */ - nic->dev->stats.tx_bytes += skb->len; swstats->mem_freed += skb->truesize; dev_kfree_skb_irq(skb); @@ -4901,48 +4900,81 @@ static void s2io_updt_stats(struct s2io_nic *sp) * Return value: * pointer to the updated net_device_stats structure. */ - static struct net_device_stats *s2io_get_stats(struct net_device *dev) { struct s2io_nic *sp = netdev_priv(dev); - struct config_param *config = &sp->config; struct mac_info *mac_control = &sp->mac_control; struct stat_block *stats = mac_control->stats_info; - int i; + u64 delta; /* Configure Stats for immediate updt */ s2io_updt_stats(sp); - /* Using sp->stats as a staging area, because reset (due to mtu - change, for example) will clear some hardware counters */ - dev->stats.tx_packets += le32_to_cpu(stats->tmac_frms) - - sp->stats.tx_packets; - sp->stats.tx_packets = le32_to_cpu(stats->tmac_frms); - - dev->stats.tx_errors += le32_to_cpu(stats->tmac_any_err_frms) - - sp->stats.tx_errors; - sp->stats.tx_errors = le32_to_cpu(stats->tmac_any_err_frms); - - dev->stats.rx_errors += le64_to_cpu(stats->rmac_drop_frms) - - sp->stats.rx_errors; - sp->stats.rx_errors = le64_to_cpu(stats->rmac_drop_frms); - - dev->stats.multicast = le32_to_cpu(stats->rmac_vld_mcst_frms) - - sp->stats.multicast; - sp->stats.multicast = le32_to_cpu(stats->rmac_vld_mcst_frms); - - dev->stats.rx_length_errors = le64_to_cpu(stats->rmac_long_frms) - - sp->stats.rx_length_errors; - sp->stats.rx_length_errors = le64_to_cpu(stats->rmac_long_frms); + /* A device reset will cause the on-adapter statistics to be zero'ed. + * This can be done while running by changing the MTU. To prevent the + * system from having the stats zero'ed, the driver keeps a copy of the + * last update to the system (which is also zero'ed on reset). This + * enables the driver to accurately know the delta between the last + * update and the current update. + */ + delta = ((u64) le32_to_cpu(stats->rmac_vld_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_vld_frms)) - sp->stats.rx_packets; + sp->stats.rx_packets += delta; + dev->stats.rx_packets += delta; + + delta = ((u64) le32_to_cpu(stats->tmac_frms_oflow) << 32 | + le32_to_cpu(stats->tmac_frms)) - sp->stats.tx_packets; + sp->stats.tx_packets += delta; + dev->stats.tx_packets += delta; + + delta = ((u64) le32_to_cpu(stats->rmac_data_octets_oflow) << 32 | + le32_to_cpu(stats->rmac_data_octets)) - sp->stats.rx_bytes; + sp->stats.rx_bytes += delta; + dev->stats.rx_bytes += delta; + + delta = ((u64) le32_to_cpu(stats->tmac_data_octets_oflow) << 32 | + le32_to_cpu(stats->tmac_data_octets)) - sp->stats.tx_bytes; + sp->stats.tx_bytes += delta; + dev->stats.tx_bytes += delta; + + delta = le64_to_cpu(stats->rmac_drop_frms) - sp->stats.rx_errors; + sp->stats.rx_errors += delta; + dev->stats.rx_errors += delta; + + delta = ((u64) le32_to_cpu(stats->tmac_any_err_frms_oflow) << 32 | + le32_to_cpu(stats->tmac_any_err_frms)) - sp->stats.tx_errors; + sp->stats.tx_errors += delta; + dev->stats.tx_errors += delta; + + delta = le64_to_cpu(stats->rmac_drop_frms) - sp->stats.rx_dropped; + sp->stats.rx_dropped += delta; + dev->stats.rx_dropped += delta; + + delta = le64_to_cpu(stats->tmac_drop_frms) - sp->stats.tx_dropped; + sp->stats.tx_dropped += delta; + dev->stats.tx_dropped += delta; + + /* The adapter MAC interprets pause frames as multicast packets, but + * does not pass them up. This erroneously increases the multicast + * packet count and needs to be deducted when the multicast frame count + * is queried. + */ + delta = (u64) le32_to_cpu(stats->rmac_vld_mcst_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_vld_mcst_frms); + delta -= le64_to_cpu(stats->rmac_pause_ctrl_frms); + delta -= sp->stats.multicast; + sp->stats.multicast += delta; + dev->stats.multicast += delta; - /* collect per-ring rx_packets and rx_bytes */ - dev->stats.rx_packets = dev->stats.rx_bytes = 0; - for (i = 0; i < config->rx_ring_num; i++) { - struct ring_info *ring = &mac_control->rings[i]; + delta = ((u64) le32_to_cpu(stats->rmac_usized_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_usized_frms)) + + le64_to_cpu(stats->rmac_long_frms) - sp->stats.rx_length_errors; + sp->stats.rx_length_errors += delta; + dev->stats.rx_length_errors += delta; - dev->stats.rx_packets += ring->rx_packets; - dev->stats.rx_bytes += ring->rx_bytes; - } + delta = le64_to_cpu(stats->rmac_fcs_err_frms) - sp->stats.rx_crc_errors; + sp->stats.rx_crc_errors += delta; + dev->stats.rx_crc_errors += delta; return &dev->stats; } @@ -7455,15 +7487,11 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) } } - /* Updating statistics */ - ring_data->rx_packets++; rxdp->Host_Control = 0; if (sp->rxd_mode == RXD_MODE_1) { int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2); - ring_data->rx_bytes += len; skb_put(skb, len); - } else if (sp->rxd_mode == RXD_MODE_3B) { int get_block = ring_data->rx_curr_get_info.block_index; int get_off = ring_data->rx_curr_get_info.offset; @@ -7472,7 +7500,6 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) unsigned char *buff = skb_push(skb, buf0_len); struct buffAdd *ba = &ring_data->ba[get_block][get_off]; - ring_data->rx_bytes += buf0_len + buf2_len; memcpy(buff, ba->ba_0, buf0_len); skb_put(skb, buf2_len); } diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 47c36e0994f..7f3a53dcc6e 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -65,7 +65,7 @@ static int debug_level = ERR_DBG; /* DEBUG message print. */ #define DBG_PRINT(dbg_level, fmt, args...) do { \ - if (dbg_level >= debug_level) \ + if (dbg_level <= debug_level) \ pr_info(fmt, ##args); \ } while (0) @@ -745,10 +745,6 @@ struct ring_info { /* Buffer Address store. */ struct buffAdd **ba; - - /* per-Ring statistics */ - unsigned long rx_packets; - unsigned long rx_bytes; } ____cacheline_aligned; /* Fifo specific structure */ diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 1f3acc3a5df..79eee306208 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2671,6 +2671,7 @@ static struct platform_driver sbmac_driver = { .remove = __exit_p(sbmac_remove), .driver = { .name = sbmac_string, + .owner = THIS_MODULE, }, }; diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 6ad6fe70631..63042596f0c 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -736,8 +736,18 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6; else if (sinfo->gso_type & SKB_GSO_UDP) gso.gso_type = VIRTIO_NET_HDR_GSO_UDP; - else - BUG(); + else { + printk(KERN_ERR "tun: unexpected GSO type: " + "0x%x, gso_size %d, hdr_len %d\n", + sinfo->gso_type, gso.gso_size, + gso.hdr_len); + print_hex_dump(KERN_ERR, "tun: ", + DUMP_PREFIX_NONE, + 16, 1, skb->head, + min((int)gso.hdr_len, 64), true); + WARN_ON_ONCE(1); + return -EINVAL; + } if (sinfo->gso_type & SKB_GSO_TCP_ECN) gso.gso_type |= VIRTIO_NET_HDR_GSO_ECN; } else diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index 28d3ee175e7..dd8a4adf48c 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -104,10 +104,8 @@ static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg, int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) { struct cdc_state *info = (void *) &dev->data; - struct usb_cdc_notification notification; int master_ifnum; int retval; - int partial; unsigned count; __le32 rsp; u32 xid = 0, msg_len, request_id; @@ -135,17 +133,13 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) if (unlikely(retval < 0 || xid == 0)) return retval; - /* Some devices don't respond on the control channel until - * polled on the status channel, so do that first. */ - retval = usb_interrupt_msg( - dev->udev, - usb_rcvintpipe(dev->udev, dev->status->desc.bEndpointAddress), - ¬ification, sizeof(notification), &partial, - RNDIS_CONTROL_TIMEOUT_MS); - if (unlikely(retval < 0)) - return retval; + // FIXME Seems like some devices discard responses when + // we time out and cancel our "get response" requests... + // so, this is fragile. Probably need to poll for status. - /* Poll the control channel; the request probably completed immediately */ + /* ignore status endpoint, just poll the control channel; + * the request probably completed immediately + */ rsp = buf->msg_type | RNDIS_MSG_COMPLETION; for (count = 0; count < 10; count++) { memset(buf, 0, CONTROL_BUFFER_SIZE); diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index a95c73de582..81c76ada8e5 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1293,6 +1293,9 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) goto out; } + /* netdev_printk() needs this so do it as early as possible */ + SET_NETDEV_DEV(net, &udev->dev); + dev = netdev_priv(net); dev->udev = xdev; dev->intf = udev; @@ -1377,8 +1380,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) dev->rx_urb_size = dev->hard_mtu; dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1); - SET_NETDEV_DEV(net, &udev->dev); - if ((dev->driver_info->flags & FLAG_WLAN) != 0) SET_NETDEV_DEVTYPE(net, &wlan_type); if ((dev->driver_info->flags & FLAG_WWAN) != 0) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 1edb7a61983..bb6b67f6b0c 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -415,7 +415,7 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, gfp_t gfp) static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp) { int err; - bool oom = false; + bool oom; do { if (vi->mergeable_rx_bufs) @@ -425,10 +425,9 @@ static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp) else err = add_recvbuf_small(vi, gfp); - if (err < 0) { - oom = true; + oom = err == -ENOMEM; + if (err < 0) break; - } ++vi->num; } while (err > 0); if (unlikely(vi->num > vi->max)) @@ -563,7 +562,6 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) struct virtnet_info *vi = netdev_priv(dev); int capacity; -again: /* Free up any pending old buffers before queueing new ones. */ free_old_xmit_skbs(vi); @@ -572,14 +570,20 @@ again: /* This can happen with OOM and indirect buffers. */ if (unlikely(capacity < 0)) { - netif_stop_queue(dev); - dev_warn(&dev->dev, "Unexpected full queue\n"); - if (unlikely(!virtqueue_enable_cb(vi->svq))) { - virtqueue_disable_cb(vi->svq); - netif_start_queue(dev); - goto again; + if (net_ratelimit()) { + if (likely(capacity == -ENOMEM)) { + dev_warn(&dev->dev, + "TX queue failure: out of memory\n"); + } else { + dev->stats.tx_fifo_errors++; + dev_warn(&dev->dev, + "Unexpected TX queue failure: %d\n", + capacity); + } } - return NETDEV_TX_BUSY; + dev->stats.tx_dropped++; + kfree_skb(skb); + return NETDEV_TX_OK; } virtqueue_kick(vi->svq); diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index d14e207de1d..fc8b2d7a091 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -4517,9 +4517,9 @@ vxge_starter(void) char version[32]; snprintf(version, 32, "%s", DRV_VERSION); - printk(KERN_CRIT "%s: Copyright(c) 2002-2009 Neterion Inc\n", + printk(KERN_INFO "%s: Copyright(c) 2002-2009 Neterion Inc\n", VXGE_DRIVER_NAME); - printk(KERN_CRIT "%s: Driver version: %s\n", + printk(KERN_INFO "%s: Driver version: %s\n", VXGE_DRIVER_NAME, version); verify_bandwidth(); diff --git a/drivers/net/wimax/i2400m/i2400m-usb.h b/drivers/net/wimax/i2400m/i2400m-usb.h index 2d7c96d7e86..eb80243e22d 100644 --- a/drivers/net/wimax/i2400m/i2400m-usb.h +++ b/drivers/net/wimax/i2400m/i2400m-usb.h @@ -152,6 +152,7 @@ enum { /* Device IDs */ USB_DEVICE_ID_I6050 = 0x0186, USB_DEVICE_ID_I6050_2 = 0x0188, + USB_DEVICE_ID_I6250 = 0x0187, }; diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index 0d5081d77dc..d3365ac85dd 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c @@ -491,6 +491,7 @@ int i2400mu_probe(struct usb_interface *iface, switch (id->idProduct) { case USB_DEVICE_ID_I6050: case USB_DEVICE_ID_I6050_2: + case USB_DEVICE_ID_I6250: i2400mu->i6050 = 1; break; default: @@ -739,6 +740,7 @@ static struct usb_device_id i2400mu_id_table[] = { { USB_DEVICE(0x8086, USB_DEVICE_ID_I6050) }, { USB_DEVICE(0x8086, USB_DEVICE_ID_I6050_2) }, + { USB_DEVICE(0x8086, USB_DEVICE_ID_I6250) }, { USB_DEVICE(0x8086, 0x0181) }, { USB_DEVICE(0x8086, 0x1403) }, { USB_DEVICE(0x8086, 0x1405) }, diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index fbb7dec6dde..5ea87736a6a 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -445,6 +445,7 @@ void ath_deinit_leds(struct ath_softc *sc); #define SC_OP_TSF_RESET BIT(11) #define SC_OP_BT_PRIORITY_DETECTED BIT(12) #define SC_OP_BT_SCAN BIT(13) +#define SC_OP_ANI_RUN BIT(14) /* Powersave flags */ #define PS_WAIT_FOR_BEACON BIT(0) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 77b359162d6..23c15aa9fbd 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -730,13 +730,17 @@ static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev) /* RX */ if (ath9k_hif_usb_alloc_rx_urbs(hif_dev) < 0) - goto err; + goto err_rx; /* Register Read */ if (ath9k_hif_usb_alloc_reg_in_urb(hif_dev) < 0) - goto err; + goto err_reg; return 0; +err_reg: + ath9k_hif_usb_dealloc_rx_urbs(hif_dev); +err_rx: + ath9k_hif_usb_dealloc_tx_urbs(hif_dev); err: return -ENOMEM; } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index abfa0493236..1e2a68ea935 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -336,6 +336,10 @@ set_timer: static void ath_start_ani(struct ath_common *common) { unsigned long timestamp = jiffies_to_msecs(jiffies); + struct ath_softc *sc = (struct ath_softc *) common->priv; + + if (!(sc->sc_flags & SC_OP_ANI_RUN)) + return; common->ani.longcal_timer = timestamp; common->ani.shortcal_timer = timestamp; @@ -872,11 +876,13 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, /* Reset rssi stats */ sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_flags |= SC_OP_ANI_RUN; ath_start_ani(common); } else { ath_print(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); common->curaid = 0; /* Stop ANI */ + sc->sc_flags &= ~SC_OP_ANI_RUN; del_timer_sync(&common->ani.timer); } } @@ -1478,8 +1484,10 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, if (vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_ADHOC || - vif->type == NL80211_IFTYPE_MONITOR) + vif->type == NL80211_IFTYPE_MONITOR) { + sc->sc_flags |= SC_OP_ANI_RUN; ath_start_ani(common); + } out: mutex_unlock(&sc->mutex); @@ -1500,6 +1508,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); /* Stop ANI */ + sc->sc_flags &= ~SC_OP_ANI_RUN; del_timer_sync(&common->ani.timer); /* Reclaim beacon resources */ diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index ca6065b71b4..e3e52913d83 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -844,9 +844,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) int dma_type; if (edma) - dma_type = DMA_FROM_DEVICE; - else dma_type = DMA_BIDIRECTIONAL; + else + dma_type = DMA_FROM_DEVICE; qtype = hp ? ATH9K_RX_QUEUE_HP : ATH9K_RX_QUEUE_LP; spin_lock_bh(&sc->rx.rxbuflock); diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c index d24dc7dc072..972a9c3af39 100644 --- a/drivers/net/wireless/hostap/hostap_pci.c +++ b/drivers/net/wireless/hostap/hostap_pci.c @@ -330,6 +330,7 @@ static int prism2_pci_probe(struct pci_dev *pdev, dev->irq = pdev->irq; hw_priv->mem_start = mem; + dev->base_addr = (unsigned long) mem; prism2_pci_cor_sreset(local); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c index 44ef5d93bef..01658cf82d3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c @@ -212,11 +212,7 @@ static void iwlagn_chain_noise_reset(struct iwl_priv *priv) static void iwlagn_rts_tx_cmd_flag(struct ieee80211_tx_info *info, __le32 *tx_flags) { - if ((info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || - (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) - *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK; - else - *tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK; + *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK; } /* Calc max signal level (dBm) among 3 possible receivers */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 426e95567de..5bbc5298ef9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1314,7 +1314,6 @@ void iwl_configure_filter(struct ieee80211_hw *hw, changed_flags, *total_flags); CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK); - CHK(FIF_ALLMULTI, RXON_FILTER_ACCEPT_GRP_MSK); CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK); CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK); @@ -1329,6 +1328,12 @@ void iwl_configure_filter(struct ieee80211_hw *hw, mutex_unlock(&priv->mutex); + /* + * Receiving all multicast frames is always enabled by the + * default flags setup in iwl_connection_init_rx_config() + * since we currently do not support programming multicast + * filters into the device. + */ *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; } diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index c2a453a1a99..dc43ebd1f1f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -97,6 +97,17 @@ static inline void iwl_clear_driver_stations(struct iwl_priv *priv) spin_lock_irqsave(&priv->sta_lock, flags); memset(priv->stations, 0, sizeof(priv->stations)); priv->num_stations = 0; + + /* + * Remove all key information that is not stored as part of station + * information since mac80211 may not have had a + * chance to remove all the keys. When device is reconfigured by + * mac80211 after an error all keys will be reconfigured. + */ + priv->ucode_key_table = 0; + priv->key_mapping_key = 0; + memset(priv->wep_keys, 0, sizeof(priv->wep_keys)); + spin_unlock_irqrestore(&priv->sta_lock, flags); } diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 3ae468c4d76..f20d3eeeea7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -854,6 +854,11 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) BIT(NL80211_IFTYPE_WDS); /* + * Initialize configuration work. + */ + INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); + + /* * Let the driver probe the device to detect the capabilities. */ retval = rt2x00dev->ops->lib->probe_hw(rt2x00dev); @@ -863,11 +868,6 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) } /* - * Initialize configuration work. - */ - INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); - - /* * Allocate queue array. */ retval = rt2x00queue_allocate(rt2x00dev); diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index 188bc8496a2..d02be78a413 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c @@ -176,16 +176,18 @@ static ssize_t led_proc_write(struct file *file, const char *buf, size_t count, loff_t *pos) { void *data = PDE(file->f_path.dentry->d_inode)->data; - char *cur, lbuf[count + 1]; + char *cur, lbuf[32]; int d; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - memset(lbuf, 0, count + 1); + if (count >= sizeof(lbuf)) + count = sizeof(lbuf)-1; if (copy_from_user(lbuf, buf, count)) return -EFAULT; + lbuf[count] = 0; cur = lbuf; diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 92379e2d37e..2aaa13150de 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -156,6 +156,38 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev, pcibios_align_resource, dev); } + if (ret < 0 && dev->fw_addr[resno]) { + struct resource *root, *conflict; + resource_size_t start, end; + + /* + * If we failed to assign anything, let's try the address + * where firmware left it. That at least has a chance of + * working, which is better than just leaving it disabled. + */ + + if (res->flags & IORESOURCE_IO) + root = &ioport_resource; + else + root = &iomem_resource; + + start = res->start; + end = res->end; + res->start = dev->fw_addr[resno]; + res->end = res->start + size - 1; + dev_info(&dev->dev, "BAR %d: trying firmware assignment %pR\n", + resno, res); + conflict = request_resource_conflict(root, res); + if (conflict) { + dev_info(&dev->dev, + "BAR %d: %pR conflicts with %s %pR\n", resno, + res, conflict->name, conflict); + res->start = start; + res->end = end; + } else + ret = 0; + } + if (!ret) { res->flags &= ~IORESOURCE_STARTALIGN; dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res); diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 9fc33984553..eac961463be 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1356,6 +1356,7 @@ static int __devinit pcmcia_bus_add_socket(struct device *dev, INIT_LIST_HEAD(&socket->devices_list); memset(&socket->pcmcia_state, 0, sizeof(u8)); socket->device_count = 0; + atomic_set(&socket->present, 0); ret = pccard_register_pcmcia(socket, &pcmcia_bus_callback); if (ret) { @@ -1364,8 +1365,6 @@ static int __devinit pcmcia_bus_add_socket(struct device *dev, return ret; } - atomic_set(&socket->present, 0); - return 0; } diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 29f91fac1df..a4cd9adfcbc 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -857,8 +857,10 @@ void pcmcia_disable_device(struct pcmcia_device *p_dev) { pcmcia_release_configuration(p_dev); pcmcia_release_io(p_dev, &p_dev->io); - if (p_dev->_irq) + if (p_dev->_irq) { free_irq(p_dev->irq, p_dev->priv); + p_dev->_irq = 0; + } if (p_dev->win) pcmcia_release_window(p_dev, p_dev->win); } diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index df4532e91b1..f370476d541 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -178,7 +178,6 @@ pxa2xx_pcmcia_frequency_change(struct soc_pcmcia_socket *skt, unsigned long val, struct cpufreq_freqs *freqs) { -#warning "it's not clear if this is right since the core CPU (N) clock has no effect on the memory (L) clock" switch (val) { case CPUFREQ_PRECHANGE: if (freqs->new > freqs->old) { @@ -186,7 +185,7 @@ pxa2xx_pcmcia_frequency_change(struct soc_pcmcia_socket *skt, "pre-updating\n", freqs->new / 1000, (freqs->new / 100) % 10, freqs->old / 1000, (freqs->old / 100) % 10); - pxa2xx_pcmcia_set_mcxx(skt, freqs->new); + pxa2xx_pcmcia_set_timing(skt); } break; @@ -196,7 +195,7 @@ pxa2xx_pcmcia_frequency_change(struct soc_pcmcia_socket *skt, "post-updating\n", freqs->new / 1000, (freqs->new / 100) % 10, freqs->old / 1000, (freqs->old / 100) % 10); - pxa2xx_pcmcia_set_mcxx(skt, freqs->new); + pxa2xx_pcmcia_set_timing(skt); } break; } diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 40658e3385b..bb2f1fba637 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -489,7 +489,7 @@ int intel_scu_ipc_simple_command(int cmd, int sub) mutex_unlock(&ipclock); return -ENODEV; } - ipc_command(cmd << 12 | sub); + ipc_command(sub << 12 | cmd); err = busy_loop(); mutex_unlock(&ipclock); return err; @@ -501,9 +501,9 @@ EXPORT_SYMBOL(intel_scu_ipc_simple_command); * @cmd: command * @sub: sub type * @in: input data - * @inlen: input length + * @inlen: input length in dwords * @out: output data - * @outlein: output length + * @outlein: output length in dwords * * Issue a command to the SCU which involves data transfers. Do the * data copies under the lock but leave it for the caller to interpret @@ -524,7 +524,7 @@ int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen, for (i = 0; i < inlen; i++) ipc_data_writel(*in++, 4 * i); - ipc_command((cmd << 12) | sub | (inlen << 18)); + ipc_command((sub << 12) | cmd | (inlen << 18)); err = busy_loop(); for (i = 0; i < outlen; i++) @@ -556,6 +556,10 @@ int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data) u32 cmd = 0; mutex_lock(&ipclock); + if (ipcdev.pdev == NULL) { + mutex_unlock(&ipclock); + return -ENODEV; + } cmd = (addr >> 24) & 0xFF; if (cmd == IPC_I2C_READ) { writel(addr, ipcdev.i2c_base + IPC_I2C_CNTRL_ADDR); diff --git a/drivers/power/ds2782_battery.c b/drivers/power/ds2782_battery.c index d762a0cbc6a..84d3c43cf2b 100644 --- a/drivers/power/ds2782_battery.c +++ b/drivers/power/ds2782_battery.c @@ -43,10 +43,9 @@ struct ds278x_info; struct ds278x_battery_ops { - int (*get_current)(struct ds278x_info *info, int *current_uA); - int (*get_voltage)(struct ds278x_info *info, int *voltage_uA); - int (*get_capacity)(struct ds278x_info *info, int *capacity_uA); - + int (*get_battery_current)(struct ds278x_info *info, int *current_uA); + int (*get_battery_voltage)(struct ds278x_info *info, int *voltage_uA); + int (*get_battery_capacity)(struct ds278x_info *info, int *capacity_uA); }; #define to_ds278x_info(x) container_of(x, struct ds278x_info, battery) @@ -163,7 +162,7 @@ static int ds2782_get_capacity(struct ds278x_info *info, int *capacity) if (err) return err; *capacity = raw; - return raw; + return 0; } static int ds2786_get_current(struct ds278x_info *info, int *current_uA) @@ -213,11 +212,11 @@ static int ds278x_get_status(struct ds278x_info *info, int *status) int current_uA; int capacity; - err = info->ops->get_current(info, ¤t_uA); + err = info->ops->get_battery_current(info, ¤t_uA); if (err) return err; - err = info->ops->get_capacity(info, &capacity); + err = info->ops->get_battery_capacity(info, &capacity); if (err) return err; @@ -246,15 +245,15 @@ static int ds278x_battery_get_property(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CAPACITY: - ret = info->ops->get_capacity(info, &val->intval); + ret = info->ops->get_battery_capacity(info, &val->intval); break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: - ret = info->ops->get_voltage(info, &val->intval); + ret = info->ops->get_battery_voltage(info, &val->intval); break; case POWER_SUPPLY_PROP_CURRENT_NOW: - ret = info->ops->get_current(info, &val->intval); + ret = info->ops->get_battery_current(info, &val->intval); break; case POWER_SUPPLY_PROP_TEMP: @@ -307,14 +306,14 @@ enum ds278x_num_id { static struct ds278x_battery_ops ds278x_ops[] = { [DS2782] = { - .get_current = ds2782_get_current, - .get_voltage = ds2782_get_voltage, - .get_capacity = ds2782_get_capacity, + .get_battery_current = ds2782_get_current, + .get_battery_voltage = ds2782_get_voltage, + .get_battery_capacity = ds2782_get_capacity, }, [DS2786] = { - .get_current = ds2786_get_current, - .get_voltage = ds2786_get_voltage, - .get_capacity = ds2786_get_capacity, + .get_battery_current = ds2786_get_current, + .get_battery_voltage = ds2786_get_voltage, + .get_battery_capacity = ds2786_get_capacity, } }; diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index 7b14a67bdca..11790990277 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c @@ -286,7 +286,7 @@ static int ab3100_list_voltage_regulator(struct regulator_dev *reg, { struct ab3100_regulator *abreg = reg->reg_data; - if (selector > abreg->voltages_len) + if (selector >= abreg->voltages_len) return -EINVAL; return abreg->typ_voltages[selector]; } @@ -318,7 +318,7 @@ static int ab3100_get_voltage_regulator(struct regulator_dev *reg) regval &= 0xE0; regval >>= 5; - if (regval > abreg->voltages_len) { + if (regval >= abreg->voltages_len) { dev_err(®->dev, "regulator register %02x contains an illegal voltage setting\n", abreg->regreg); diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c index 14b4576281c..8152d65220f 100644 --- a/drivers/regulator/tps6507x-regulator.c +++ b/drivers/regulator/tps6507x-regulator.c @@ -22,6 +22,7 @@ #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <linux/regulator/tps6507x.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/mfd/tps6507x.h> @@ -101,9 +102,12 @@ struct tps_info { unsigned max_uV; u8 table_len; const u16 *table; + + /* Does DCDC high or the low register defines output voltage? */ + bool defdcdc_default; }; -static const struct tps_info tps6507x_pmic_regs[] = { +static struct tps_info tps6507x_pmic_regs[] = { { .name = "VDCDC1", .min_uV = 725000, @@ -145,7 +149,7 @@ struct tps6507x_pmic { struct regulator_desc desc[TPS6507X_NUM_REGULATOR]; struct tps6507x_dev *mfd; struct regulator_dev *rdev[TPS6507X_NUM_REGULATOR]; - const struct tps_info *info[TPS6507X_NUM_REGULATOR]; + struct tps_info *info[TPS6507X_NUM_REGULATOR]; struct mutex io_lock; }; static inline int tps6507x_pmic_read(struct tps6507x_pmic *tps, u8 reg) @@ -341,10 +345,16 @@ static int tps6507x_pmic_dcdc_get_voltage(struct regulator_dev *dev) reg = TPS6507X_REG_DEFDCDC1; break; case TPS6507X_DCDC_2: - reg = TPS6507X_REG_DEFDCDC2_LOW; + if (tps->info[dcdc]->defdcdc_default) + reg = TPS6507X_REG_DEFDCDC2_HIGH; + else + reg = TPS6507X_REG_DEFDCDC2_LOW; break; case TPS6507X_DCDC_3: - reg = TPS6507X_REG_DEFDCDC3_LOW; + if (tps->info[dcdc]->defdcdc_default) + reg = TPS6507X_REG_DEFDCDC3_HIGH; + else + reg = TPS6507X_REG_DEFDCDC3_LOW; break; default: return -EINVAL; @@ -370,10 +380,16 @@ static int tps6507x_pmic_dcdc_set_voltage(struct regulator_dev *dev, reg = TPS6507X_REG_DEFDCDC1; break; case TPS6507X_DCDC_2: - reg = TPS6507X_REG_DEFDCDC2_LOW; + if (tps->info[dcdc]->defdcdc_default) + reg = TPS6507X_REG_DEFDCDC2_HIGH; + else + reg = TPS6507X_REG_DEFDCDC2_LOW; break; case TPS6507X_DCDC_3: - reg = TPS6507X_REG_DEFDCDC3_LOW; + if (tps->info[dcdc]->defdcdc_default) + reg = TPS6507X_REG_DEFDCDC3_HIGH; + else + reg = TPS6507X_REG_DEFDCDC3_LOW; break; default: return -EINVAL; @@ -532,7 +548,7 @@ int tps6507x_pmic_probe(struct platform_device *pdev) { struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent); static int desc_id; - const struct tps_info *info = &tps6507x_pmic_regs[0]; + struct tps_info *info = &tps6507x_pmic_regs[0]; struct regulator_init_data *init_data; struct regulator_dev *rdev; struct tps6507x_pmic *tps; @@ -569,6 +585,12 @@ int tps6507x_pmic_probe(struct platform_device *pdev) for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++, init_data++) { /* Register the regulators */ tps->info[i] = info; + if (init_data->driver_data) { + struct tps6507x_reg_platform_data *data = + init_data->driver_data; + tps->info[i]->defdcdc_default = data->defdcdc_default; + } + tps->desc[i].name = info->name; tps->desc[i].id = desc_id++; tps->desc[i].n_voltages = num_voltages[i]; diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 723cd1fb486..0e6ed7db936 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -1495,7 +1495,7 @@ int wm8350_register_regulator(struct wm8350 *wm8350, int reg, if (ret != 0) { dev_err(wm8350->dev, "Failed to register regulator %d: %d\n", reg, ret); - platform_device_del(pdev); + platform_device_put(pdev); wm8350->pmic.pdev[reg] = NULL; } diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 3587d9922f2..71bbefc3544 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -456,7 +456,7 @@ static struct rtc_class_ops stv2_pl031_ops = { .irq_set_freq = pl031_irq_set_freq, }; -static struct amba_id pl031_ids[] __initdata = { +static struct amba_id pl031_ids[] = { { .id = 0x00041031, .mask = 0x000fffff, diff --git a/drivers/rtc/rtc-rx8581.c b/drivers/rtc/rtc-rx8581.c index 9718aaaa821..600b890a3c1 100644 --- a/drivers/rtc/rtc-rx8581.c +++ b/drivers/rtc/rtc-rx8581.c @@ -168,7 +168,7 @@ static int rx8581_set_datetime(struct i2c_client *client, struct rtc_time *tm) return -EIO; } - err = i2c_smbus_write_byte_data(client, RX8581_REG_FLAG, + err = i2c_smbus_write_byte_data(client, RX8581_REG_CTRL, (data | RX8581_CTRL_STOP)); if (err < 0) { dev_err(&client->dev, "Unable to write control register\n"); @@ -182,6 +182,20 @@ static int rx8581_set_datetime(struct i2c_client *client, struct rtc_time *tm) return -EIO; } + /* get VLF and clear it */ + data = i2c_smbus_read_byte_data(client, RX8581_REG_FLAG); + if (data < 0) { + dev_err(&client->dev, "Unable to read flag register\n"); + return -EIO; + } + + err = i2c_smbus_write_byte_data(client, RX8581_REG_FLAG, + (data & ~(RX8581_FLAG_VLF))); + if (err != 0) { + dev_err(&client->dev, "Unable to write flag register\n"); + return -EIO; + } + /* Restart the clock */ data = i2c_smbus_read_byte_data(client, RX8581_REG_CTRL); if (data < 0) { @@ -189,8 +203,8 @@ static int rx8581_set_datetime(struct i2c_client *client, struct rtc_time *tm) return -EIO; } - err = i2c_smbus_write_byte_data(client, RX8581_REG_FLAG, - (data | ~(RX8581_CTRL_STOP))); + err = i2c_smbus_write_byte_data(client, RX8581_REG_CTRL, + (data & ~(RX8581_CTRL_STOP))); if (err != 0) { dev_err(&client->dev, "Unable to write control register\n"); return -EIO; diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 34d51dd4c53..bed7b4634cc 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -948,8 +948,10 @@ static ssize_t dasd_alias_show(struct device *dev, if (device->discipline && device->discipline->get_uid && !device->discipline->get_uid(device, &uid)) { if (uid.type == UA_BASE_PAV_ALIAS || - uid.type == UA_HYPER_PAV_ALIAS) + uid.type == UA_HYPER_PAV_ALIAS) { + dasd_put_device(device); return sprintf(buf, "1\n"); + } } dasd_put_device(device); diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index ce7cb87479f..407d0e9adfa 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -713,7 +713,7 @@ int chsc_determine_base_channel_path_desc(struct chp_id chpid, ret = chsc_determine_channel_path_desc(chpid, 0, 0, 0, 0, chsc_resp); if (ret) goto out_free; - memcpy(desc, &chsc_resp->data, chsc_resp->length); + memcpy(desc, &chsc_resp->data, sizeof(*desc)); out_free: kfree(chsc_resp); return ret; diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index e3dbeda9717..fd068bc1bd0 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -714,6 +714,14 @@ static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act) if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED) return ZFCP_ERP_FAILED; + if (mempool_resize(act->adapter->pool.status_read_data, + act->adapter->stat_read_buf_num, GFP_KERNEL)) + return ZFCP_ERP_FAILED; + + if (mempool_resize(act->adapter->pool.status_read_req, + act->adapter->stat_read_buf_num, GFP_KERNEL)) + return ZFCP_ERP_FAILED; + atomic_set(&act->adapter->stat_miss, act->adapter->stat_read_buf_num); if (zfcp_status_read_refill(act->adapter)) return ZFCP_ERP_FAILED; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 9ac6a6e4a60..71663fb7731 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -496,7 +496,8 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) adapter->hydra_version = bottom->adapter_type; adapter->timer_ticks = bottom->timer_interval; - adapter->stat_read_buf_num = max(bottom->status_read_buf_num, (u16)16); + adapter->stat_read_buf_num = max(bottom->status_read_buf_num, + (u16)FSF_STATUS_READS_RECOM); if (fc_host_permanent_port_name(shost) == -1) fc_host_permanent_port_name(shost) = fc_host_port_name(shost); @@ -719,11 +720,6 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio, zfcp_qdio_req_init(adapter->qdio, &req->qdio_req, req->req_id, sbtype, req->qtcb, sizeof(struct fsf_qtcb)); - if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) { - zfcp_fsf_req_free(req); - return ERR_PTR(-EIO); - } - return req; } @@ -981,7 +977,7 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, } /* use single, unchained SBAL if it can hold the request */ - if (zfcp_qdio_sg_one_sbale(sg_req) || zfcp_qdio_sg_one_sbale(sg_resp)) { + if (zfcp_qdio_sg_one_sbale(sg_req) && zfcp_qdio_sg_one_sbale(sg_resp)) { zfcp_fsf_setup_ct_els_unchained(adapter->qdio, &req->qdio_req, sg_req, sg_resp); return 0; diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 28117e130e2..6fa5e045317 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -251,7 +251,8 @@ static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio) struct zfcp_qdio_queue *req_q = &qdio->req_q; spin_lock_bh(&qdio->req_q_lock); - if (atomic_read(&req_q->count)) + if (atomic_read(&req_q->count) || + !(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) return 1; spin_unlock_bh(&qdio->req_q_lock); return 0; @@ -274,8 +275,13 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio) spin_unlock_bh(&qdio->req_q_lock); ret = wait_event_interruptible_timeout(qdio->req_q_wq, zfcp_qdio_sbal_check(qdio), 5 * HZ); + + if (!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) + return -EIO; + if (ret > 0) return 0; + if (!ret) { atomic_inc(&qdio->req_q_full); /* assume hanging outbound queue, try queue recovery */ @@ -375,6 +381,8 @@ void zfcp_qdio_close(struct zfcp_qdio *qdio) atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status); spin_unlock_bh(&qdio->req_q_lock); + wake_up(&qdio->req_q_wq); + qdio_shutdown(qdio->adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR); diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index d53e62ab09d..aacbe14e2e7 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -554,7 +554,7 @@ static int opiocgetnext(unsigned int cmd, void __user *argp) static int openprom_bsd_ioctl(struct file * file, unsigned int cmd, unsigned long arg) { - DATA *data = (DATA *) file->private_data; + DATA *data = file->private_data; void __user *argp = (void __user *)arg; int err; @@ -601,7 +601,7 @@ static int openprom_bsd_ioctl(struct file * file, static long openprom_ioctl(struct file * file, unsigned int cmd, unsigned long arg) { - DATA *data = (DATA *) file->private_data; + DATA *data = file->private_data; switch (cmd) { case OPROMGETOPT: diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c index a864ccc0a34..989b9a8ba72 100644 --- a/drivers/scsi/ibmvscsi/rpa_vscsi.c +++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c @@ -277,6 +277,12 @@ static int rpavscsi_init_crq_queue(struct crq_queue *queue, goto reg_crq_failed; } + queue->cur = 0; + spin_lock_init(&queue->lock); + + tasklet_init(&hostdata->srp_task, (void *)rpavscsi_task, + (unsigned long)hostdata); + if (request_irq(vdev->irq, rpavscsi_handle_event, 0, "ibmvscsi", (void *)hostdata) != 0) { @@ -291,15 +297,10 @@ static int rpavscsi_init_crq_queue(struct crq_queue *queue, goto req_irq_failed; } - queue->cur = 0; - spin_lock_init(&queue->lock); - - tasklet_init(&hostdata->srp_task, (void *)rpavscsi_task, - (unsigned long)hostdata); - return retrc; req_irq_failed: + tasklet_kill(&hostdata->srp_task); do { rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 82ea4a8226b..f820cffb7f0 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -1129,20 +1129,22 @@ static int ipr_is_same_device(struct ipr_resource_entry *res, } /** - * ipr_format_resource_path - Format the resource path for printing. + * ipr_format_res_path - Format the resource path for printing. * @res_path: resource path * @buf: buffer * * Return value: * pointer to buffer **/ -static char *ipr_format_resource_path(u8 *res_path, char *buffer) +static char *ipr_format_res_path(u8 *res_path, char *buffer, int len) { int i; + char *p = buffer; - sprintf(buffer, "%02X", res_path[0]); - for (i=1; res_path[i] != 0xff; i++) - sprintf(buffer, "%s-%02X", buffer, res_path[i]); + res_path[0] = '\0'; + p += snprintf(p, buffer + len - p, "%02X", res_path[0]); + for (i = 1; res_path[i] != 0xff && ((i * 3) < len); i++) + p += snprintf(p, buffer + len - p, "-%02X", res_path[i]); return buffer; } @@ -1187,7 +1189,8 @@ static void ipr_update_res_entry(struct ipr_resource_entry *res, if (res->sdev && new_path) sdev_printk(KERN_INFO, res->sdev, "Resource path: %s\n", - ipr_format_resource_path(&res->res_path[0], &buffer[0])); + ipr_format_res_path(res->res_path, buffer, + sizeof(buffer))); } else { res->flags = cfgtew->u.cfgte->flags; if (res->flags & IPR_IS_IOA_RESOURCE) @@ -1573,7 +1576,8 @@ static void ipr_log_sis64_config_error(struct ipr_ioa_cfg *ioa_cfg, ipr_err_separator; ipr_err("Device %d : %s", i + 1, - ipr_format_resource_path(&dev_entry->res_path[0], &buffer[0])); + ipr_format_res_path(dev_entry->res_path, buffer, + sizeof(buffer))); ipr_log_ext_vpd(&dev_entry->vpd); ipr_err("-----New Device Information-----\n"); @@ -1919,13 +1923,14 @@ static void ipr_log64_fabric_path(struct ipr_hostrcb *hostrcb, ipr_hcam_err(hostrcb, "%s %s: Resource Path=%s\n", path_active_desc[i].desc, path_state_desc[j].desc, - ipr_format_resource_path(&fabric->res_path[0], &buffer[0])); + ipr_format_res_path(fabric->res_path, buffer, + sizeof(buffer))); return; } } ipr_err("Path state=%02X Resource Path=%s\n", path_state, - ipr_format_resource_path(&fabric->res_path[0], &buffer[0])); + ipr_format_res_path(fabric->res_path, buffer, sizeof(buffer))); } static const struct { @@ -2066,7 +2071,8 @@ static void ipr_log64_path_elem(struct ipr_hostrcb *hostrcb, ipr_hcam_err(hostrcb, "%s %s: Resource Path=%s, Link rate=%s, WWN=%08X%08X\n", path_status_desc[j].desc, path_type_desc[i].desc, - ipr_format_resource_path(&cfg->res_path[0], &buffer[0]), + ipr_format_res_path(cfg->res_path, buffer, + sizeof(buffer)), link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); return; @@ -2074,7 +2080,7 @@ static void ipr_log64_path_elem(struct ipr_hostrcb *hostrcb, } ipr_hcam_err(hostrcb, "Path element=%02X: Resource Path=%s, Link rate=%s " "WWN=%08X%08X\n", cfg->type_status, - ipr_format_resource_path(&cfg->res_path[0], &buffer[0]), + ipr_format_res_path(cfg->res_path, buffer, sizeof(buffer)), link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); } @@ -2139,7 +2145,7 @@ static void ipr_log_sis64_array_error(struct ipr_ioa_cfg *ioa_cfg, ipr_err("RAID %s Array Configuration: %s\n", error->protection_level, - ipr_format_resource_path(&error->last_res_path[0], &buffer[0])); + ipr_format_res_path(error->last_res_path, buffer, sizeof(buffer))); ipr_err_separator; @@ -2160,9 +2166,11 @@ static void ipr_log_sis64_array_error(struct ipr_ioa_cfg *ioa_cfg, ipr_err("Array Member %d:\n", i); ipr_log_ext_vpd(&array_entry->vpd); ipr_err("Current Location: %s", - ipr_format_resource_path(&array_entry->res_path[0], &buffer[0])); + ipr_format_res_path(array_entry->res_path, buffer, + sizeof(buffer))); ipr_err("Expected Location: %s", - ipr_format_resource_path(&array_entry->expected_res_path[0], &buffer[0])); + ipr_format_res_path(array_entry->expected_res_path, + buffer, sizeof(buffer))); ipr_err_separator; } @@ -4079,7 +4087,8 @@ static struct device_attribute ipr_adapter_handle_attr = { }; /** - * ipr_show_resource_path - Show the resource path for this device. + * ipr_show_resource_path - Show the resource path or the resource address for + * this device. * @dev: device struct * @buf: buffer * @@ -4097,9 +4106,14 @@ static ssize_t ipr_show_resource_path(struct device *dev, struct device_attribut spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); res = (struct ipr_resource_entry *)sdev->hostdata; - if (res) + if (res && ioa_cfg->sis64) len = snprintf(buf, PAGE_SIZE, "%s\n", - ipr_format_resource_path(&res->res_path[0], &buffer[0])); + ipr_format_res_path(res->res_path, buffer, + sizeof(buffer))); + else if (res) + len = snprintf(buf, PAGE_SIZE, "%d:%d:%d:%d\n", ioa_cfg->host->host_no, + res->bus, res->target, res->lun); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); return len; } @@ -4351,7 +4365,8 @@ static int ipr_slave_configure(struct scsi_device *sdev) scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); if (ioa_cfg->sis64) sdev_printk(KERN_INFO, sdev, "Resource path: %s\n", - ipr_format_resource_path(&res->res_path[0], &buffer[0])); + ipr_format_res_path(res->res_path, buffer, + sizeof(buffer))); return 0; } spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 9ecd2259eb3..b965f3587c9 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -1684,8 +1684,9 @@ struct ipr_ucode_image_header { if (ipr_is_device(hostrcb)) { \ if ((hostrcb)->ioa_cfg->sis64) { \ printk(KERN_ERR IPR_NAME ": %s: " fmt, \ - ipr_format_resource_path(&hostrcb->hcam.u.error64.fd_res_path[0], \ - &hostrcb->rp_buffer[0]), \ + ipr_format_res_path(hostrcb->hcam.u.error64.fd_res_path, \ + hostrcb->rp_buffer, \ + sizeof(hostrcb->rp_buffer)), \ __VA_ARGS__); \ } else { \ ipr_ra_err((hostrcb)->ioa_cfg, \ diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index b09a638d051..50441ffe8e3 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c @@ -782,7 +782,7 @@ static int pl010_resume(struct amba_device *dev) return 0; } -static struct amba_id pl010_ids[] __initdata = { +static struct amba_id pl010_ids[] = { { .id = 0x00041010, .mask = 0x000fffff, diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index eb4cb480b93..6ca7a44f29c 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -69,9 +69,12 @@ struct uart_amba_port { struct uart_port port; struct clk *clk; - unsigned int im; /* interrupt mask */ + unsigned int im; /* interrupt mask */ unsigned int old_status; - unsigned int ifls; /* vendor-specific */ + unsigned int ifls; /* vendor-specific */ + unsigned int lcrh_tx; /* vendor-specific */ + unsigned int lcrh_rx; /* vendor-specific */ + bool oversampling; /* vendor-specific */ bool autorts; }; @@ -79,16 +82,25 @@ struct uart_amba_port { struct vendor_data { unsigned int ifls; unsigned int fifosize; + unsigned int lcrh_tx; + unsigned int lcrh_rx; + bool oversampling; }; static struct vendor_data vendor_arm = { .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, .fifosize = 16, + .lcrh_tx = UART011_LCRH, + .lcrh_rx = UART011_LCRH, + .oversampling = false, }; static struct vendor_data vendor_st = { .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, .fifosize = 64, + .lcrh_tx = ST_UART011_LCRH_TX, + .lcrh_rx = ST_UART011_LCRH_RX, + .oversampling = true, }; static void pl011_stop_tx(struct uart_port *port) @@ -327,12 +339,12 @@ static void pl011_break_ctl(struct uart_port *port, int break_state) unsigned int lcr_h; spin_lock_irqsave(&uap->port.lock, flags); - lcr_h = readw(uap->port.membase + UART011_LCRH); + lcr_h = readw(uap->port.membase + uap->lcrh_tx); if (break_state == -1) lcr_h |= UART01x_LCRH_BRK; else lcr_h &= ~UART01x_LCRH_BRK; - writew(lcr_h, uap->port.membase + UART011_LCRH); + writew(lcr_h, uap->port.membase + uap->lcrh_tx); spin_unlock_irqrestore(&uap->port.lock, flags); } @@ -393,7 +405,17 @@ static int pl011_startup(struct uart_port *port) writew(cr, uap->port.membase + UART011_CR); writew(0, uap->port.membase + UART011_FBRD); writew(1, uap->port.membase + UART011_IBRD); - writew(0, uap->port.membase + UART011_LCRH); + writew(0, uap->port.membase + uap->lcrh_rx); + if (uap->lcrh_tx != uap->lcrh_rx) { + int i; + /* + * Wait 10 PCLKs before writing LCRH_TX register, + * to get this delay write read only register 10 times + */ + for (i = 0; i < 10; ++i) + writew(0xff, uap->port.membase + UART011_MIS); + writew(0, uap->port.membase + uap->lcrh_tx); + } writew(0, uap->port.membase + UART01x_DR); while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) barrier(); @@ -422,10 +444,19 @@ static int pl011_startup(struct uart_port *port) return retval; } +static void pl011_shutdown_channel(struct uart_amba_port *uap, + unsigned int lcrh) +{ + unsigned long val; + + val = readw(uap->port.membase + lcrh); + val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN); + writew(val, uap->port.membase + lcrh); +} + static void pl011_shutdown(struct uart_port *port) { struct uart_amba_port *uap = (struct uart_amba_port *)port; - unsigned long val; /* * disable all interrupts @@ -450,9 +481,9 @@ static void pl011_shutdown(struct uart_port *port) /* * disable break condition and fifos */ - val = readw(uap->port.membase + UART011_LCRH); - val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN); - writew(val, uap->port.membase + UART011_LCRH); + pl011_shutdown_channel(uap, uap->lcrh_rx); + if (uap->lcrh_rx != uap->lcrh_tx) + pl011_shutdown_channel(uap, uap->lcrh_tx); /* * Shut down the clock producer @@ -472,8 +503,13 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, /* * Ask the core to calculate the divisor for us. */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); - quot = port->uartclk * 4 / baud; + baud = uart_get_baud_rate(port, termios, old, 0, + port->uartclk/(uap->oversampling ? 8 : 16)); + + if (baud > port->uartclk/16) + quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud); + else + quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud); switch (termios->c_cflag & CSIZE) { case CS5: @@ -552,6 +588,13 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, uap->autorts = false; } + if (uap->oversampling) { + if (baud > port->uartclk/16) + old_cr |= ST_UART011_CR_OVSFACT; + else + old_cr &= ~ST_UART011_CR_OVSFACT; + } + /* Set baud rate */ writew(quot & 0x3f, port->membase + UART011_FBRD); writew(quot >> 6, port->membase + UART011_IBRD); @@ -561,7 +604,17 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L * ----------^----------^----------^----------^----- */ - writew(lcr_h, port->membase + UART011_LCRH); + writew(lcr_h, port->membase + uap->lcrh_rx); + if (uap->lcrh_rx != uap->lcrh_tx) { + int i; + /* + * Wait 10 PCLKs before writing LCRH_TX register, + * to get this delay write read only register 10 times + */ + for (i = 0; i < 10; ++i) + writew(0xff, uap->port.membase + UART011_MIS); + writew(lcr_h, port->membase + uap->lcrh_tx); + } writew(old_cr, port->membase + UART011_CR); spin_unlock_irqrestore(&port->lock, flags); @@ -688,7 +741,7 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud, if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) { unsigned int lcr_h, ibrd, fbrd; - lcr_h = readw(uap->port.membase + UART011_LCRH); + lcr_h = readw(uap->port.membase + uap->lcrh_tx); *parity = 'n'; if (lcr_h & UART01x_LCRH_PEN) { @@ -707,6 +760,12 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud, fbrd = readw(uap->port.membase + UART011_FBRD); *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd); + + if (uap->oversampling) { + if (readw(uap->port.membase + UART011_CR) + & ST_UART011_CR_OVSFACT) + *baud *= 2; + } } } @@ -800,6 +859,9 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id) } uap->ifls = vendor->ifls; + uap->lcrh_rx = vendor->lcrh_rx; + uap->lcrh_tx = vendor->lcrh_tx; + uap->oversampling = vendor->oversampling; uap->port.dev = &dev->dev; uap->port.mapbase = dev->res.start; uap->port.membase = base; @@ -868,7 +930,7 @@ static int pl011_resume(struct amba_device *dev) } #endif -static struct amba_id pl011_ids[] __initdata = { +static struct amba_id pl011_ids[] = { { .id = 0x00041011, .mask = 0x000fffff, diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index eed3c2d8dd1..a182def7007 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -41,6 +41,7 @@ #include <linux/uaccess.h> #include <asm/io.h> +#include <asm/ioctls.h> #include <asm/mach/serial_at91.h> #include <mach/board.h> diff --git a/drivers/serial/suncore.c b/drivers/serial/suncore.c index ed7d958b0a0..544f2e25d0e 100644 --- a/drivers/serial/suncore.c +++ b/drivers/serial/suncore.c @@ -71,7 +71,9 @@ int sunserial_console_match(struct console *con, struct device_node *dp, con->index = line; drv->cons = con; - add_preferred_console(con->name, line, NULL); + + if (!console_set_on_cmdline) + add_preferred_console(con->name, line, NULL); return 1; } diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 234459c2f01..ffbf4553f66 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1500,20 +1500,25 @@ out_unmap: static int __devexit su_remove(struct of_device *op) { struct uart_sunsu_port *up = dev_get_drvdata(&op->dev); + bool kbdms = false; if (up->su_type == SU_PORT_MS || - up->su_type == SU_PORT_KBD) { + up->su_type == SU_PORT_KBD) + kbdms = true; + + if (kbdms) { #ifdef CONFIG_SERIO serio_unregister_port(&up->serio); #endif - kfree(up); - } else if (up->port.type != PORT_UNKNOWN) { + } else if (up->port.type != PORT_UNKNOWN) uart_remove_one_port(&sunsu_reg, &up->port); - } if (up->port.membase) of_iounmap(&op->resource[0], up->port.membase, up->reg_size); + if (kbdms) + kfree(up); + dev_set_drvdata(&op->dev, NULL); return 0; diff --git a/drivers/spi/spi_mpc8xxx.c b/drivers/spi/spi_mpc8xxx.c index ffa111a7e9d..97ab0a81338 100644 --- a/drivers/spi/spi_mpc8xxx.c +++ b/drivers/spi/spi_mpc8xxx.c @@ -66,28 +66,6 @@ struct mpc8xxx_spi_reg { __be32 receive; }; -/* SPI Parameter RAM */ -struct spi_pram { - __be16 rbase; /* Rx Buffer descriptor base address */ - __be16 tbase; /* Tx Buffer descriptor base address */ - u8 rfcr; /* Rx function code */ - u8 tfcr; /* Tx function code */ - __be16 mrblr; /* Max receive buffer length */ - __be32 rstate; /* Internal */ - __be32 rdp; /* Internal */ - __be16 rbptr; /* Internal */ - __be16 rbc; /* Internal */ - __be32 rxtmp; /* Internal */ - __be32 tstate; /* Internal */ - __be32 tdp; /* Internal */ - __be16 tbptr; /* Internal */ - __be16 tbc; /* Internal */ - __be32 txtmp; /* Internal */ - __be32 res; /* Tx temp. */ - __be16 rpbase; /* Relocation pointer (CPM1 only) */ - __be16 res1; /* Reserved */ -}; - /* SPI Controller mode register definitions */ #define SPMODE_LOOP (1 << 30) #define SPMODE_CI_INACTIVEHIGH (1 << 29) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 61d75507d5d..162c95a088e 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1596,6 +1596,7 @@ static const struct usb_device_id acm_ids[] = { { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */ { NOKIA_PCSUITE_ACM_INFO(0x0108), }, /* Nokia 5320 XpressMusic 2G */ { NOKIA_PCSUITE_ACM_INFO(0x01f5), }, /* Nokia N97, RM-505 */ + { NOKIA_PCSUITE_ACM_INFO(0x02e3), }, /* Nokia 5230, RM-588 */ /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 83e7bbbe97f..70cccc75a36 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1982,6 +1982,8 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, (portstatus & USB_PORT_STAT_ENABLE)) { if (hub_is_wusb(hub)) udev->speed = USB_SPEED_WIRELESS; + else if (portstatus & USB_PORT_STAT_SUPER_SPEED) + udev->speed = USB_SPEED_SUPER; else if (portstatus & USB_PORT_STAT_HIGH_SPEED) udev->speed = USB_SPEED_HIGH; else if (portstatus & USB_PORT_STAT_LOW_SPEED) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index f22d03df8b1..db99c084df9 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -41,6 +41,10 @@ static const struct usb_device_id usb_quirk_list[] = { /* Philips PSC805 audio device */ { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Artisman Watchdog Dongle */ + { USB_DEVICE(0x04b4, 0x0526), .driver_info = + USB_QUIRK_CONFIG_INTF_STRINGS }, + /* Roland SC-8820 */ { USB_DEVICE(0x0582, 0x0007), .driver_info = USB_QUIRK_RESET_RESUME }, @@ -64,6 +68,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* X-Rite/Gretag-Macbeth Eye-One Pro display colorimeter */ { USB_DEVICE(0x0971, 0x2000), .driver_info = USB_QUIRK_NO_SET_INTF }, + /* Broadcom BCM92035DGROM BT dongle */ + { USB_DEVICE(0x0a5c, 0x2021), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Action Semiconductor flash disk */ { USB_DEVICE(0x10d6, 0x2200), .driver_info = USB_QUIRK_STRING_FETCH_255 }, diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index eaa79c8a9b8..93ead19507b 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -76,11 +76,12 @@ static const char driver_name [] = "at91_udc"; static const char ep0name[] = "ep0"; +#define VBUS_POLL_TIMEOUT msecs_to_jiffies(1000) -#define at91_udp_read(dev, reg) \ - __raw_readl((dev)->udp_baseaddr + (reg)) -#define at91_udp_write(dev, reg, val) \ - __raw_writel((val), (dev)->udp_baseaddr + (reg)) +#define at91_udp_read(udc, reg) \ + __raw_readl((udc)->udp_baseaddr + (reg)) +#define at91_udp_write(udc, reg, val) \ + __raw_writel((val), (udc)->udp_baseaddr + (reg)) /*-------------------------------------------------------------------------*/ @@ -102,8 +103,9 @@ static void proc_ep_show(struct seq_file *s, struct at91_ep *ep) u32 csr; struct at91_request *req; unsigned long flags; + struct at91_udc *udc = ep->udc; - local_irq_save(flags); + spin_lock_irqsave(&udc->lock, flags); csr = __raw_readl(ep->creg); @@ -147,7 +149,7 @@ static void proc_ep_show(struct seq_file *s, struct at91_ep *ep) &req->req, length, req->req.length, req->req.buf); } - local_irq_restore(flags); + spin_unlock_irqrestore(&udc->lock, flags); } static void proc_irq_show(struct seq_file *s, const char *label, u32 mask) @@ -272,7 +274,9 @@ static void done(struct at91_ep *ep, struct at91_request *req, int status) VDBG("%s done %p, status %d\n", ep->ep.name, req, status); ep->stopped = 1; + spin_unlock(&udc->lock); req->req.complete(&ep->ep, &req->req); + spin_lock(&udc->lock); ep->stopped = stopped; /* ep0 is always ready; other endpoints need a non-empty queue */ @@ -472,7 +476,7 @@ static int at91_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) { struct at91_ep *ep = container_of(_ep, struct at91_ep, ep); - struct at91_udc *dev = ep->udc; + struct at91_udc *udc = ep->udc; u16 maxpacket; u32 tmp; unsigned long flags; @@ -487,7 +491,7 @@ static int at91_ep_enable(struct usb_ep *_ep, return -EINVAL; } - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { + if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) { DBG("bogus device state\n"); return -ESHUTDOWN; } @@ -521,7 +525,7 @@ bogus_max: } ok: - local_irq_save(flags); + spin_lock_irqsave(&udc->lock, flags); /* initialize endpoint to match this descriptor */ ep->is_in = usb_endpoint_dir_in(desc); @@ -540,10 +544,10 @@ ok: * reset/init endpoint fifo. NOTE: leaves fifo_bank alone, * since endpoint resets don't reset hw pingpong state. */ - at91_udp_write(dev, AT91_UDP_RST_EP, ep->int_mask); - at91_udp_write(dev, AT91_UDP_RST_EP, 0); + at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask); + at91_udp_write(udc, AT91_UDP_RST_EP, 0); - local_irq_restore(flags); + spin_unlock_irqrestore(&udc->lock, flags); return 0; } @@ -556,7 +560,7 @@ static int at91_ep_disable (struct usb_ep * _ep) if (ep == &ep->udc->ep[0]) return -EINVAL; - local_irq_save(flags); + spin_lock_irqsave(&udc->lock, flags); nuke(ep, -ESHUTDOWN); @@ -571,7 +575,7 @@ static int at91_ep_disable (struct usb_ep * _ep) __raw_writel(0, ep->creg); } - local_irq_restore(flags); + spin_unlock_irqrestore(&udc->lock, flags); return 0; } @@ -607,7 +611,7 @@ static int at91_ep_queue(struct usb_ep *_ep, { struct at91_request *req; struct at91_ep *ep; - struct at91_udc *dev; + struct at91_udc *udc; int status; unsigned long flags; @@ -625,9 +629,9 @@ static int at91_ep_queue(struct usb_ep *_ep, return -EINVAL; } - dev = ep->udc; + udc = ep->udc; - if (!dev || !dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { + if (!udc || !udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) { DBG("invalid device\n"); return -EINVAL; } @@ -635,7 +639,7 @@ static int at91_ep_queue(struct usb_ep *_ep, _req->status = -EINPROGRESS; _req->actual = 0; - local_irq_save(flags); + spin_lock_irqsave(&udc->lock, flags); /* try to kickstart any empty and idle queue */ if (list_empty(&ep->queue) && !ep->stopped) { @@ -653,7 +657,7 @@ static int at91_ep_queue(struct usb_ep *_ep, if (is_ep0) { u32 tmp; - if (!dev->req_pending) { + if (!udc->req_pending) { status = -EINVAL; goto done; } @@ -662,11 +666,11 @@ static int at91_ep_queue(struct usb_ep *_ep, * defer changing CONFG until after the gadget driver * reconfigures the endpoints. */ - if (dev->wait_for_config_ack) { - tmp = at91_udp_read(dev, AT91_UDP_GLB_STAT); + if (udc->wait_for_config_ack) { + tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT); tmp ^= AT91_UDP_CONFG; VDBG("toggle config\n"); - at91_udp_write(dev, AT91_UDP_GLB_STAT, tmp); + at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp); } if (req->req.length == 0) { ep0_in_status: @@ -676,7 +680,7 @@ ep0_in_status: tmp &= ~SET_FX; tmp |= CLR_FX | AT91_UDP_TXPKTRDY; __raw_writel(tmp, ep->creg); - dev->req_pending = 0; + udc->req_pending = 0; goto done; } } @@ -695,31 +699,40 @@ ep0_in_status: if (req && !status) { list_add_tail (&req->queue, &ep->queue); - at91_udp_write(dev, AT91_UDP_IER, ep->int_mask); + at91_udp_write(udc, AT91_UDP_IER, ep->int_mask); } done: - local_irq_restore(flags); + spin_unlock_irqrestore(&udc->lock, flags); return (status < 0) ? status : 0; } static int at91_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) { - struct at91_ep *ep; + struct at91_ep *ep; struct at91_request *req; + unsigned long flags; + struct at91_udc *udc; ep = container_of(_ep, struct at91_ep, ep); if (!_ep || ep->ep.name == ep0name) return -EINVAL; + udc = ep->udc; + + spin_lock_irqsave(&udc->lock, flags); + /* make sure it's actually queued on this endpoint */ list_for_each_entry (req, &ep->queue, queue) { if (&req->req == _req) break; } - if (&req->req != _req) + if (&req->req != _req) { + spin_unlock_irqrestore(&udc->lock, flags); return -EINVAL; + } done(ep, req, -ECONNRESET); + spin_unlock_irqrestore(&udc->lock, flags); return 0; } @@ -736,7 +749,7 @@ static int at91_ep_set_halt(struct usb_ep *_ep, int value) return -EINVAL; creg = ep->creg; - local_irq_save(flags); + spin_lock_irqsave(&udc->lock, flags); csr = __raw_readl(creg); @@ -761,7 +774,7 @@ static int at91_ep_set_halt(struct usb_ep *_ep, int value) __raw_writel(csr, creg); } - local_irq_restore(flags); + spin_unlock_irqrestore(&udc->lock, flags); return status; } @@ -795,7 +808,7 @@ static int at91_wakeup(struct usb_gadget *gadget) unsigned long flags; DBG("%s\n", __func__ ); - local_irq_save(flags); + spin_lock_irqsave(&udc->lock, flags); if (!udc->clocked || !udc->suspended) goto done; @@ -809,7 +822,7 @@ static int at91_wakeup(struct usb_gadget *gadget) at91_udp_write(udc, AT91_UDP_GLB_STAT, glbstate); done: - local_irq_restore(flags); + spin_unlock_irqrestore(&udc->lock, flags); return status; } @@ -851,8 +864,11 @@ static void stop_activity(struct at91_udc *udc) ep->stopped = 1; nuke(ep, -ESHUTDOWN); } - if (driver) + if (driver) { + spin_unlock(&udc->lock); driver->disconnect(&udc->gadget); + spin_lock(&udc->lock); + } udc_reinit(udc); } @@ -935,13 +951,13 @@ static int at91_vbus_session(struct usb_gadget *gadget, int is_active) unsigned long flags; // VDBG("vbus %s\n", is_active ? "on" : "off"); - local_irq_save(flags); + spin_lock_irqsave(&udc->lock, flags); udc->vbus = (is_active != 0); if (udc->driver) pullup(udc, is_active); else pullup(udc, 0); - local_irq_restore(flags); + spin_unlock_irqrestore(&udc->lock, flags); return 0; } @@ -950,10 +966,10 @@ static int at91_pullup(struct usb_gadget *gadget, int is_on) struct at91_udc *udc = to_udc(gadget); unsigned long flags; - local_irq_save(flags); + spin_lock_irqsave(&udc->lock, flags); udc->enabled = is_on = !!is_on; pullup(udc, is_on); - local_irq_restore(flags); + spin_unlock_irqrestore(&udc->lock, flags); return 0; } @@ -962,9 +978,9 @@ static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on) struct at91_udc *udc = to_udc(gadget); unsigned long flags; - local_irq_save(flags); + spin_lock_irqsave(&udc->lock, flags); udc->selfpowered = (is_on != 0); - local_irq_restore(flags); + spin_unlock_irqrestore(&udc->lock, flags); return 0; } @@ -1226,8 +1242,11 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) #undef w_length /* pass request up to the gadget driver */ - if (udc->driver) + if (udc->driver) { + spin_unlock(&udc->lock); status = udc->driver->setup(&udc->gadget, &pkt.r); + spin_lock(&udc->lock); + } else status = -ENODEV; if (status < 0) { @@ -1378,6 +1397,9 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) struct at91_udc *udc = _udc; u32 rescans = 5; int disable_clock = 0; + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); if (!udc->clocked) { clk_on(udc); @@ -1433,8 +1455,11 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) * and then into standby to avoid drawing more than * 500uA power (2500uA for some high-power configs). */ - if (udc->driver && udc->driver->suspend) + if (udc->driver && udc->driver->suspend) { + spin_unlock(&udc->lock); udc->driver->suspend(&udc->gadget); + spin_lock(&udc->lock); + } /* host initiated resume */ } else if (status & AT91_UDP_RXRSM) { @@ -1451,8 +1476,11 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) * would normally want to switch out of slow clock * mode into normal mode. */ - if (udc->driver && udc->driver->resume) + if (udc->driver && udc->driver->resume) { + spin_unlock(&udc->lock); udc->driver->resume(&udc->gadget); + spin_lock(&udc->lock); + } /* endpoint IRQs are cleared by handling them */ } else { @@ -1474,6 +1502,8 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) if (disable_clock) clk_off(udc); + spin_unlock_irqrestore(&udc->lock, flags); + return IRQ_HANDLED; } @@ -1556,24 +1586,53 @@ static struct at91_udc controller = { /* ep6 and ep7 are also reserved (custom silicon might use them) */ }; +static void at91_vbus_update(struct at91_udc *udc, unsigned value) +{ + value ^= udc->board.vbus_active_low; + if (value != udc->vbus) + at91_vbus_session(&udc->gadget, value); +} + static irqreturn_t at91_vbus_irq(int irq, void *_udc) { struct at91_udc *udc = _udc; - unsigned value; /* vbus needs at least brief debouncing */ udelay(10); - value = gpio_get_value(udc->board.vbus_pin); - if (value != udc->vbus) - at91_vbus_session(&udc->gadget, value); + at91_vbus_update(udc, gpio_get_value(udc->board.vbus_pin)); return IRQ_HANDLED; } +static void at91_vbus_timer_work(struct work_struct *work) +{ + struct at91_udc *udc = container_of(work, struct at91_udc, + vbus_timer_work); + + at91_vbus_update(udc, gpio_get_value_cansleep(udc->board.vbus_pin)); + + if (!timer_pending(&udc->vbus_timer)) + mod_timer(&udc->vbus_timer, jiffies + VBUS_POLL_TIMEOUT); +} + +static void at91_vbus_timer(unsigned long data) +{ + struct at91_udc *udc = (struct at91_udc *)data; + + /* + * If we are polling vbus it is likely that the gpio is on an + * bus such as i2c or spi which may sleep, so schedule some work + * to read the vbus gpio + */ + if (!work_pending(&udc->vbus_timer_work)) + schedule_work(&udc->vbus_timer_work); +} + int usb_gadget_register_driver (struct usb_gadget_driver *driver) { struct at91_udc *udc = &controller; int retval; + unsigned long flags; if (!driver || driver->speed < USB_SPEED_FULL @@ -1605,9 +1664,9 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) return retval; } - local_irq_disable(); + spin_lock_irqsave(&udc->lock, flags); pullup(udc, 1); - local_irq_enable(); + spin_unlock_irqrestore(&udc->lock, flags); DBG("bound to %s\n", driver->driver.name); return 0; @@ -1617,15 +1676,16 @@ EXPORT_SYMBOL (usb_gadget_register_driver); int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) { struct at91_udc *udc = &controller; + unsigned long flags; if (!driver || driver != udc->driver || !driver->unbind) return -EINVAL; - local_irq_disable(); + spin_lock_irqsave(&udc->lock, flags); udc->enabled = 0; at91_udp_write(udc, AT91_UDP_IDR, ~0); pullup(udc, 0); - local_irq_enable(); + spin_unlock_irqrestore(&udc->lock, flags); driver->unbind(&udc->gadget); udc->gadget.dev.driver = NULL; @@ -1641,8 +1701,13 @@ EXPORT_SYMBOL (usb_gadget_unregister_driver); static void at91udc_shutdown(struct platform_device *dev) { + struct at91_udc *udc = platform_get_drvdata(dev); + unsigned long flags; + /* force disconnect on reboot */ + spin_lock_irqsave(&udc->lock, flags); pullup(platform_get_drvdata(dev), 0); + spin_unlock_irqrestore(&udc->lock, flags); } static int __init at91udc_probe(struct platform_device *pdev) @@ -1683,6 +1748,7 @@ static int __init at91udc_probe(struct platform_device *pdev) udc->board = *(struct at91_udc_data *) dev->platform_data; udc->pdev = pdev; udc->enabled = 0; + spin_lock_init(&udc->lock); /* rm9200 needs manual D+ pullup; off by default */ if (cpu_is_at91rm9200()) { @@ -1763,13 +1829,23 @@ static int __init at91udc_probe(struct platform_device *pdev) * Get the initial state of VBUS - we cannot expect * a pending interrupt. */ - udc->vbus = gpio_get_value(udc->board.vbus_pin); - if (request_irq(udc->board.vbus_pin, at91_vbus_irq, - IRQF_DISABLED, driver_name, udc)) { - DBG("request vbus irq %d failed\n", - udc->board.vbus_pin); - retval = -EBUSY; - goto fail3; + udc->vbus = gpio_get_value_cansleep(udc->board.vbus_pin) ^ + udc->board.vbus_active_low; + + if (udc->board.vbus_polled) { + INIT_WORK(&udc->vbus_timer_work, at91_vbus_timer_work); + setup_timer(&udc->vbus_timer, at91_vbus_timer, + (unsigned long)udc); + mod_timer(&udc->vbus_timer, + jiffies + VBUS_POLL_TIMEOUT); + } else { + if (request_irq(udc->board.vbus_pin, at91_vbus_irq, + IRQF_DISABLED, driver_name, udc)) { + DBG("request vbus irq %d failed\n", + udc->board.vbus_pin); + retval = -EBUSY; + goto fail3; + } } } else { DBG("no VBUS detection, assuming always-on\n"); @@ -1804,13 +1880,16 @@ static int __exit at91udc_remove(struct platform_device *pdev) { struct at91_udc *udc = platform_get_drvdata(pdev); struct resource *res; + unsigned long flags; DBG("remove\n"); if (udc->driver) return -EBUSY; + spin_lock_irqsave(&udc->lock, flags); pullup(udc, 0); + spin_unlock_irqrestore(&udc->lock, flags); device_init_wakeup(&pdev->dev, 0); remove_debug_file(udc); @@ -1840,6 +1919,7 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg) { struct at91_udc *udc = platform_get_drvdata(pdev); int wake = udc->driver && device_may_wakeup(&pdev->dev); + unsigned long flags; /* Unless we can act normally to the host (letting it wake us up * whenever it has work for us) force disconnect. Wakeup requires @@ -1849,13 +1929,15 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg) if ((!udc->suspended && udc->addr) || !wake || at91_suspend_entering_slow_clock()) { + spin_lock_irqsave(&udc->lock, flags); pullup(udc, 0); wake = 0; + spin_unlock_irqrestore(&udc->lock, flags); } else enable_irq_wake(udc->udp_irq); udc->active_suspend = wake; - if (udc->board.vbus_pin > 0 && wake) + if (udc->board.vbus_pin > 0 && !udc->board.vbus_polled && wake) enable_irq_wake(udc->board.vbus_pin); return 0; } @@ -1863,15 +1945,20 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg) static int at91udc_resume(struct platform_device *pdev) { struct at91_udc *udc = platform_get_drvdata(pdev); + unsigned long flags; - if (udc->board.vbus_pin > 0 && udc->active_suspend) + if (udc->board.vbus_pin > 0 && !udc->board.vbus_polled && + udc->active_suspend) disable_irq_wake(udc->board.vbus_pin); /* maybe reconnect to host; if so, clocks on */ if (udc->active_suspend) disable_irq_wake(udc->udp_irq); - else + else { + spin_lock_irqsave(&udc->lock, flags); pullup(udc, 1); + spin_unlock_irqrestore(&udc->lock, flags); + } return 0; } #else diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h index c65d6229589..108ca54f909 100644 --- a/drivers/usb/gadget/at91_udc.h +++ b/drivers/usb/gadget/at91_udc.h @@ -144,6 +144,9 @@ struct at91_udc { struct proc_dir_entry *pde; void __iomem *udp_baseaddr; int udp_irq; + spinlock_t lock; + struct timer_list vbus_timer; + struct work_struct vbus_timer_work; }; static inline struct at91_udc *to_udc(struct usb_gadget *g) diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index d69eccf5f19..2aaa0f75c6c 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -136,7 +136,7 @@ struct ffs_data { * handling setup requests immidiatelly user space may be so * slow that another setup will be sent to the gadget but this * time not to us but another function and then there could be - * a race. Is taht the case? Or maybe we can use cdev->req + * a race. Is that the case? Or maybe we can use cdev->req * after all, maybe we just need some spinlock for that? */ struct usb_request *ep0req; /* P: mutex */ struct completion ep0req_completion; /* P: mutex */ diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c index fc2611f8b32..dbe6db0184f 100644 --- a/drivers/usb/gadget/f_uvc.c +++ b/drivers/usb/gadget/f_uvc.c @@ -28,7 +28,7 @@ #include "uvc.h" -unsigned int uvc_trace_param; +unsigned int uvc_gadget_trace_param; /* -------------------------------------------------------------------------- * Function descriptors @@ -656,6 +656,6 @@ error: return ret; } -module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR); +module_param_named(trace, uvc_gadget_trace_param, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(trace, "Trace level bitmask"); diff --git a/drivers/usb/gadget/fsl_mxc_udc.c b/drivers/usb/gadget/fsl_mxc_udc.c index d0b8bde59e5..eafa6d2c5ed 100644 --- a/drivers/usb/gadget/fsl_mxc_udc.c +++ b/drivers/usb/gadget/fsl_mxc_udc.c @@ -30,7 +30,7 @@ int fsl_udc_clk_init(struct platform_device *pdev) pdata = pdev->dev.platform_data; - if (!cpu_is_mx35()) { + if (!cpu_is_mx35() && !cpu_is_mx25()) { mxc_ahb_clk = clk_get(&pdev->dev, "usb_ahb"); if (IS_ERR(mxc_ahb_clk)) return PTR_ERR(mxc_ahb_clk); diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 85b0d8921ea..980762453a9 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -2561,7 +2561,7 @@ static void pxa_udc_shutdown(struct platform_device *_dev) udc_disable(udc); } -#ifdef CONFIG_CPU_PXA27x +#ifdef CONFIG_PXA27x extern void pxa27x_clear_otgph(void); #else #define pxa27x_clear_otgph() do {} while (0) diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index e724a051bfd..ea2b3c7ebee 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -735,6 +735,10 @@ static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev, else dev->ep0state = EP0_OUT_DATA_PHASE; + if (!dev->driver) + return; + + /* deliver the request to the gadget driver */ ret = dev->driver->setup(&dev->gadget, crq); if (ret < 0) { if (dev->req_config) { diff --git a/drivers/usb/gadget/uvc.h b/drivers/usb/gadget/uvc.h index 0a705e63c93..e92454cddd7 100644 --- a/drivers/usb/gadget/uvc.h +++ b/drivers/usb/gadget/uvc.h @@ -107,11 +107,11 @@ struct uvc_streaming_control { #define UVC_WARN_MINMAX 0 #define UVC_WARN_PROBE_DEF 1 -extern unsigned int uvc_trace_param; +extern unsigned int uvc_gadget_trace_param; #define uvc_trace(flag, msg...) \ do { \ - if (uvc_trace_param & flag) \ + if (uvc_gadget_trace_param & flag) \ printk(KERN_DEBUG "uvcvideo: " msg); \ } while (0) @@ -220,16 +220,10 @@ struct uvc_file_handle #define to_uvc_file_handle(handle) \ container_of(handle, struct uvc_file_handle, vfh) -extern struct v4l2_file_operations uvc_v4l2_fops; - /* ------------------------------------------------------------------------ * Functions */ -extern int uvc_video_enable(struct uvc_video *video, int enable); -extern int uvc_video_init(struct uvc_video *video); -extern int uvc_video_pump(struct uvc_video *video); - extern void uvc_endpoint_stream(struct uvc_device *dev); extern void uvc_function_connect(struct uvc_device *uvc); diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c index 43891991bf2..f7395ac5dc1 100644 --- a/drivers/usb/gadget/uvc_queue.c +++ b/drivers/usb/gadget/uvc_queue.c @@ -78,7 +78,8 @@ * */ -void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) +static void +uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) { mutex_init(&queue->mutex); spin_lock_init(&queue->irqlock); @@ -88,6 +89,28 @@ void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) } /* + * Free the video buffers. + * + * This function must be called with the queue lock held. + */ +static int uvc_free_buffers(struct uvc_video_queue *queue) +{ + unsigned int i; + + for (i = 0; i < queue->count; ++i) { + if (queue->buffer[i].vma_use_count != 0) + return -EBUSY; + } + + if (queue->count) { + vfree(queue->mem); + queue->count = 0; + } + + return 0; +} + +/* * Allocate the video buffers. * * Pages are reserved to make sure they will not be swapped, as they will be @@ -95,8 +118,9 @@ void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) * * Buffers will be individually mapped, so they must all be page aligned. */ -int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers, - unsigned int buflength) +static int +uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers, + unsigned int buflength) { unsigned int bufsize = PAGE_ALIGN(buflength); unsigned int i; @@ -150,28 +174,6 @@ done: return ret; } -/* - * Free the video buffers. - * - * This function must be called with the queue lock held. - */ -int uvc_free_buffers(struct uvc_video_queue *queue) -{ - unsigned int i; - - for (i = 0; i < queue->count; ++i) { - if (queue->buffer[i].vma_use_count != 0) - return -EBUSY; - } - - if (queue->count) { - vfree(queue->mem); - queue->count = 0; - } - - return 0; -} - static void __uvc_query_buffer(struct uvc_buffer *buf, struct v4l2_buffer *v4l2_buf) { @@ -195,8 +197,8 @@ static void __uvc_query_buffer(struct uvc_buffer *buf, } } -int uvc_query_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf) +static int +uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf) { int ret = 0; @@ -217,8 +219,8 @@ done: * Queue a video buffer. Attempting to queue a buffer that has already been * queued will return -EINVAL. */ -int uvc_queue_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf) +static int +uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf) { struct uvc_buffer *buf; unsigned long flags; @@ -298,8 +300,9 @@ static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking) * Dequeue a video buffer. If nonblocking is false, block until a buffer is * available. */ -int uvc_dequeue_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf, int nonblocking) +static int +uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf, + int nonblocking) { struct uvc_buffer *buf; int ret = 0; @@ -359,8 +362,9 @@ done: * This function implements video queue polling and is intended to be used by * the device poll handler. */ -unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, - poll_table *wait) +static unsigned int +uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, + poll_table *wait) { struct uvc_buffer *buf; unsigned int mask = 0; @@ -407,7 +411,8 @@ static struct vm_operations_struct uvc_vm_ops = { * This function implements video buffer memory mapping and is intended to be * used by the device mmap handler. */ -int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) +static int +uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) { struct uvc_buffer *uninitialized_var(buffer); struct page *page; @@ -458,6 +463,42 @@ done: } /* + * Cancel the video buffers queue. + * + * Cancelling the queue marks all buffers on the irq queue as erroneous, + * wakes them up and removes them from the queue. + * + * If the disconnect parameter is set, further calls to uvc_queue_buffer will + * fail with -ENODEV. + * + * This function acquires the irq spinlock and can be called from interrupt + * context. + */ +static void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect) +{ + struct uvc_buffer *buf; + unsigned long flags; + + spin_lock_irqsave(&queue->irqlock, flags); + while (!list_empty(&queue->irqqueue)) { + buf = list_first_entry(&queue->irqqueue, struct uvc_buffer, + queue); + list_del(&buf->queue); + buf->state = UVC_BUF_STATE_ERROR; + wake_up(&buf->wait); + } + /* This must be protected by the irqlock spinlock to avoid race + * conditions between uvc_queue_buffer and the disconnection event that + * could result in an interruptible wait in uvc_dequeue_buffer. Do not + * blindly replace this logic by checking for the UVC_DEV_DISCONNECTED + * state outside the queue code. + */ + if (disconnect) + queue->flags |= UVC_QUEUE_DISCONNECTED; + spin_unlock_irqrestore(&queue->irqlock, flags); +} + +/* * Enable or disable the video buffers queue. * * The queue must be enabled before starting video acquisition and must be @@ -474,7 +515,7 @@ done: * This function can't be called from interrupt context. Use * uvc_queue_cancel() instead. */ -int uvc_queue_enable(struct uvc_video_queue *queue, int enable) +static int uvc_queue_enable(struct uvc_video_queue *queue, int enable) { unsigned int i; int ret = 0; @@ -503,44 +544,8 @@ done: return ret; } -/* - * Cancel the video buffers queue. - * - * Cancelling the queue marks all buffers on the irq queue as erroneous, - * wakes them up and removes them from the queue. - * - * If the disconnect parameter is set, further calls to uvc_queue_buffer will - * fail with -ENODEV. - * - * This function acquires the irq spinlock and can be called from interrupt - * context. - */ -void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect) -{ - struct uvc_buffer *buf; - unsigned long flags; - - spin_lock_irqsave(&queue->irqlock, flags); - while (!list_empty(&queue->irqqueue)) { - buf = list_first_entry(&queue->irqqueue, struct uvc_buffer, - queue); - list_del(&buf->queue); - buf->state = UVC_BUF_STATE_ERROR; - wake_up(&buf->wait); - } - /* This must be protected by the irqlock spinlock to avoid race - * conditions between uvc_queue_buffer and the disconnection event that - * could result in an interruptible wait in uvc_dequeue_buffer. Do not - * blindly replace this logic by checking for the UVC_DEV_DISCONNECTED - * state outside the queue code. - */ - if (disconnect) - queue->flags |= UVC_QUEUE_DISCONNECTED; - spin_unlock_irqrestore(&queue->irqlock, flags); -} - -struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, - struct uvc_buffer *buf) +static struct uvc_buffer * +uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf) { struct uvc_buffer *nextbuf; unsigned long flags; @@ -568,7 +573,7 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, return nextbuf; } -struct uvc_buffer *uvc_queue_head(struct uvc_video_queue *queue) +static struct uvc_buffer *uvc_queue_head(struct uvc_video_queue *queue) { struct uvc_buffer *buf = NULL; diff --git a/drivers/usb/gadget/uvc_queue.h b/drivers/usb/gadget/uvc_queue.h index 7f5a33fe7ae..1812a8ecc5d 100644 --- a/drivers/usb/gadget/uvc_queue.h +++ b/drivers/usb/gadget/uvc_queue.h @@ -58,30 +58,10 @@ struct uvc_video_queue { struct list_head irqqueue; }; -extern void uvc_queue_init(struct uvc_video_queue *queue, - enum v4l2_buf_type type); -extern int uvc_alloc_buffers(struct uvc_video_queue *queue, - unsigned int nbuffers, unsigned int buflength); -extern int uvc_free_buffers(struct uvc_video_queue *queue); -extern int uvc_query_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf); -extern int uvc_queue_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf); -extern int uvc_dequeue_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf, int nonblocking); -extern int uvc_queue_enable(struct uvc_video_queue *queue, int enable); -extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); -extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, - struct uvc_buffer *buf); -extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue, - struct file *file, poll_table *wait); -extern int uvc_queue_mmap(struct uvc_video_queue *queue, - struct vm_area_struct *vma); static inline int uvc_queue_streaming(struct uvc_video_queue *queue) { return queue->flags & UVC_QUEUE_STREAMING; } -extern struct uvc_buffer *uvc_queue_head(struct uvc_video_queue *queue); #endif /* __KERNEL__ */ diff --git a/drivers/usb/gadget/uvc_v4l2.c b/drivers/usb/gadget/uvc_v4l2.c index a7989f29837..2dcffdac86d 100644 --- a/drivers/usb/gadget/uvc_v4l2.c +++ b/drivers/usb/gadget/uvc_v4l2.c @@ -363,7 +363,7 @@ uvc_v4l2_poll(struct file *file, poll_table *wait) return mask; } -struct v4l2_file_operations uvc_v4l2_fops = { +static struct v4l2_file_operations uvc_v4l2_fops = { .owner = THIS_MODULE, .open = uvc_v4l2_open, .release = uvc_v4l2_release, diff --git a/drivers/usb/gadget/uvc_video.c b/drivers/usb/gadget/uvc_video.c index de8cbc46518..b08f35438d7 100644 --- a/drivers/usb/gadget/uvc_video.c +++ b/drivers/usb/gadget/uvc_video.c @@ -271,7 +271,7 @@ error: * This function fills the available USB requests (listed in req_free) with * video data from the queued buffers. */ -int +static int uvc_video_pump(struct uvc_video *video) { struct usb_request *req; @@ -328,7 +328,7 @@ uvc_video_pump(struct uvc_video *video) /* * Enable or disable the video stream. */ -int +static int uvc_video_enable(struct uvc_video *video, int enable) { unsigned int i; @@ -367,7 +367,7 @@ uvc_video_enable(struct uvc_video *video, int enable) /* * Initialize the UVC video stream. */ -int +static int uvc_video_init(struct uvc_video *video) { INIT_LIST_HEAD(&video->req_free); diff --git a/drivers/usb/gadget/webcam.c b/drivers/usb/gadget/webcam.c index 417fd688769..f5f3030cc41 100644 --- a/drivers/usb/gadget/webcam.c +++ b/drivers/usb/gadget/webcam.c @@ -28,10 +28,10 @@ #include "config.c" #include "epautoconf.c" -#include "f_uvc.c" #include "uvc_queue.c" -#include "uvc_v4l2.c" #include "uvc_video.c" +#include "uvc_v4l2.c" +#include "f_uvc.c" /* -------------------------------------------------------------------------- * Device descriptor diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index bd4027745aa..a8ad8ac120a 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c @@ -182,7 +182,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) } clk_enable(priv->usbclk); - if (!cpu_is_mx35()) { + if (!cpu_is_mx35() && !cpu_is_mx25()) { priv->ahbclk = clk_get(dev, "usb_ahb"); if (IS_ERR(priv->ahbclk)) { ret = PTR_ERR(priv->ahbclk); diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index a18debdd79b..41816389477 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -203,7 +203,7 @@ static inline void pxa27x_reset_hc(struct pxa27x_ohci *ohci) __raw_writel(uhchr & ~UHCHR_FHR, ohci->mmio_base + UHCHR); } -#ifdef CONFIG_CPU_PXA27x +#ifdef CONFIG_PXA27x extern void pxa27x_clear_otgph(void); #else #define pxa27x_clear_otgph() do {} while (0) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index fd9e03afd91..2eb658d2639 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -835,6 +835,27 @@ fail: return 0; } +void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci, + struct usb_device *udev) +{ + struct xhci_virt_device *virt_dev; + struct xhci_ep_ctx *ep0_ctx; + struct xhci_ring *ep_ring; + + virt_dev = xhci->devs[udev->slot_id]; + ep0_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, 0); + ep_ring = virt_dev->eps[0].ring; + /* + * FIXME we don't keep track of the dequeue pointer very well after a + * Set TR dequeue pointer, so we're setting the dequeue pointer of the + * host to our enqueue pointer. This should only be called after a + * configured device has reset, so all control transfers should have + * been completed or cancelled before the reset. + */ + ep0_ctx->deq = xhci_trb_virt_to_dma(ep_ring->enq_seg, ep_ring->enqueue); + ep0_ctx->deq |= ep_ring->cycle_state; +} + /* Setup an xHCI virtual device for a Set Address command */ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev) { @@ -1002,7 +1023,7 @@ static inline unsigned int xhci_get_endpoint_interval(struct usb_device *udev, return EP_INTERVAL(interval); } -/* The "Mult" field in the endpoint context is only set for SuperSpeed devices. +/* The "Mult" field in the endpoint context is only set for SuperSpeed isoc eps. * High speed endpoint descriptors can define "the number of additional * transaction opportunities per microframe", but that goes in the Max Burst * endpoint context field. @@ -1010,7 +1031,8 @@ static inline unsigned int xhci_get_endpoint_interval(struct usb_device *udev, static inline u32 xhci_get_endpoint_mult(struct usb_device *udev, struct usb_host_endpoint *ep) { - if (udev->speed != USB_SPEED_SUPER) + if (udev->speed != USB_SPEED_SUPER || + !usb_endpoint_xfer_isoc(&ep->desc)) return 0; return ep->ss_ep_comp.bmAttributes; } diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 94e6934edb0..bfc99a93945 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2380,16 +2380,19 @@ static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2, u32 field3, u32 field4, bool command_must_succeed) { int reserved_trbs = xhci->cmd_ring_reserved_trbs; + int ret; + if (!command_must_succeed) reserved_trbs++; - if (!room_on_ring(xhci, xhci->cmd_ring, reserved_trbs)) { - if (!in_interrupt()) - xhci_err(xhci, "ERR: No room for command on command ring\n"); + ret = prepare_ring(xhci, xhci->cmd_ring, EP_STATE_RUNNING, + reserved_trbs, GFP_ATOMIC); + if (ret < 0) { + xhci_err(xhci, "ERR: No room for command on command ring\n"); if (command_must_succeed) xhci_err(xhci, "ERR: Reserved TRB counting for " "unfailable commands failed.\n"); - return -ENOMEM; + return ret; } queue_trb(xhci, xhci->cmd_ring, false, false, field1, field2, field3, field4 | xhci->cmd_ring->cycle_state); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 27345cd04da..3998f72cd0c 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -2134,6 +2134,8 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) /* If this is a Set Address to an unconfigured device, setup ep 0 */ if (!udev->config) xhci_setup_addressable_virt_dev(xhci, udev); + else + xhci_copy_ep0_dequeue_into_input_ctx(xhci, udev); /* Otherwise, assume the core has the device configured how it wants */ xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 8b4b7d39f79..6c7e3430ec9 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1292,6 +1292,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags); void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id); int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, struct usb_device *udev, gfp_t flags); int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev); +void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci, + struct usb_device *udev); unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc); unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc); unsigned int xhci_get_endpoint_flag_from_index(unsigned int ep_index); diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 30d930386b6..d25814c172b 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -2436,7 +2436,8 @@ sisusb_open(struct inode *inode, struct file *file) } if (!sisusb->devinit) { - if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) { + if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH || + sisusb->sisusb_dev->speed == USB_SPEED_SUPER) { if (sisusb_init_gfxdevice(sisusb, 0)) { mutex_unlock(&sisusb->lock); dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n"); @@ -3166,7 +3167,7 @@ static int sisusb_probe(struct usb_interface *intf, sisusb->present = 1; - if (dev->speed == USB_SPEED_HIGH) { + if (dev->speed == USB_SPEED_HIGH || dev->speed == USB_SPEED_SUPER) { int initscreen = 1; #ifdef INCL_SISUSB_CON if (sisusb_first_vc > 0 && diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 05c077f8f9a..3c48e77a0aa 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -29,19 +29,6 @@ static void tusb_source_power(struct musb *musb, int is_on); #define TUSB_REV_MAJOR(reg_val) ((reg_val >> 4) & 0xf) #define TUSB_REV_MINOR(reg_val) (reg_val & 0xf) -#ifdef CONFIG_PM -/* REVISIT: These should be only needed if somebody implements off idle */ -void musb_platform_save_context(struct musb *musb, - struct musb_context_registers *musb_context) -{ -} - -void musb_platform_restore_context(struct musb *musb, - struct musb_context_registers *musb_context) -{ -} -#endif - /* * Checks the revision. We need to use the DMA register as 3.0 does not * have correct versions for TUSB_PRCM_REV or TUSB_INT_CTRL_REV. diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index da7e334b040..e298dc4baed 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -691,6 +691,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID), .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) }, { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) }, @@ -737,6 +738,14 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, MJSG_SR_RADIO_PID) }, { USB_DEVICE(FTDI_VID, MJSG_HD_RADIO_PID) }, { USB_DEVICE(FTDI_VID, MJSG_XM_RADIO_PID) }, + { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_ST_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SLITE_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH2_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH4_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index bbc159a1df4..d01946db8fa 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -696,6 +696,12 @@ #define TELLDUS_TELLSTICK_PID 0x0C30 /* RF control dongle 433 MHz using FT232RL */ /* + * RT Systems programming cables for various ham radios + */ +#define RTSYSTEMS_VID 0x2100 /* Vendor ID */ +#define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */ + +/* * Bayer Ascensia Contour blood glucose meter USB-converter cable. * http://winglucofacts.com/cables/ */ @@ -1017,3 +1023,12 @@ #define MJSG_SR_RADIO_PID 0x9379 #define MJSG_XM_RADIO_PID 0x937A #define MJSG_HD_RADIO_PID 0x937C + +/* + * Xverve Signalyzer tools (http://www.signalyzer.com/) + */ +#define XVERVE_SIGNALYZER_ST_PID 0xBCA0 +#define XVERVE_SIGNALYZER_SLITE_PID 0xBCA1 +#define XVERVE_SIGNALYZER_SH2_PID 0xBCA2 +#define XVERVE_SIGNALYZER_SH4_PID 0xBCA4 + diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index e280ad8e12f..5cd30e4345c 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -206,6 +206,7 @@ static void option_instat_callback(struct urb *urb); #define AMOI_PRODUCT_H01 0x0800 #define AMOI_PRODUCT_H01A 0x7002 #define AMOI_PRODUCT_H02 0x0802 +#define AMOI_PRODUCT_SKYPEPHONE_S2 0x0407 #define DELL_VENDOR_ID 0x413C @@ -302,6 +303,7 @@ static void option_instat_callback(struct urb *urb); #define QISDA_PRODUCT_H21_4512 0x4512 #define QISDA_PRODUCT_H21_4523 0x4523 #define QISDA_PRODUCT_H20_4515 0x4515 +#define QISDA_PRODUCT_H20_4518 0x4518 #define QISDA_PRODUCT_H20_4519 0x4519 /* TLAYTECH PRODUCTS */ @@ -516,6 +518,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) }, { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) }, { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H02) }, + { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_SKYPEPHONE_S2) }, { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5700_MINICARD) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite EV620 CDMA/EV-DO */ { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5500_MINICARD) }, /* Dell Wireless 5500 Mobile Broadband HSDPA Mini-Card == Novatel Expedite EU740 HSDPA/3G */ @@ -852,6 +855,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4512) }, { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4523) }, { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4515) }, + { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4518) }, { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4519) }, { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_G450) }, { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_HSDPA_MINICARD ) }, /* Toshiba 3G HSDPA == Novatel Expedite EU870D MiniCard */ diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 93d72eb8caf..cde67cacb2c 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -51,6 +51,8 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE(0x1f45, 0x0001)}, /* Unknown Gobi QDL device */ {USB_DEVICE(0x413c, 0x8185)}, /* Dell Gobi 2000 QDL device (N0218, VU936) */ {USB_DEVICE(0x413c, 0x8186)}, /* Dell Gobi 2000 Modem device (N0218, VU936) */ + {USB_DEVICE(0x05c6, 0x9208)}, /* Generic Gobi 2000 QDL device */ + {USB_DEVICE(0x05c6, 0x920b)}, /* Generic Gobi 2000 Modem device */ {USB_DEVICE(0x05c6, 0x9224)}, /* Sony Gobi 2000 QDL device (N0279, VU730) */ {USB_DEVICE(0x05c6, 0x9225)}, /* Sony Gobi 2000 Modem device (N0279, VU730) */ {USB_DEVICE(0x05c6, 0x9244)}, /* Samsung Gobi 2000 QDL device (VL176) */ diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index ef0bdb08d78..d47b56e9e8c 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -245,6 +245,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */ { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */ { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */ + { USB_DEVICE(0x1199, 0x0301) }, /* Sierra Wireless USB Dongle 250U */ /* Sierra Wireless C597 */ { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x0023, 0xFF, 0xFF, 0xFF) }, /* Sierra Wireless T598 */ diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 44716427c51..64ec073e89d 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -139,9 +139,7 @@ static int usb_stor_msg_common(struct us_data *us, int timeout) /* fill the common fields in the URB */ us->current_urb->context = &urb_done; - us->current_urb->actual_length = 0; - us->current_urb->error_count = 0; - us->current_urb->status = 0; + us->current_urb->transfer_flags = 0; /* we assume that if transfer_buffer isn't us->iobuf then it * hasn't been mapped for DMA. Yes, this is clunky, but it's diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index df5b6b971f2..d219070fed3 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -98,7 +98,8 @@ static void tx_poll_start(struct vhost_net *net, struct socket *sock) static void handle_tx(struct vhost_net *net) { struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX]; - unsigned head, out, in, s; + unsigned out, in, s; + int head; struct msghdr msg = { .msg_name = NULL, .msg_namelen = 0, @@ -135,6 +136,9 @@ static void handle_tx(struct vhost_net *net) ARRAY_SIZE(vq->iov), &out, &in, NULL, NULL); + /* On error, stop handling until the next kick. */ + if (unlikely(head < 0)) + break; /* Nothing new? Wait for eventfd to tell us they refilled. */ if (head == vq->num) { wmem = atomic_read(&sock->sk->sk_wmem_alloc); @@ -173,8 +177,8 @@ static void handle_tx(struct vhost_net *net) break; } if (err != len) - pr_err("Truncated TX packet: " - " len %d != %zd\n", err, len); + pr_debug("Truncated TX packet: " + " len %d != %zd\n", err, len); vhost_add_used_and_signal(&net->dev, vq, head, 0); total_len += len; if (unlikely(total_len >= VHOST_NET_WEIGHT)) { @@ -192,7 +196,8 @@ static void handle_tx(struct vhost_net *net) static void handle_rx(struct vhost_net *net) { struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX]; - unsigned head, out, in, log, s; + unsigned out, in, log, s; + int head; struct vhost_log *vq_log; struct msghdr msg = { .msg_name = NULL, @@ -228,6 +233,9 @@ static void handle_rx(struct vhost_net *net) ARRAY_SIZE(vq->iov), &out, &in, vq_log, &log); + /* On error, stop handling until the next kick. */ + if (unlikely(head < 0)) + break; /* OK, now we need to know about added descriptors. */ if (head == vq->num) { if (unlikely(vhost_enable_notify(vq))) { @@ -267,8 +275,8 @@ static void handle_rx(struct vhost_net *net) } /* TODO: Should check and handle checksum. */ if (err > len) { - pr_err("Discarded truncated rx packet: " - " len %d > %zd\n", err, len); + pr_debug("Discarded truncated rx packet: " + " len %d > %zd\n", err, len); vhost_discard_vq_desc(vq); continue; } @@ -526,11 +534,16 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) rcu_assign_pointer(vq->private_data, sock); vhost_net_enable_vq(n, vq); done: + mutex_unlock(&vq->mutex); + if (oldsock) { vhost_net_flush_vq(n, index); fput(oldsock->file); } + mutex_unlock(&n->dev.mutex); + return 0; + err_vq: mutex_unlock(&vq->mutex); err: diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 3b83382e06e..0b99783083f 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -736,12 +736,12 @@ static int translate_desc(struct vhost_dev *dev, u64 addr, u32 len, mem = rcu_dereference(dev->memory); while ((u64)len > s) { u64 size; - if (ret >= iov_size) { + if (unlikely(ret >= iov_size)) { ret = -ENOBUFS; break; } reg = find_region(mem, addr, len); - if (!reg) { + if (unlikely(!reg)) { ret = -EFAULT; break; } @@ -780,18 +780,18 @@ static unsigned next_desc(struct vring_desc *desc) return next; } -static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, - struct iovec iov[], unsigned int iov_size, - unsigned int *out_num, unsigned int *in_num, - struct vhost_log *log, unsigned int *log_num, - struct vring_desc *indirect) +static int get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, + struct iovec iov[], unsigned int iov_size, + unsigned int *out_num, unsigned int *in_num, + struct vhost_log *log, unsigned int *log_num, + struct vring_desc *indirect) { struct vring_desc desc; unsigned int i = 0, count, found = 0; int ret; /* Sanity check */ - if (indirect->len % sizeof desc) { + if (unlikely(indirect->len % sizeof desc)) { vq_err(vq, "Invalid length in indirect descriptor: " "len 0x%llx not multiple of 0x%zx\n", (unsigned long long)indirect->len, @@ -801,7 +801,7 @@ static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, ret = translate_desc(dev, indirect->addr, indirect->len, vq->indirect, ARRAY_SIZE(vq->indirect)); - if (ret < 0) { + if (unlikely(ret < 0)) { vq_err(vq, "Translation failure %d in indirect.\n", ret); return ret; } @@ -813,7 +813,7 @@ static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, count = indirect->len / sizeof desc; /* Buffers are chained via a 16 bit next field, so * we can have at most 2^16 of these. */ - if (count > USHRT_MAX + 1) { + if (unlikely(count > USHRT_MAX + 1)) { vq_err(vq, "Indirect buffer length too big: %d\n", indirect->len); return -E2BIG; @@ -821,19 +821,19 @@ static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, do { unsigned iov_count = *in_num + *out_num; - if (++found > count) { + if (unlikely(++found > count)) { vq_err(vq, "Loop detected: last one at %u " "indirect size %u\n", i, count); return -EINVAL; } - if (memcpy_fromiovec((unsigned char *)&desc, vq->indirect, - sizeof desc)) { + if (unlikely(memcpy_fromiovec((unsigned char *)&desc, vq->indirect, + sizeof desc))) { vq_err(vq, "Failed indirect descriptor: idx %d, %zx\n", i, (size_t)indirect->addr + i * sizeof desc); return -EINVAL; } - if (desc.flags & VRING_DESC_F_INDIRECT) { + if (unlikely(desc.flags & VRING_DESC_F_INDIRECT)) { vq_err(vq, "Nested indirect descriptor: idx %d, %zx\n", i, (size_t)indirect->addr + i * sizeof desc); return -EINVAL; @@ -841,7 +841,7 @@ static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, ret = translate_desc(dev, desc.addr, desc.len, iov + iov_count, iov_size - iov_count); - if (ret < 0) { + if (unlikely(ret < 0)) { vq_err(vq, "Translation failure %d indirect idx %d\n", ret, i); return ret; @@ -857,7 +857,7 @@ static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, } else { /* If it's an output descriptor, they're all supposed * to come before any input descriptors. */ - if (*in_num) { + if (unlikely(*in_num)) { vq_err(vq, "Indirect descriptor " "has out after in: idx %d\n", i); return -EINVAL; @@ -873,12 +873,13 @@ static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, * number of output then some number of input descriptors, it's actually two * iovecs, but we pack them into one and note how many of each there were. * - * This function returns the descriptor number found, or vq->num (which - * is never a valid descriptor number) if none was found. */ -unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, - struct iovec iov[], unsigned int iov_size, - unsigned int *out_num, unsigned int *in_num, - struct vhost_log *log, unsigned int *log_num) + * This function returns the descriptor number found, or vq->num (which is + * never a valid descriptor number) if none was found. A negative code is + * returned on error. */ +int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, + struct iovec iov[], unsigned int iov_size, + unsigned int *out_num, unsigned int *in_num, + struct vhost_log *log, unsigned int *log_num) { struct vring_desc desc; unsigned int i, head, found = 0; @@ -887,16 +888,16 @@ unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, /* Check it isn't doing very strange things with descriptor numbers. */ last_avail_idx = vq->last_avail_idx; - if (get_user(vq->avail_idx, &vq->avail->idx)) { + if (unlikely(get_user(vq->avail_idx, &vq->avail->idx))) { vq_err(vq, "Failed to access avail idx at %p\n", &vq->avail->idx); - return vq->num; + return -EFAULT; } - if ((u16)(vq->avail_idx - last_avail_idx) > vq->num) { + if (unlikely((u16)(vq->avail_idx - last_avail_idx) > vq->num)) { vq_err(vq, "Guest moved used index from %u to %u", last_avail_idx, vq->avail_idx); - return vq->num; + return -EFAULT; } /* If there's nothing new since last we looked, return invalid. */ @@ -908,18 +909,19 @@ unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, /* Grab the next descriptor number they're advertising, and increment * the index we've seen. */ - if (get_user(head, &vq->avail->ring[last_avail_idx % vq->num])) { + if (unlikely(get_user(head, + &vq->avail->ring[last_avail_idx % vq->num]))) { vq_err(vq, "Failed to read head: idx %d address %p\n", last_avail_idx, &vq->avail->ring[last_avail_idx % vq->num]); - return vq->num; + return -EFAULT; } /* If their number is silly, that's an error. */ - if (head >= vq->num) { + if (unlikely(head >= vq->num)) { vq_err(vq, "Guest says index %u > %u is available", head, vq->num); - return vq->num; + return -EINVAL; } /* When we start there are none of either input nor output. */ @@ -930,41 +932,41 @@ unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, i = head; do { unsigned iov_count = *in_num + *out_num; - if (i >= vq->num) { + if (unlikely(i >= vq->num)) { vq_err(vq, "Desc index is %u > %u, head = %u", i, vq->num, head); - return vq->num; + return -EINVAL; } - if (++found > vq->num) { + if (unlikely(++found > vq->num)) { vq_err(vq, "Loop detected: last one at %u " "vq size %u head %u\n", i, vq->num, head); - return vq->num; + return -EINVAL; } ret = copy_from_user(&desc, vq->desc + i, sizeof desc); - if (ret) { + if (unlikely(ret)) { vq_err(vq, "Failed to get descriptor: idx %d addr %p\n", i, vq->desc + i); - return vq->num; + return -EFAULT; } if (desc.flags & VRING_DESC_F_INDIRECT) { ret = get_indirect(dev, vq, iov, iov_size, out_num, in_num, log, log_num, &desc); - if (ret < 0) { + if (unlikely(ret < 0)) { vq_err(vq, "Failure detected " "in indirect descriptor at idx %d\n", i); - return vq->num; + return ret; } continue; } ret = translate_desc(dev, desc.addr, desc.len, iov + iov_count, iov_size - iov_count); - if (ret < 0) { + if (unlikely(ret < 0)) { vq_err(vq, "Translation failure %d descriptor idx %d\n", ret, i); - return vq->num; + return ret; } if (desc.flags & VRING_DESC_F_WRITE) { /* If this is an input descriptor, @@ -978,10 +980,10 @@ unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, } else { /* If it's an output descriptor, they're all supposed * to come before any input descriptors. */ - if (*in_num) { + if (unlikely(*in_num)) { vq_err(vq, "Descriptor has out after in: " "idx %d\n", i); - return vq->num; + return -EINVAL; } *out_num += ret; } diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 44591ba9b07..11ee13dba0f 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -120,10 +120,10 @@ long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, unsigned long arg); int vhost_vq_access_ok(struct vhost_virtqueue *vq); int vhost_log_access_ok(struct vhost_dev *); -unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *, - struct iovec iov[], unsigned int iov_count, - unsigned int *out_num, unsigned int *in_num, - struct vhost_log *log, unsigned int *log_num); +int vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *, + struct iovec iov[], unsigned int iov_count, + unsigned int *out_num, unsigned int *in_num, + struct vhost_log *log, unsigned int *log_num); void vhost_discard_vq_desc(struct vhost_virtqueue *); int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len); diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c index 515cf1978d1..c4e17642d9c 100644 --- a/drivers/video/aty/radeon_pm.c +++ b/drivers/video/aty/radeon_pm.c @@ -2872,7 +2872,7 @@ void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk, int ignore_devlis } #if 0 - /* Power down TV DAC, taht saves a significant amount of power, + /* Power down TV DAC, that saves a significant amount of power, * we'll have something better once we actually have some TVOut * support */ diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c index 40f61320ce1..34b2fc472fe 100644 --- a/drivers/video/au1100fb.c +++ b/drivers/video/au1100fb.c @@ -95,7 +95,7 @@ struct fb_bitfield rgb_bitfields[][4] = { { 8, 4, 0 }, { 4, 4, 0 }, { 0, 4, 0 }, { 0, 0, 0 } }, }; -static struct fb_fix_screeninfo au1100fb_fix __initdata = { +static struct fb_fix_screeninfo au1100fb_fix __devinitdata = { .id = "AU1100 FB", .xpanstep = 1, .ypanstep = 1, @@ -103,7 +103,7 @@ static struct fb_fix_screeninfo au1100fb_fix __initdata = { .accel = FB_ACCEL_NONE, }; -static struct fb_var_screeninfo au1100fb_var __initdata = { +static struct fb_var_screeninfo au1100fb_var __devinitdata = { .activate = FB_ACTIVATE_NOW, .height = -1, .width = -1, @@ -458,7 +458,7 @@ static struct fb_ops au1100fb_ops = /* AU1100 LCD controller device driver */ -static int __init au1100fb_drv_probe(struct platform_device *dev) +static int __devinit au1100fb_drv_probe(struct platform_device *dev) { struct au1100fb_device *fbdev = NULL; struct resource *regs_res; diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index 3a561df2e8a..0c1afd13ddd 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c @@ -388,6 +388,7 @@ cyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, pseudo_val |= convert_bitfield(red, &var->red); pseudo_val |= convert_bitfield(green, &var->green); pseudo_val |= convert_bitfield(blue, &var->blue); + ret = 0; break; } @@ -436,6 +437,8 @@ static void cyber2000fb_write_ramdac_ctrl(struct cfb_info *cfb) cyber2000fb_writeb(i | 4, 0x3cf, cfb); cyber2000fb_writeb(val, 0x3c6, cfb); cyber2000fb_writeb(i, 0x3cf, cfb); + /* prevent card lock-up observed on x86 with CyberPro 2000 */ + cyber2000fb_readb(0x3cf, cfb); } static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw) diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index 7d8c55d7fd2..ca3355e430b 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c @@ -91,10 +91,10 @@ static uint32_t pseudo_palette[16]; static uint32_t gbe_cmap[256]; static int gbe_turned_on; /* 0 turned off, 1 turned on */ -static char *mode_option __initdata = NULL; +static char *mode_option __devinitdata = NULL; /* default CRT mode */ -static struct fb_var_screeninfo default_var_CRT __initdata = { +static struct fb_var_screeninfo default_var_CRT __devinitdata = { /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ .xres = 640, .yres = 480, @@ -125,7 +125,7 @@ static struct fb_var_screeninfo default_var_CRT __initdata = { }; /* default LCD mode */ -static struct fb_var_screeninfo default_var_LCD __initdata = { +static struct fb_var_screeninfo default_var_LCD __devinitdata = { /* 1600x1024, 8 bpp */ .xres = 1600, .yres = 1024, @@ -157,7 +157,7 @@ static struct fb_var_screeninfo default_var_LCD __initdata = { /* default modedb mode */ /* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */ -static struct fb_videomode default_mode_CRT __initdata = { +static struct fb_videomode default_mode_CRT __devinitdata = { .refresh = 60, .xres = 640, .yres = 480, @@ -172,7 +172,7 @@ static struct fb_videomode default_mode_CRT __initdata = { .vmode = FB_VMODE_NONINTERLACED, }; /* 1600x1024 SGI flatpanel 1600sw */ -static struct fb_videomode default_mode_LCD __initdata = { +static struct fb_videomode default_mode_LCD __devinitdata = { /* 1600x1024, 8 bpp */ .xres = 1600, .yres = 1024, @@ -186,8 +186,8 @@ static struct fb_videomode default_mode_LCD __initdata = { .vmode = FB_VMODE_NONINTERLACED, }; -static struct fb_videomode *default_mode __initdata = &default_mode_CRT; -static struct fb_var_screeninfo *default_var __initdata = &default_var_CRT; +static struct fb_videomode *default_mode __devinitdata = &default_mode_CRT; +static struct fb_var_screeninfo *default_var __devinitdata = &default_var_CRT; static int flat_panel_enabled = 0; @@ -1098,7 +1098,7 @@ static void gbefb_create_sysfs(struct device *dev) * Initialization */ -static int __init gbefb_setup(char *options) +static int __devinit gbefb_setup(char *options) { char *this_opt; diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index b4b6deceed1..43f0639b1c1 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -175,6 +175,7 @@ struct imxfb_info { struct imx_fb_videomode *mode; int num_modes; + struct backlight_device *bl; void (*lcd_power)(int); void (*backlight_power)(int); @@ -449,6 +450,73 @@ static int imxfb_set_par(struct fb_info *info) return 0; } + + +static int imxfb_bl_get_brightness(struct backlight_device *bl) +{ + struct imxfb_info *fbi = bl_get_data(bl); + + return readl(fbi->regs + LCDC_PWMR) & 0xFF; +} + +static int imxfb_bl_update_status(struct backlight_device *bl) +{ + struct imxfb_info *fbi = bl_get_data(bl); + int brightness = bl->props.brightness; + + if (bl->props.power != FB_BLANK_UNBLANK) + brightness = 0; + if (bl->props.fb_blank != FB_BLANK_UNBLANK) + brightness = 0; + + fbi->pwmr = (fbi->pwmr & ~0xFF) | brightness; + + if (bl->props.fb_blank != FB_BLANK_UNBLANK) + clk_enable(fbi->clk); + writel(fbi->pwmr, fbi->regs + LCDC_PWMR); + if (bl->props.fb_blank != FB_BLANK_UNBLANK) + clk_disable(fbi->clk); + + return 0; +} + +static const struct backlight_ops imxfb_lcdc_bl_ops = { + .update_status = imxfb_bl_update_status, + .get_brightness = imxfb_bl_get_brightness, +}; + +static void imxfb_init_backlight(struct imxfb_info *fbi) +{ + struct backlight_properties props; + struct backlight_device *bl; + + if (fbi->bl) + return; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = 0xff; + writel(fbi->pwmr, fbi->regs + LCDC_PWMR); + + bl = backlight_device_register("imxfb-bl", &fbi->pdev->dev, fbi, + &imxfb_lcdc_bl_ops, &props); + if (IS_ERR(bl)) { + dev_err(&fbi->pdev->dev, "error %ld on backlight register\n", + PTR_ERR(bl)); + return; + } + + fbi->bl = bl; + bl->props.power = FB_BLANK_UNBLANK; + bl->props.fb_blank = FB_BLANK_UNBLANK; + bl->props.brightness = imxfb_bl_get_brightness(bl); +} + +static void imxfb_exit_backlight(struct imxfb_info *fbi) +{ + if (fbi->bl) + backlight_device_unregister(fbi->bl); +} + static void imxfb_enable_controller(struct imxfb_info *fbi) { pr_debug("Enabling LCD controller\n"); @@ -579,7 +647,6 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf fbi->regs + LCDC_SIZE); writel(fbi->pcr, fbi->regs + LCDC_PCR); - writel(fbi->pwmr, fbi->regs + LCDC_PWMR); writel(fbi->lscr1, fbi->regs + LCDC_LSCR1); writel(fbi->dmacr, fbi->regs + LCDC_DMACR); @@ -779,6 +846,8 @@ static int __init imxfb_probe(struct platform_device *pdev) } imxfb_enable_controller(fbi); + fbi->pdev = pdev; + imxfb_init_backlight(fbi); return 0; @@ -816,6 +885,7 @@ static int __devexit imxfb_remove(struct platform_device *pdev) imxfb_disable_controller(fbi); + imxfb_exit_backlight(fbi); unregister_framebuffer(info); pdata = pdev->dev.platform_data; diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c index 3b1237ad85e..f6fdc2085f3 100644 --- a/drivers/video/omap2/vram.c +++ b/drivers/video/omap2/vram.c @@ -25,7 +25,7 @@ #include <linux/list.h> #include <linux/slab.h> #include <linux/seq_file.h> -#include <linux/bootmem.h> +#include <linux/memblock.h> #include <linux/completion.h> #include <linux/debugfs.h> #include <linux/jiffies.h> @@ -525,10 +525,8 @@ early_param("vram", omap_vram_early_vram); * Called from map_io. We need to call to this early enough so that we * can reserve the fixed SDRAM regions before VM could get hold of them. */ -void __init omap_vram_reserve_sdram(void) +void __init omap_vram_reserve_sdram_memblock(void) { - struct bootmem_data *bdata; - unsigned long sdram_start, sdram_size; u32 paddr; u32 size = 0; @@ -555,29 +553,28 @@ void __init omap_vram_reserve_sdram(void) size = PAGE_ALIGN(size); - bdata = NODE_DATA(0)->bdata; - sdram_start = bdata->node_min_pfn << PAGE_SHIFT; - sdram_size = (bdata->node_low_pfn << PAGE_SHIFT) - sdram_start; - if (paddr) { - if ((paddr & ~PAGE_MASK) || paddr < sdram_start || - paddr + size > sdram_start + sdram_size) { + struct memblock_property res; + + res.base = paddr; + res.size = size; + if ((paddr & ~PAGE_MASK) || memblock_find(&res) || + res.base != paddr || res.size != size) { pr_err("Illegal SDRAM region for VRAM\n"); return; } - if (reserve_bootmem(paddr, size, BOOTMEM_EXCLUSIVE) < 0) { - pr_err("FB: failed to reserve VRAM\n"); + if (memblock_is_region_reserved(paddr, size)) { + pr_err("FB: failed to reserve VRAM - busy\n"); return; } - } else { - if (size > sdram_size) { - pr_err("Illegal SDRAM size for VRAM\n"); + + if (memblock_reserve(paddr, size) < 0) { + pr_err("FB: failed to reserve VRAM - no memory\n"); return; } - - paddr = virt_to_phys(alloc_bootmem_pages(size)); - BUG_ON(paddr & ~PAGE_MASK); + } else { + paddr = memblock_alloc_base(size, PAGE_SIZE, MEMBLOCK_REAL_LIMIT); } omap_vram_add_region(paddr, size); diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c index 0f361b6100d..0c69fa20251 100644 --- a/drivers/video/pmag-ba-fb.c +++ b/drivers/video/pmag-ba-fb.c @@ -44,7 +44,7 @@ struct pmagbafb_par { }; -static struct fb_var_screeninfo pmagbafb_defined __initdata = { +static struct fb_var_screeninfo pmagbafb_defined __devinitdata = { .xres = 1024, .yres = 864, .xres_virtual = 1024, @@ -68,7 +68,7 @@ static struct fb_var_screeninfo pmagbafb_defined __initdata = { .vmode = FB_VMODE_NONINTERLACED, }; -static struct fb_fix_screeninfo pmagbafb_fix __initdata = { +static struct fb_fix_screeninfo pmagbafb_fix __devinitdata = { .id = "PMAG-BA", .smem_len = (1024 * 1024), .type = FB_TYPE_PACKED_PIXELS, @@ -142,7 +142,7 @@ static void __init pmagbafb_erase_cursor(struct fb_info *info) } -static int __init pmagbafb_probe(struct device *dev) +static int __devinit pmagbafb_probe(struct device *dev) { struct tc_dev *tdev = to_tc_dev(dev); resource_size_t start, len; diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c index 2de0806421b..22fcb9a3d5c 100644 --- a/drivers/video/pmagb-b-fb.c +++ b/drivers/video/pmagb-b-fb.c @@ -45,7 +45,7 @@ struct pmagbbfb_par { }; -static struct fb_var_screeninfo pmagbbfb_defined __initdata = { +static struct fb_var_screeninfo pmagbbfb_defined __devinitdata = { .bits_per_pixel = 8, .red.length = 8, .green.length = 8, @@ -58,7 +58,7 @@ static struct fb_var_screeninfo pmagbbfb_defined __initdata = { .vmode = FB_VMODE_NONINTERLACED, }; -static struct fb_fix_screeninfo pmagbbfb_fix __initdata = { +static struct fb_fix_screeninfo pmagbbfb_fix __devinitdata = { .id = "PMAGB-BA", .smem_len = (2048 * 1024), .type = FB_TYPE_PACKED_PIXELS, @@ -148,7 +148,7 @@ static void __init pmagbbfb_erase_cursor(struct fb_info *info) /* * Set up screen parameters. */ -static void __init pmagbbfb_screen_setup(struct fb_info *info) +static void __devinit pmagbbfb_screen_setup(struct fb_info *info) { struct pmagbbfb_par *par = info->par; @@ -180,9 +180,9 @@ static void __init pmagbbfb_screen_setup(struct fb_info *info) /* * Determine oscillator configuration. */ -static void __init pmagbbfb_osc_setup(struct fb_info *info) +static void __devinit pmagbbfb_osc_setup(struct fb_info *info) { - static unsigned int pmagbbfb_freqs[] __initdata = { + static unsigned int pmagbbfb_freqs[] __devinitdata = { 130808, 119843, 104000, 92980, 74370, 72800, 69197, 66000, 65000, 50350, 36000, 32000, 25175 }; @@ -247,7 +247,7 @@ static void __init pmagbbfb_osc_setup(struct fb_info *info) }; -static int __init pmagbbfb_probe(struct device *dev) +static int __devinit pmagbbfb_probe(struct device *dev) { struct tc_dev *tdev = to_tc_dev(dev); resource_size_t start, len; diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index afe7e21dd0a..1475ed6b575 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -164,7 +164,8 @@ int virtqueue_add_buf_gfp(struct virtqueue *_vq, gfp_t gfp) { struct vring_virtqueue *vq = to_vvq(_vq); - unsigned int i, avail, head, uninitialized_var(prev); + unsigned int i, avail, uninitialized_var(prev); + int head; START_USE(vq); @@ -174,7 +175,7 @@ int virtqueue_add_buf_gfp(struct virtqueue *_vq, * buffers, then go indirect. FIXME: tune this threshold */ if (vq->indirect && (out + in) > 1 && vq->num_free) { head = vring_add_indirect(vq, sg, out, in, gfp); - if (head != vq->vring.num) + if (likely(head >= 0)) goto add_head; } |