diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-06-30 15:23:59 +1000 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-06-30 15:23:59 +1000 |
commit | 6da49a292534d31ca391928ea97f8225774dc1e0 (patch) | |
tree | 060c5f5f40dceb10d4528763bc7fc1ccc88210d9 /drivers | |
parent | 17bdc6c0e979ae61879806e4dd93ec3b169d0931 (diff) | |
parent | ca56a95eedcc95f8fea7b49c87565cd961d74fe2 (diff) | |
download | op-kernel-dev-6da49a292534d31ca391928ea97f8225774dc1e0.zip op-kernel-dev-6da49a292534d31ca391928ea97f8225774dc1e0.tar.gz |
Merge remote branch 'origin/master' into next
Diffstat (limited to 'drivers')
272 files changed, 4135 insertions, 1207 deletions
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index d38c40f..41223c7 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -452,7 +452,7 @@ void ahci_save_initial_config(struct device *dev, } if (mask_port_map) { - dev_printk(KERN_ERR, dev, "masking port_map 0x%x -> 0x%x\n", + dev_printk(KERN_WARNING, dev, "masking port_map 0x%x -> 0x%x\n", port_map, port_map & mask_port_map); port_map &= mask_port_map; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 736bee5..000d03a 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4143,9 +4143,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { * Devices which choke on SETXFER. Applies only if both the * device and controller are SATA. */ - { "PIONEER DVD-RW DVRTD08", "1.00", ATA_HORKAGE_NOSETXFER }, - { "PIONEER DVD-RW DVR-212D", "1.28", ATA_HORKAGE_NOSETXFER }, - { "PIONEER DVD-RW DVR-216D", "1.08", ATA_HORKAGE_NOSETXFER }, + { "PIONEER DVD-RW DVRTD08", NULL, ATA_HORKAGE_NOSETXFER }, + { "PIONEER DVD-RW DVR-212D", NULL, ATA_HORKAGE_NOSETXFER }, + { "PIONEER DVD-RW DVR-216D", NULL, ATA_HORKAGE_NOSETXFER }, /* End Marker */ { } diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index dfb6e9d..7f099d6 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2802,10 +2802,11 @@ int ata_eh_reset(struct ata_link *link, int classify, } /* - * Some controllers can't be frozen very well and may set - * spuruious error conditions during reset. Clear accumulated - * error information. As reset is the final recovery action, - * nothing is lost by doing this. + * Some controllers can't be frozen very well and may set spurious + * error conditions during reset. Clear accumulated error + * information and re-thaw the port if frozen. As reset is the + * final recovery action and we cross check link onlineness against + * device classification later, no hotplug event is lost by this. */ spin_lock_irqsave(link->ap->lock, flags); memset(&link->eh_info, 0, sizeof(link->eh_info)); @@ -2814,6 +2815,9 @@ int ata_eh_reset(struct ata_link *link, int classify, ap->pflags &= ~ATA_PFLAG_EH_PENDING; spin_unlock_irqrestore(link->ap->lock, flags); + if (ap->pflags & ATA_PFLAG_FROZEN) + ata_eh_thaw_port(ap); + /* * Make sure onlineness and classification result correspond. * Hotplug could have happened during reset and some diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index d51f979..927f968 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3797,6 +3797,12 @@ EXPORT_SYMBOL_GPL(ata_sas_port_alloc); */ int ata_sas_port_start(struct ata_port *ap) { + /* + * the port is marked as frozen at allocation time, but if we don't + * have new eh, we won't thaw it + */ + if (!ap->ops->error_handler) + ap->pflags &= ~ATA_PFLAG_FROZEN; return 0; } EXPORT_SYMBOL_GPL(ata_sas_port_start); diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index 75a6a0c..5d7f58a 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -161,6 +161,9 @@ static const struct pci_device_id marvell_pci_tbl[] = { { PCI_DEVICE(0x11AB, 0x6121), }, { PCI_DEVICE(0x11AB, 0x6123), }, { PCI_DEVICE(0x11AB, 0x6145), }, + { PCI_DEVICE(0x1B4B, 0x91A0), }, + { PCI_DEVICE(0x1B4B, 0x91A4), }, + { } /* terminate list */ }; diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index 1c4b3aa..dc88a39 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -389,7 +389,7 @@ static void sata_dwc_tf_dump(struct ata_taskfile *tf) /* * Function: get_burst_length_encode * arguments: datalength: length in bytes of data - * returns value to be programmed in register corrresponding to data length + * returns value to be programmed in register corresponding to data length * This value is effectively the log(base 2) of the length */ static int get_burst_length_encode(int datalength) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 1c291af..6040717 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -367,7 +367,7 @@ EXPORT_SYMBOL_GPL(platform_device_unregister); * * Returns &struct platform_device pointer on success, or ERR_PTR() on error. */ -struct platform_device *__init_or_module platform_device_register_resndata( +struct platform_device *platform_device_register_resndata( struct device *parent, const char *name, int id, const struct resource *res, unsigned int num, diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index eaa8a85..ad367c4 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c @@ -387,7 +387,7 @@ static int pm_runtime_clk_notify(struct notifier_block *nb, clknb = container_of(nb, struct pm_clk_notifier_block, nb); switch (action) { - case BUS_NOTIFY_ADD_DEVICE: + case BUS_NOTIFY_BIND_DRIVER: if (clknb->con_ids[0]) { for (con_id = clknb->con_ids; *con_id; con_id++) enable_clock(dev, *con_id); @@ -395,7 +395,7 @@ static int pm_runtime_clk_notify(struct notifier_block *nb, enable_clock(dev, NULL); } break; - case BUS_NOTIFY_DEL_DEVICE: + case BUS_NOTIFY_UNBOUND_DRIVER: if (clknb->con_ids[0]) { for (con_id = clknb->con_ids; *con_id; con_id++) disable_clock(dev, *con_id); diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index aa632020..06f09bf 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -57,7 +57,8 @@ static int async_error; */ void device_pm_init(struct device *dev) { - dev->power.in_suspend = false; + dev->power.is_prepared = false; + dev->power.is_suspended = false; init_completion(&dev->power.completion); complete_all(&dev->power.completion); dev->power.wakeup = NULL; @@ -91,7 +92,7 @@ void device_pm_add(struct device *dev) pr_debug("PM: Adding info for %s:%s\n", dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); mutex_lock(&dpm_list_mtx); - if (dev->parent && dev->parent->power.in_suspend) + if (dev->parent && dev->parent->power.is_prepared) dev_warn(dev, "parent %s should not be sleeping\n", dev_name(dev->parent)); list_add_tail(&dev->power.entry, &dpm_list); @@ -511,7 +512,14 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) dpm_wait(dev->parent, async); device_lock(dev); - dev->power.in_suspend = false; + /* + * This is a fib. But we'll allow new children to be added below + * a resumed device, even if the device hasn't been completed yet. + */ + dev->power.is_prepared = false; + + if (!dev->power.is_suspended) + goto Unlock; if (dev->pwr_domain) { pm_dev_dbg(dev, state, "power domain "); @@ -548,6 +556,9 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) } End: + dev->power.is_suspended = false; + + Unlock: device_unlock(dev); complete_all(&dev->power.completion); @@ -670,7 +681,7 @@ void dpm_complete(pm_message_t state) struct device *dev = to_device(dpm_prepared_list.prev); get_device(dev); - dev->power.in_suspend = false; + dev->power.is_prepared = false; list_move(&dev->power.entry, &list); mutex_unlock(&dpm_list_mtx); @@ -835,11 +846,11 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) device_lock(dev); if (async_error) - goto End; + goto Unlock; if (pm_wakeup_pending()) { async_error = -EBUSY; - goto End; + goto Unlock; } if (dev->pwr_domain) { @@ -877,6 +888,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) } End: + dev->power.is_suspended = !error; + + Unlock: device_unlock(dev); complete_all(&dev->power.completion); @@ -1042,7 +1056,7 @@ int dpm_prepare(pm_message_t state) put_device(dev); break; } - dev->power.in_suspend = true; + dev->power.is_prepared = true; if (!list_empty(&dev->power.entry)) list_move_tail(&dev->power.entry, &dpm_prepared_list); put_device(dev); diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c index fd6305b..8ecf4c6 100644 --- a/drivers/bluetooth/btmrvl_debugfs.c +++ b/drivers/bluetooth/btmrvl_debugfs.c @@ -64,6 +64,8 @@ static ssize_t btmrvl_hscfgcmd_write(struct file *file, return -EFAULT; ret = strict_strtol(buf, 10, &result); + if (ret) + return ret; priv->btmrvl_dev.hscfgcmd = result; @@ -108,6 +110,8 @@ static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf, return -EFAULT; ret = strict_strtol(buf, 10, &result); + if (ret) + return ret; priv->btmrvl_dev.psmode = result; @@ -147,6 +151,8 @@ static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf, return -EFAULT; ret = strict_strtol(buf, 10, &result); + if (ret) + return ret; priv->btmrvl_dev.pscmd = result; @@ -191,6 +197,8 @@ static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf, return -EFAULT; ret = strict_strtol(buf, 16, &result); + if (ret) + return ret; priv->btmrvl_dev.gpio_gap = result; @@ -230,6 +238,8 @@ static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf, return -EFAULT; ret = strict_strtol(buf, 10, &result); + if (ret) + return ret; priv->btmrvl_dev.hscmd = result; if (priv->btmrvl_dev.hscmd) { @@ -272,6 +282,8 @@ static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf, return -EFAULT; ret = strict_strtol(buf, 10, &result); + if (ret) + return ret; priv->btmrvl_dev.hsmode = result; diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 051474c..34d6a1c 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -163,11 +163,32 @@ static irqreturn_t hpet_interrupt(int irq, void *data) * This has the effect of treating non-periodic like periodic. */ if ((devp->hd_flags & (HPET_IE | HPET_PERIODIC)) == HPET_IE) { - unsigned long m, t; + unsigned long m, t, mc, base, k; + struct hpet __iomem *hpet = devp->hd_hpet; + struct hpets *hpetp = devp->hd_hpets; t = devp->hd_ireqfreq; m = read_counter(&devp->hd_timer->hpet_compare); - write_counter(t + m, &devp->hd_timer->hpet_compare); + mc = read_counter(&hpet->hpet_mc); + /* The time for the next interrupt would logically be t + m, + * however, if we are very unlucky and the interrupt is delayed + * for longer than t then we will completely miss the next + * interrupt if we set t + m and an application will hang. + * Therefore we need to make a more complex computation assuming + * that there exists a k for which the following is true: + * k * t + base < mc + delta + * (k + 1) * t + base > mc + delta + * where t is the interval in hpet ticks for the given freq, + * base is the theoretical start value 0 < base < t, + * mc is the main counter value at the time of the interrupt, + * delta is the time it takes to write the a value to the + * comparator. + * k may then be computed as (mc - base + delta) / t . + */ + base = mc % t; + k = (mc - base + hpetp->hp_delta) / t; + write_counter(t * (k + 1) + base, + &devp->hd_timer->hpet_compare); } if (devp->hd_flags & HPET_SHARED_IRQ) diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index 219d88a..dde6a0f 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -139,6 +139,7 @@ static int cn_call_callback(struct sk_buff *skb) spin_unlock_bh(&dev->cbdev->queue_lock); if (cbq != NULL) { + err = 0; cbq->callback(msg, nsp); kfree_skb(skb); cn_queue_release_callback(cbq); diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index b60a4c2..faf7c52 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -298,11 +298,13 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb, old_index = stat->last_index; new_index = freq_table_get_index(stat, freq->new); - cpufreq_stats_update(freq->cpu); - if (old_index == new_index) + /* We can't do stat->time_in_state[-1]= .. */ + if (old_index == -1 || new_index == -1) return 0; - if (old_index == -1 || new_index == -1) + cpufreq_stats_update(freq->cpu); + + if (old_index == new_index) return 0; spin_lock(&cpufreq_stats_lock); @@ -387,6 +389,7 @@ static void __exit cpufreq_stats_exit(void) unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier); for_each_online_cpu(cpu) { cpufreq_stats_free_table(cpu); + cpufreq_stats_free_sysfs(cpu); } } diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index 83479b6..bce576d 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -1079,6 +1079,9 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data, } res = transition_fid_vid(data, fid, vid); + if (res) + return res; + freqs.new = find_khz_freq_from_fid(data->currfid); for_each_cpu(i, data->available_cores) { @@ -1101,7 +1104,8 @@ static int transition_frequency_pstate(struct powernow_k8_data *data, /* get MSR index for hardware pstate transition */ pstate = index & HW_PSTATE_MASK; if (pstate > data->max_hw_pstate) - return 0; + return -EINVAL; + freqs.old = find_khz_freq_from_pstate(data->powernow_table, data->currpstate); freqs.new = find_khz_freq_from_pstate(data->powernow_table, pstate); diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index d0e65d6..676d957 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -238,9 +238,9 @@ static int build_sh_desc_ipsec(struct caam_ctx *ctx) /* build shared descriptor for this session */ sh_desc = kmalloc(CAAM_CMD_SZ * DESC_AEAD_SHARED_TEXT_LEN + - keys_fit_inline ? - ctx->split_key_pad_len + ctx->enckeylen : - CAAM_PTR_SZ * 2, GFP_DMA | GFP_KERNEL); + (keys_fit_inline ? + ctx->split_key_pad_len + ctx->enckeylen : + CAAM_PTR_SZ * 2), GFP_DMA | GFP_KERNEL); if (!sh_desc) { dev_err(jrdev, "could not allocate shared descriptor\n"); return -ENOMEM; diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index 2a638f9..0283300 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -1221,6 +1221,11 @@ static int __init sh_dmae_probe(struct platform_device *pdev) } else { do { for (i = chanirq_res->start; i <= chanirq_res->end; i++) { + if (irq_cnt >= SH_DMAC_MAX_CHANNELS) { + irq_cap = 1; + break; + } + if ((errirq_res->flags & IORESOURCE_BITS) == IORESOURCE_IRQ_SHAREABLE) chan_flag[irq_cnt] = IRQF_SHARED; @@ -1230,15 +1235,11 @@ static int __init sh_dmae_probe(struct platform_device *pdev) "Found IRQ %d for channel %d\n", i, irq_cnt); chan_irq[irq_cnt++] = i; - - if (irq_cnt >= SH_DMAC_MAX_CHANNELS) - break; } - if (irq_cnt >= SH_DMAC_MAX_CHANNELS) { - irq_cap = 1; + if (irq_cnt >= SH_DMAC_MAX_CHANNELS) break; - } + chanirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, ++irqres); } while (irq_cnt < pdata->channel_num && chanirq_res); diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig index 87096b6..2f21b0b 100644 --- a/drivers/firmware/google/Kconfig +++ b/drivers/firmware/google/Kconfig @@ -13,6 +13,7 @@ menu "Google Firmware Drivers" config GOOGLE_SMI tristate "SMI interface for Google platforms" depends on ACPI && DMI + select EFI select EFI_VARS help Say Y here if you want to enable SMI callbacks for Google diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c index f032e44..bfe7232 100644 --- a/drivers/firmware/iscsi_ibft_find.c +++ b/drivers/firmware/iscsi_ibft_find.c @@ -108,7 +108,9 @@ done: */ unsigned long __init find_ibft_region(unsigned long *sizep) { +#ifdef CONFIG_ACPI int i; +#endif ibft_addr = NULL; #ifdef CONFIG_ACPI diff --git a/drivers/gpio/gpio-nomadik.c b/drivers/gpio/gpio-nomadik.c index 4961ef9..2c212c7 100644 --- a/drivers/gpio/gpio-nomadik.c +++ b/drivers/gpio/gpio-nomadik.c @@ -4,6 +4,7 @@ * Copyright (C) 2008,2009 STMicroelectronics * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it> * Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com> + * Copyright (C) 2011 Linus Walleij <linus.walleij@linaro.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -49,6 +50,7 @@ struct nmk_gpio_chip { u32 (*get_secondary_status)(unsigned int bank); void (*set_ioforce)(bool enable); spinlock_t lock; + bool sleepmode; /* Keep track of configured edges */ u32 edge_rising; u32 edge_falling; @@ -393,14 +395,25 @@ EXPORT_SYMBOL(nmk_config_pins_sleep); * @gpio: pin number * @mode: NMK_GPIO_SLPM_INPUT or NMK_GPIO_SLPM_NOCHANGE, * - * Sets the sleep mode of a pin. If @mode is NMK_GPIO_SLPM_INPUT, the pin is - * changed to an input (with pullup/down enabled) in sleep and deep sleep. If - * @mode is NMK_GPIO_SLPM_NOCHANGE, the pin remains in the state it was - * configured even when in sleep and deep sleep. + * This register is actually in the pinmux layer, not the GPIO block itself. + * The GPIO1B_SLPM register defines the GPIO mode when SLEEP/DEEP-SLEEP + * mode is entered (i.e. when signal IOFORCE is HIGH by the platform code). + * Each GPIO can be configured to be forced into GPIO mode when IOFORCE is + * HIGH, overriding the normal setting defined by GPIO_AFSELx registers. + * When IOFORCE returns LOW (by software, after SLEEP/DEEP-SLEEP exit), + * the GPIOs return to the normal setting defined by GPIO_AFSELx registers. * - * On DB8500v2 onwards, this setting loses the previous meaning and instead - * indicates if wakeup detection is enabled on the pin. Note that - * enable_irq_wake() will automatically enable wakeup detection. + * If @mode is NMK_GPIO_SLPM_INPUT, the corresponding GPIO is switched to GPIO + * mode when signal IOFORCE is HIGH (i.e. when SLEEP/DEEP-SLEEP mode is + * entered) regardless of the altfunction selected. Also wake-up detection is + * ENABLED. + * + * If @mode is NMK_GPIO_SLPM_NOCHANGE, the corresponding GPIO remains + * controlled by NMK_GPIO_DATC, NMK_GPIO_DATS, NMK_GPIO_DIR, NMK_GPIO_PDIS + * (for altfunction GPIO) or respective on-chip peripherals (for other + * altfuncs) when IOFORCE is HIGH. Also wake-up detection DISABLED. + * + * Note that enable_irq_wake() will automatically enable wakeup detection. */ int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode) { @@ -551,6 +564,12 @@ static void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip, static void __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip, int gpio, bool on) { + if (nmk_chip->sleepmode) { + __nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base, + on ? NMK_GPIO_SLPM_WAKEUP_ENABLE + : NMK_GPIO_SLPM_WAKEUP_DISABLE); + } + __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on); } @@ -901,7 +920,7 @@ void nmk_gpio_wakeups_suspend(void) writel(chip->fwimsc & chip->real_wake, chip->addr + NMK_GPIO_FWIMSC); - if (cpu_is_u8500v2()) { + if (chip->sleepmode) { chip->slpm = readl(chip->addr + NMK_GPIO_SLPC); /* 0 -> wakeup enable */ @@ -923,7 +942,7 @@ void nmk_gpio_wakeups_resume(void) writel(chip->rwimsc, chip->addr + NMK_GPIO_RWIMSC); writel(chip->fwimsc, chip->addr + NMK_GPIO_FWIMSC); - if (cpu_is_u8500v2()) + if (chip->sleepmode) writel(chip->slpm, chip->addr + NMK_GPIO_SLPC); } } @@ -1010,6 +1029,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) nmk_chip->secondary_parent_irq = secondary_irq; nmk_chip->get_secondary_status = pdata->get_secondary_status; nmk_chip->set_ioforce = pdata->set_ioforce; + nmk_chip->sleepmode = pdata->supports_sleepmode; spin_lock_init(&nmk_chip->lock); chip = &nmk_chip->chip; @@ -1065,5 +1085,3 @@ core_initcall(nmk_gpio_init); MODULE_AUTHOR("Prafulla WADASKAR and Alessandro Rubini"); MODULE_DESCRIPTION("Nomadik GPIO Driver"); MODULE_LICENSE("GPL"); - - diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 01f74a8..35bebde 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -469,8 +469,9 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, + OMAP24XX_GPIO_CLEARWKUENA); } } - /* This part needs to be executed always for OMAP34xx */ - if (cpu_is_omap34xx() || (bank->non_wakeup_gpios & gpio_bit)) { + /* This part needs to be executed always for OMAP{34xx, 44xx} */ + if (cpu_is_omap34xx() || cpu_is_omap44xx() || + (bank->non_wakeup_gpios & gpio_bit)) { /* * Log the edge gpio and manually trigger the IRQ * after resume if the input level changes diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index 3e257a5..61e1ef9 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -46,10 +46,11 @@ static struct drm_map_list *drm_find_matching_map(struct drm_device *dev, list_for_each_entry(entry, &dev->maplist, head) { /* * Because the kernel-userspace ABI is fixed at a 32-bit offset - * while PCI resources may live above that, we ignore the map - * offset for maps of type _DRM_FRAMEBUFFER or _DRM_REGISTERS. - * It is assumed that each driver will have only one resource of - * each type. + * while PCI resources may live above that, we only compare the + * lower 32 bits of the map offset for maps of type + * _DRM_FRAMEBUFFER or _DRM_REGISTERS. + * It is assumed that if a driver have more than one resource + * of each type, the lower 32 bits are different. */ if (!entry->map || map->type != entry->map->type || @@ -59,9 +60,12 @@ static struct drm_map_list *drm_find_matching_map(struct drm_device *dev, case _DRM_SHM: if (map->flags != _DRM_CONTAINS_LOCK) break; + return entry; case _DRM_REGISTERS: case _DRM_FRAME_BUFFER: - return entry; + if ((entry->map->offset & 0xffffffff) == + (map->offset & 0xffffffff)) + return entry; default: /* Make gcc happy */ ; } @@ -183,9 +187,6 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, return -EINVAL; } #endif -#ifdef __alpha__ - map->offset += dev->hose->mem_space->start; -#endif /* Some drivers preinitialize some maps, without the X Server * needing to be aware of it. Therefore, we just return success * when the server tries to create a duplicate map. diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 872747c..21058e6 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1113,7 +1113,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, if (card_res->count_fbs >= fb_count) { copied = 0; fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr; - list_for_each_entry(fb, &file_priv->fbs, head) { + list_for_each_entry(fb, &file_priv->fbs, filp_head) { if (put_user(fb->base.id, fb_id + copied)) { ret = -EFAULT; goto out; diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 0a9357c..0929219 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -184,9 +184,9 @@ drm_edid_block_valid(u8 *raw_edid) bad: if (raw_edid) { - DRM_ERROR("Raw EDID:\n"); + printk(KERN_ERR "Raw EDID:\n"); print_hex_dump_bytes(KERN_ERR, DUMP_PREFIX_NONE, raw_edid, EDID_LENGTH); - printk("\n"); + printk(KERN_ERR "\n"); } return 0; } @@ -258,6 +258,17 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf, return ret == 2 ? 0 : -1; } +static bool drm_edid_is_zero(u8 *in_edid, int length) +{ + int i; + u32 *raw_edid = (u32 *)in_edid; + + for (i = 0; i < length / 4; i++) + if (*(raw_edid + i) != 0) + return false; + return true; +} + static u8 * drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) { @@ -273,6 +284,10 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) goto out; if (drm_edid_block_valid(block)) break; + if (i == 0 && drm_edid_is_zero(block, EDID_LENGTH)) { + connector->null_edid_counter++; + goto carp; + } } if (i == 4) goto carp; diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 74e4ff5..4012fe4 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -34,6 +34,7 @@ #include <linux/module.h> #include <linux/mman.h> #include <linux/pagemap.h> +#include <linux/shmem_fs.h> #include "drmP.h" /** @file drm_gem.c diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index d61d185..4a058c7 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -28,6 +28,7 @@ * IN THE SOFTWARE. */ #include <linux/compat.h> +#include <linux/ratelimit.h> #include "drmP.h" #include "drm_core.h" @@ -253,10 +254,10 @@ static int compat_drm_addmap(struct file *file, unsigned int cmd, return -EFAULT; m32.handle = (unsigned long)handle; - if (m32.handle != (unsigned long)handle && printk_ratelimit()) - printk(KERN_ERR "compat_drm_addmap truncated handle" - " %p for type %d offset %x\n", - handle, m32.type, m32.offset); + if (m32.handle != (unsigned long)handle) + printk_ratelimited(KERN_ERR "compat_drm_addmap truncated handle" + " %p for type %d offset %x\n", + handle, m32.type, m32.offset); if (copy_to_user(argp, &m32, sizeof(m32))) return -EFAULT; diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index e1aee4f..b6a19cb 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -251,7 +251,7 @@ err: } -int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p) +static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p) { if ((p->busnum >> 8) != drm_get_pci_domain(dev) || (p->busnum & 0xff) != dev->pdev->bus->number || @@ -292,6 +292,7 @@ static struct drm_bus drm_pci_bus = { .get_name = drm_pci_get_name, .set_busid = drm_pci_set_busid, .set_unique = drm_pci_set_unique, + .irq_by_busid = drm_pci_irq_by_busid, .agp_init = drm_pci_agp_init, }; diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c index 2c3fcbd..5db96d45 100644 --- a/drivers/gpu/drm/drm_vm.c +++ b/drivers/gpu/drm/drm_vm.c @@ -526,7 +526,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) static resource_size_t drm_core_get_reg_ofs(struct drm_device *dev) { #ifdef __alpha__ - return dev->hose->dense_mem_base - dev->hose->mem_space->start; + return dev->hose->dense_mem_base; #else return 0; #endif diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 0239e99..2b79588 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2182,9 +2182,8 @@ int i915_driver_unload(struct drm_device *dev) /* Flush any outstanding unpin_work. */ flush_workqueue(dev_priv->wq); - i915_gem_free_all_phys_object(dev); - mutex_lock(&dev->struct_mutex); + i915_gem_free_all_phys_object(dev); i915_gem_cleanup_ringbuffer(dev); mutex_unlock(&dev->struct_mutex); if (I915_HAS_FBC(dev) && i915_powersave) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 0defd42..609358f 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -579,6 +579,9 @@ int i915_reset(struct drm_device *dev, u8 flags) } else switch (INTEL_INFO(dev)->gen) { case 6: ret = gen6_do_reset(dev, flags); + /* If reset with a user forcewake, try to restore */ + if (atomic_read(&dev_priv->forcewake_count)) + __gen6_gt_force_wake_get(dev_priv); break; case 5: ret = ironlake_do_reset(dev, flags); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f63ee16..eddabf6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -211,6 +211,9 @@ struct drm_i915_display_funcs { void (*fdi_link_train)(struct drm_crtc *crtc); void (*init_clock_gating)(struct drm_device *dev); void (*init_pch_clock_gating)(struct drm_device *dev); + int (*queue_flip)(struct drm_device *dev, struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj); /* clock updates for mode set */ /* cursor updates */ /* render clock increase/decrease */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 12d3257..5c0d124 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -31,6 +31,7 @@ #include "i915_drv.h" #include "i915_trace.h" #include "intel_drv.h" +#include <linux/shmem_fs.h> #include <linux/slab.h> #include <linux/swap.h> #include <linux/pci.h> @@ -359,8 +360,7 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, if ((page_offset + remain) > PAGE_SIZE) page_length = PAGE_SIZE - page_offset; - page = read_cache_page_gfp(mapping, offset >> PAGE_SHIFT, - GFP_HIGHUSER | __GFP_RECLAIMABLE); + page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT); if (IS_ERR(page)) return PTR_ERR(page); @@ -463,10 +463,11 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, if ((data_page_offset + page_length) > PAGE_SIZE) page_length = PAGE_SIZE - data_page_offset; - page = read_cache_page_gfp(mapping, offset >> PAGE_SHIFT, - GFP_HIGHUSER | __GFP_RECLAIMABLE); - if (IS_ERR(page)) - return PTR_ERR(page); + page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT); + if (IS_ERR(page)) { + ret = PTR_ERR(page); + goto out; + } if (do_bit17_swizzling) { slow_shmem_bit17_copy(page, @@ -795,8 +796,7 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev, if ((page_offset + remain) > PAGE_SIZE) page_length = PAGE_SIZE - page_offset; - page = read_cache_page_gfp(mapping, offset >> PAGE_SHIFT, - GFP_HIGHUSER | __GFP_RECLAIMABLE); + page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT); if (IS_ERR(page)) return PTR_ERR(page); @@ -905,8 +905,7 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, if ((data_page_offset + page_length) > PAGE_SIZE) page_length = PAGE_SIZE - data_page_offset; - page = read_cache_page_gfp(mapping, offset >> PAGE_SHIFT, - GFP_HIGHUSER | __GFP_RECLAIMABLE); + page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT); if (IS_ERR(page)) { ret = PTR_ERR(page); goto out; @@ -1217,11 +1216,11 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ret = i915_gem_object_bind_to_gtt(obj, 0, true); if (ret) goto unlock; - } - ret = i915_gem_object_set_to_gtt_domain(obj, write); - if (ret) - goto unlock; + ret = i915_gem_object_set_to_gtt_domain(obj, write); + if (ret) + goto unlock; + } if (obj->tiling_mode == I915_TILING_NONE) ret = i915_gem_object_put_fence(obj); @@ -1556,12 +1555,10 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj, inode = obj->base.filp->f_path.dentry->d_inode; mapping = inode->i_mapping; + gfpmask |= mapping_gfp_mask(mapping); + for (i = 0; i < page_count; i++) { - page = read_cache_page_gfp(mapping, i, - GFP_HIGHUSER | - __GFP_COLD | - __GFP_RECLAIMABLE | - gfpmask); + page = shmem_read_mapping_page_gfp(mapping, i, gfpmask); if (IS_ERR(page)) goto err_pages; @@ -1699,13 +1696,10 @@ i915_gem_object_truncate(struct drm_i915_gem_object *obj) /* Our goal here is to return as much of the memory as * is possible back to the system as we are called from OOM. * To do this we must instruct the shmfs to drop all of its - * backing pages, *now*. Here we mirror the actions taken - * when by shmem_delete_inode() to release the backing store. + * backing pages, *now*. */ inode = obj->base.filp->f_path.dentry->d_inode; - truncate_inode_pages(inode->i_mapping, 0); - if (inode->i_op->truncate_range) - inode->i_op->truncate_range(inode, 0, (loff_t)-1); + shmem_truncate_range(inode, 0, (loff_t)-1); obj->madv = __I915_MADV_PURGED; } @@ -2078,8 +2072,8 @@ i915_wait_request(struct intel_ring_buffer *ring, if (!ier) { DRM_ERROR("something (likely vbetool) disabled " "interrupts, re-enabling\n"); - i915_driver_irq_preinstall(ring->dev); - i915_driver_irq_postinstall(ring->dev); + ring->dev->driver->irq_preinstall(ring->dev); + ring->dev->driver->irq_postinstall(ring->dev); } trace_i915_gem_request_wait_begin(ring, seqno); @@ -2924,8 +2918,6 @@ i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj) */ wmb(); - i915_gem_release_mmap(obj); - old_write_domain = obj->base.write_domain; obj->base.write_domain = 0; @@ -3565,6 +3557,7 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; + struct address_space *mapping; obj = kzalloc(sizeof(*obj), GFP_KERNEL); if (obj == NULL) @@ -3575,6 +3568,9 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, return NULL; } + mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping; + mapping_set_gfp_mask(mapping, GFP_HIGHUSER | __GFP_RECLAIMABLE); + i915_gem_info_add_obj(dev_priv, size); obj->base.write_domain = I915_GEM_DOMAIN_CPU; @@ -3950,8 +3946,7 @@ void i915_gem_detach_phys_object(struct drm_device *dev, page_count = obj->base.size / PAGE_SIZE; for (i = 0; i < page_count; i++) { - struct page *page = read_cache_page_gfp(mapping, i, - GFP_HIGHUSER | __GFP_RECLAIMABLE); + struct page *page = shmem_read_mapping_page(mapping, i); if (!IS_ERR(page)) { char *dst = kmap_atomic(page); memcpy(dst, vaddr + i*PAGE_SIZE, PAGE_SIZE); @@ -4012,8 +4007,7 @@ i915_gem_attach_phys_object(struct drm_device *dev, struct page *page; char *dst, *src; - page = read_cache_page_gfp(mapping, i, - GFP_HIGHUSER | __GFP_RECLAIMABLE); + page = shmem_read_mapping_page(mapping, i); if (IS_ERR(page)) return PTR_ERR(page); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 20a4cc5..4934cf8 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -187,10 +187,6 @@ i915_gem_object_set_to_gpu_domain(struct drm_i915_gem_object *obj, if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) i915_gem_clflush_object(obj); - /* blow away mappings if mapped through GTT */ - if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_GTT) - i915_gem_release_mmap(obj); - if (obj->base.pending_write_domain) cd->flips |= atomic_read(&obj->pending_flip); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b9fafe3..ae2b499 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1740,6 +1740,17 @@ void ironlake_irq_preinstall(struct drm_device *dev) INIT_WORK(&dev_priv->rps_work, gen6_pm_rps_work); I915_WRITE(HWSTAM, 0xeffe); + if (IS_GEN6(dev)) { + /* Workaround stalls observed on Sandy Bridge GPUs by + * making the blitter command streamer generate a + * write to the Hardware Status Page for + * MI_USER_INTERRUPT. This appears to serialize the + * previous seqno write out before the interrupt + * happens. + */ + I915_WRITE(GEN6_BLITTER_HWSTAM, ~GEN6_BLITTER_USER_INTERRUPT); + I915_WRITE(GEN6_BSD_HWSTAM, ~GEN6_BSD_USER_INTERRUPT); + } /* XXX hotplug from PCH */ diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2f967af..5d5def7 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -531,6 +531,7 @@ #define GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE 0 #define GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR (1 << 3) +#define GEN6_BSD_HWSTAM 0x12098 #define GEN6_BSD_IMR 0x120a8 #define GEN6_BSD_USER_INTERRUPT (1 << 12) diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 60a94d2..e8152d2 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -678,6 +678,7 @@ void i915_save_display(struct drm_device *dev) } /* VGA state */ + mutex_lock(&dev->struct_mutex); dev_priv->saveVGA0 = I915_READ(VGA0); dev_priv->saveVGA1 = I915_READ(VGA1); dev_priv->saveVGA_PD = I915_READ(VGA_PD); @@ -687,6 +688,7 @@ void i915_save_display(struct drm_device *dev) dev_priv->saveVGACNTRL = I915_READ(VGACNTRL); i915_save_vga(dev); + mutex_unlock(&dev->struct_mutex); } void i915_restore_display(struct drm_device *dev) @@ -780,6 +782,8 @@ void i915_restore_display(struct drm_device *dev) I915_WRITE(CPU_VGACNTRL, dev_priv->saveVGACNTRL); else I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL); + + mutex_lock(&dev->struct_mutex); I915_WRITE(VGA0, dev_priv->saveVGA0); I915_WRITE(VGA1, dev_priv->saveVGA1); I915_WRITE(VGA_PD, dev_priv->saveVGA_PD); @@ -787,6 +791,7 @@ void i915_restore_display(struct drm_device *dev) udelay(150); i915_restore_vga(dev); + mutex_unlock(&dev->struct_mutex); } int i915_save_state(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 81a9059..21b6f93 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4687,6 +4687,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(DSPCNTR(plane), dspcntr); POSTING_READ(DSPCNTR(plane)); + intel_enable_plane(dev_priv, plane, pipe); ret = intel_pipe_set_base(crtc, x, y, old_fb); @@ -5217,8 +5218,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(DSPCNTR(plane), dspcntr); POSTING_READ(DSPCNTR(plane)); - if (!HAS_PCH_SPLIT(dev)) - intel_enable_plane(dev_priv, plane, pipe); ret = intel_pipe_set_base(crtc, x, y, old_fb); @@ -6262,6 +6261,197 @@ void intel_prepare_page_flip(struct drm_device *dev, int plane) spin_unlock_irqrestore(&dev->event_lock, flags); } +static int intel_gen2_queue_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + unsigned long offset; + u32 flip_mask; + int ret; + + ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv)); + if (ret) + goto out; + + /* Offset into the new buffer for cases of shared fbs between CRTCs */ + offset = crtc->y * fb->pitch + crtc->x * fb->bits_per_pixel/8; + + ret = BEGIN_LP_RING(6); + if (ret) + goto out; + + /* Can't queue multiple flips, so wait for the previous + * one to finish before executing the next. + */ + if (intel_crtc->plane) + flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; + else + flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; + OUT_RING(MI_WAIT_FOR_EVENT | flip_mask); + OUT_RING(MI_NOOP); + OUT_RING(MI_DISPLAY_FLIP | + MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); + OUT_RING(fb->pitch); + OUT_RING(obj->gtt_offset + offset); + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); +out: + return ret; +} + +static int intel_gen3_queue_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + unsigned long offset; + u32 flip_mask; + int ret; + + ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv)); + if (ret) + goto out; + + /* Offset into the new buffer for cases of shared fbs between CRTCs */ + offset = crtc->y * fb->pitch + crtc->x * fb->bits_per_pixel/8; + + ret = BEGIN_LP_RING(6); + if (ret) + goto out; + + if (intel_crtc->plane) + flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; + else + flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; + OUT_RING(MI_WAIT_FOR_EVENT | flip_mask); + OUT_RING(MI_NOOP); + OUT_RING(MI_DISPLAY_FLIP_I915 | + MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); + OUT_RING(fb->pitch); + OUT_RING(obj->gtt_offset + offset); + OUT_RING(MI_NOOP); + + ADVANCE_LP_RING(); +out: + return ret; +} + +static int intel_gen4_queue_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + uint32_t pf, pipesrc; + int ret; + + ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv)); + if (ret) + goto out; + + ret = BEGIN_LP_RING(4); + if (ret) + goto out; + + /* i965+ uses the linear or tiled offsets from the + * Display Registers (which do not change across a page-flip) + * so we need only reprogram the base address. + */ + OUT_RING(MI_DISPLAY_FLIP | + MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); + OUT_RING(fb->pitch); + OUT_RING(obj->gtt_offset | obj->tiling_mode); + + /* XXX Enabling the panel-fitter across page-flip is so far + * untested on non-native modes, so ignore it for now. + * pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE; + */ + pf = 0; + pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; + OUT_RING(pf | pipesrc); + ADVANCE_LP_RING(); +out: + return ret; +} + +static int intel_gen6_queue_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + uint32_t pf, pipesrc; + int ret; + + ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv)); + if (ret) + goto out; + + ret = BEGIN_LP_RING(4); + if (ret) + goto out; + + OUT_RING(MI_DISPLAY_FLIP | + MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); + OUT_RING(fb->pitch | obj->tiling_mode); + OUT_RING(obj->gtt_offset); + + pf = I915_READ(PF_CTL(intel_crtc->pipe)) & PF_ENABLE; + pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; + OUT_RING(pf | pipesrc); + ADVANCE_LP_RING(); +out: + return ret; +} + +/* + * On gen7 we currently use the blit ring because (in early silicon at least) + * the render ring doesn't give us interrpts for page flip completion, which + * means clients will hang after the first flip is queued. Fortunately the + * blit ring generates interrupts properly, so use it instead. + */ +static int intel_gen7_queue_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_ring_buffer *ring = &dev_priv->ring[BCS]; + int ret; + + ret = intel_pin_and_fence_fb_obj(dev, obj, ring); + if (ret) + goto out; + + ret = intel_ring_begin(ring, 4); + if (ret) + goto out; + + intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | (intel_crtc->plane << 19)); + intel_ring_emit(ring, (fb->pitch | obj->tiling_mode)); + intel_ring_emit(ring, (obj->gtt_offset)); + intel_ring_emit(ring, (MI_NOOP)); + intel_ring_advance(ring); +out: + return ret; +} + +static int intel_default_queue_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj) +{ + return -ENODEV; +} + static int intel_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event) @@ -6272,9 +6462,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, struct drm_i915_gem_object *obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_unpin_work *work; - unsigned long flags, offset; - int pipe = intel_crtc->pipe; - u32 pf, pipesrc; + unsigned long flags; int ret; work = kzalloc(sizeof *work, GFP_KERNEL); @@ -6303,9 +6491,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, obj = intel_fb->obj; mutex_lock(&dev->struct_mutex); - ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv)); - if (ret) - goto cleanup_work; /* Reference the objects for the scheduled work. */ drm_gem_object_reference(&work->old_fb_obj->base); @@ -6317,91 +6502,18 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, if (ret) goto cleanup_objs; - if (IS_GEN3(dev) || IS_GEN2(dev)) { - u32 flip_mask; - - /* Can't queue multiple flips, so wait for the previous - * one to finish before executing the next. - */ - ret = BEGIN_LP_RING(2); - if (ret) - goto cleanup_objs; - - if (intel_crtc->plane) - flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; - else - flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; - OUT_RING(MI_WAIT_FOR_EVENT | flip_mask); - OUT_RING(MI_NOOP); - ADVANCE_LP_RING(); - } - work->pending_flip_obj = obj; work->enable_stall_check = true; - /* Offset into the new buffer for cases of shared fbs between CRTCs */ - offset = crtc->y * fb->pitch + crtc->x * fb->bits_per_pixel/8; - - ret = BEGIN_LP_RING(4); - if (ret) - goto cleanup_objs; - /* Block clients from rendering to the new back buffer until * the flip occurs and the object is no longer visible. */ atomic_add(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip); - switch (INTEL_INFO(dev)->gen) { - case 2: - OUT_RING(MI_DISPLAY_FLIP | - MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); - OUT_RING(fb->pitch); - OUT_RING(obj->gtt_offset + offset); - OUT_RING(MI_NOOP); - break; - - case 3: - OUT_RING(MI_DISPLAY_FLIP_I915 | - MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); - OUT_RING(fb->pitch); - OUT_RING(obj->gtt_offset + offset); - OUT_RING(MI_NOOP); - break; - - case 4: - case 5: - /* i965+ uses the linear or tiled offsets from the - * Display Registers (which do not change across a page-flip) - * so we need only reprogram the base address. - */ - OUT_RING(MI_DISPLAY_FLIP | - MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); - OUT_RING(fb->pitch); - OUT_RING(obj->gtt_offset | obj->tiling_mode); - - /* XXX Enabling the panel-fitter across page-flip is so far - * untested on non-native modes, so ignore it for now. - * pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE; - */ - pf = 0; - pipesrc = I915_READ(PIPESRC(pipe)) & 0x0fff0fff; - OUT_RING(pf | pipesrc); - break; - - case 6: - case 7: - OUT_RING(MI_DISPLAY_FLIP | - MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); - OUT_RING(fb->pitch | obj->tiling_mode); - OUT_RING(obj->gtt_offset); - - pf = I915_READ(PF_CTL(pipe)) & PF_ENABLE; - pipesrc = I915_READ(PIPESRC(pipe)) & 0x0fff0fff; - OUT_RING(pf | pipesrc); - break; - } - ADVANCE_LP_RING(); + ret = dev_priv->display.queue_flip(dev, crtc, fb, obj); + if (ret) + goto cleanup_pending; mutex_unlock(&dev->struct_mutex); @@ -6409,10 +6521,11 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, return 0; +cleanup_pending: + atomic_sub(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip); cleanup_objs: drm_gem_object_unreference(&work->old_fb_obj->base); drm_gem_object_unreference(&obj->base); -cleanup_work: mutex_unlock(&dev->struct_mutex); spin_lock_irqsave(&dev->event_lock, flags); @@ -7657,6 +7770,31 @@ static void intel_init_display(struct drm_device *dev) else dev_priv->display.get_fifo_size = i830_get_fifo_size; } + + /* Default just returns -ENODEV to indicate unsupported */ + dev_priv->display.queue_flip = intel_default_queue_flip; + + switch (INTEL_INFO(dev)->gen) { + case 2: + dev_priv->display.queue_flip = intel_gen2_queue_flip; + break; + + case 3: + dev_priv->display.queue_flip = intel_gen3_queue_flip; + break; + + case 4: + case 5: + dev_priv->display.queue_flip = intel_gen4_queue_flip; + break; + + case 6: + dev_priv->display.queue_flip = intel_gen6_queue_flip; + break; + case 7: + dev_priv->display.queue_flip = intel_gen7_queue_flip; + break; + } } /* diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index d3b903b..d98cee6 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -401,8 +401,7 @@ int intel_setup_gmbus(struct drm_device *dev) bus->reg0 = i | GMBUS_RATE_100KHZ; /* XXX force bit banging until GMBUS is fully debugged */ - if (IS_GEN2(dev)) - bus->force_bit = intel_gpio_create(dev_priv, i); + bus->force_bit = intel_gpio_create(dev_priv, i); } intel_i2c_reset(dev_priv->dev); diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index a670c00..56a8e2a 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -1416,6 +1416,8 @@ void intel_setup_overlay(struct drm_device *dev) goto out_free; overlay->reg_bo = reg_bo; + mutex_lock(&dev->struct_mutex); + if (OVERLAY_NEEDS_PHYSICAL(dev)) { ret = i915_gem_attach_phys_object(dev, reg_bo, I915_GEM_PHYS_OVERLAY_REGS, @@ -1440,6 +1442,8 @@ void intel_setup_overlay(struct drm_device *dev) } } + mutex_unlock(&dev->struct_mutex); + /* init all values */ overlay->color_key = 0x0101fe; overlay->brightness = -19; @@ -1464,6 +1468,7 @@ out_unpin_bo: i915_gem_object_unpin(reg_bo); out_free_bo: drm_gem_object_unreference(®_bo->base); + mutex_unlock(&dev->struct_mutex); out_free: kfree(overlay); return; diff --git a/drivers/gpu/drm/mga/mga_drv.h b/drivers/gpu/drm/mga/mga_drv.h index 1084fa4..54558a0 100644 --- a/drivers/gpu/drm/mga/mga_drv.h +++ b/drivers/gpu/drm/mga/mga_drv.h @@ -195,29 +195,10 @@ extern long mga_compat_ioctl(struct file *filp, unsigned int cmd, #define mga_flush_write_combine() DRM_WRITEMEMORYBARRIER() -#if defined(__linux__) && defined(__alpha__) -#define MGA_BASE(reg) ((unsigned long)(dev_priv->mmio->handle)) -#define MGA_ADDR(reg) (MGA_BASE(reg) + reg) - -#define MGA_DEREF(reg) (*(volatile u32 *)MGA_ADDR(reg)) -#define MGA_DEREF8(reg) (*(volatile u8 *)MGA_ADDR(reg)) - -#define MGA_READ(reg) (_MGA_READ((u32 *)MGA_ADDR(reg))) -#define MGA_READ8(reg) (_MGA_READ((u8 *)MGA_ADDR(reg))) -#define MGA_WRITE(reg, val) do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF(reg) = val; } while (0) -#define MGA_WRITE8(reg, val) do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF8(reg) = val; } while (0) - -static inline u32 _MGA_READ(u32 *addr) -{ - DRM_MEMORYBARRIER(); - return *(volatile u32 *)addr; -} -#else #define MGA_READ8(reg) DRM_READ8(dev_priv->mmio, (reg)) #define MGA_READ(reg) DRM_READ32(dev_priv->mmio, (reg)) #define MGA_WRITE8(reg, val) DRM_WRITE8(dev_priv->mmio, (reg), (val)) #define MGA_WRITE(reg, val) DRM_WRITE32(dev_priv->mmio, (reg), (val)) -#endif #define DWGREG0 0x1c00 #define DWGREG0_END 0x1dff diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index f0d459b..525744d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -262,7 +262,6 @@ static bool nouveau_dsm_detect(void) vga_count++; retval = nouveau_dsm_pci_probe(pdev); - printk("ret val is %d\n", retval); if (retval & NOUVEAU_DSM_HAS_MUX) has_dsm |= 1; if (retval & NOUVEAU_DSM_HAS_OPT) diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 4b9f449..7347075 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -339,11 +339,12 @@ semaphore_acquire(struct nouveau_channel *chan, struct nouveau_semaphore *sema) int ret; if (dev_priv->chipset < 0x84) { - ret = RING_SPACE(chan, 3); + ret = RING_SPACE(chan, 4); if (ret) return ret; - BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_OFFSET, 2); + BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 3); + OUT_RING (chan, NvSema); OUT_RING (chan, sema->mem->start); OUT_RING (chan, 1); } else @@ -351,10 +352,12 @@ semaphore_acquire(struct nouveau_channel *chan, struct nouveau_semaphore *sema) struct nouveau_vma *vma = &dev_priv->fence.bo->vma; u64 offset = vma->offset + sema->mem->start; - ret = RING_SPACE(chan, 5); + ret = RING_SPACE(chan, 7); if (ret) return ret; + BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1); + OUT_RING (chan, chan->vram_handle); BEGIN_RING(chan, NvSubSw, 0x0010, 4); OUT_RING (chan, upper_32_bits(offset)); OUT_RING (chan, lower_32_bits(offset)); @@ -394,11 +397,12 @@ semaphore_release(struct nouveau_channel *chan, struct nouveau_semaphore *sema) int ret; if (dev_priv->chipset < 0x84) { - ret = RING_SPACE(chan, 4); + ret = RING_SPACE(chan, 5); if (ret) return ret; - BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_OFFSET, 1); + BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 2); + OUT_RING (chan, NvSema); OUT_RING (chan, sema->mem->start); BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_RELEASE, 1); OUT_RING (chan, 1); @@ -407,10 +411,12 @@ semaphore_release(struct nouveau_channel *chan, struct nouveau_semaphore *sema) struct nouveau_vma *vma = &dev_priv->fence.bo->vma; u64 offset = vma->offset + sema->mem->start; - ret = RING_SPACE(chan, 5); + ret = RING_SPACE(chan, 7); if (ret) return ret; + BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1); + OUT_RING (chan, chan->vram_handle); BEGIN_RING(chan, NvSubSw, 0x0010, 4); OUT_RING (chan, upper_32_bits(offset)); OUT_RING (chan, lower_32_bits(offset)); @@ -504,22 +510,22 @@ nouveau_fence_channel_init(struct nouveau_channel *chan) struct nouveau_gpuobj *obj = NULL; int ret; - if (dev_priv->card_type >= NV_C0) - goto out_initialised; + if (dev_priv->card_type < NV_C0) { + /* Create an NV_SW object for various sync purposes */ + ret = nouveau_gpuobj_gr_new(chan, NvSw, NV_SW); + if (ret) + return ret; - /* Create an NV_SW object for various sync purposes */ - ret = nouveau_gpuobj_gr_new(chan, NvSw, NV_SW); - if (ret) - return ret; + ret = RING_SPACE(chan, 2); + if (ret) + return ret; - /* we leave subchannel empty for nvc0 */ - ret = RING_SPACE(chan, 2); - if (ret) - return ret; - BEGIN_RING(chan, NvSubSw, 0, 1); - OUT_RING(chan, NvSw); + BEGIN_RING(chan, NvSubSw, 0, 1); + OUT_RING (chan, NvSw); + FIRE_RING (chan); + } - /* Create a DMA object for the shared cross-channel sync area. */ + /* Setup area of memory shared between all channels for x-chan sync */ if (USE_SEMA(dev) && dev_priv->chipset < 0x84) { struct ttm_mem_reg *mem = &dev_priv->fence.bo->bo.mem; @@ -534,23 +540,8 @@ nouveau_fence_channel_init(struct nouveau_channel *chan) nouveau_gpuobj_ref(NULL, &obj); if (ret) return ret; - - ret = RING_SPACE(chan, 2); - if (ret) - return ret; - BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1); - OUT_RING(chan, NvSema); - } else { - ret = RING_SPACE(chan, 2); - if (ret) - return ret; - BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1); - OUT_RING (chan, chan->vram_handle); /* whole VM */ } - FIRE_RING(chan); - -out_initialised: INIT_LIST_HEAD(&chan->fence.pending); spin_lock_init(&chan->fence.lock); atomic_set(&chan->fence.last_sequence_irq, 0); diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c index 922fb6b..ef9dec0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_perf.c +++ b/drivers/gpu/drm/nouveau/nouveau_perf.c @@ -182,6 +182,11 @@ nouveau_perf_init(struct drm_device *dev) entries = perf[2]; } + if (entries > NOUVEAU_PM_MAX_LEVEL) { + NV_DEBUG(dev, "perf table has too many entries - buggy vbios?\n"); + entries = NOUVEAU_PM_MAX_LEVEL; + } + entry = perf + headerlen; for (i = 0; i < entries; i++) { struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl]; diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 8021888..144f79a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -881,8 +881,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) #ifdef __BIG_ENDIAN /* Put the card in BE mode if it's not */ - if (nv_rd32(dev, NV03_PMC_BOOT_1)) - nv_wr32(dev, NV03_PMC_BOOT_1, 0x00000001); + if (nv_rd32(dev, NV03_PMC_BOOT_1) != 0x01000001) + nv_wr32(dev, NV03_PMC_BOOT_1, 0x01000001); DRM_MEMORYBARRIER(); #endif diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 74a3f68..08da478 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -409,7 +409,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct nouveau_channel *evo = dispc->sync; int ret; - ret = RING_SPACE(evo, 24); + ret = RING_SPACE(evo, chan ? 25 : 27); if (unlikely(ret)) return ret; @@ -458,8 +458,19 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, /* queue the flip on the crtc's "display sync" channel */ BEGIN_RING(evo, 0, 0x0100, 1); OUT_RING (evo, 0xfffe0000); - BEGIN_RING(evo, 0, 0x0084, 5); - OUT_RING (evo, chan ? 0x00000100 : 0x00000010); + if (chan) { + BEGIN_RING(evo, 0, 0x0084, 1); + OUT_RING (evo, 0x00000100); + } else { + BEGIN_RING(evo, 0, 0x0084, 1); + OUT_RING (evo, 0x00000010); + /* allows gamma somehow, PDISP will bitch at you if + * you don't wait for vblank before changing this.. + */ + BEGIN_RING(evo, 0, 0x00e0, 1); + OUT_RING (evo, 0x40000000); + } + BEGIN_RING(evo, 0, 0x0088, 4); OUT_RING (evo, dispc->sem.offset); OUT_RING (evo, 0xf00d0000 | dispc->sem.value); OUT_RING (evo, 0x74b1e000); diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h index 49611e2..1b50ad8 100644 --- a/drivers/gpu/drm/radeon/atombios.h +++ b/drivers/gpu/drm/radeon/atombios.h @@ -1200,6 +1200,7 @@ typedef struct _EXTERNAL_ENCODER_CONTROL_PARAMETERS_V3 #define EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING_OFF 0x10 #define EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING 0x11 #define EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION 0x12 +#define EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP 0x14 // ucConfig #define EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_MASK 0x03 diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 84a69e7..9541995 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -671,6 +671,13 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, DISPPLL_CONFIG_DUAL_LINK; } } + if (radeon_encoder_is_dp_bridge(encoder)) { + struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); + struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder); + args.v3.sInput.ucExtTransmitterID = ext_radeon_encoder->encoder_id; + } else + args.v3.sInput.ucExtTransmitterID = 0; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10; diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 98ea597..12d2fdc 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -88,7 +88,8 @@ u32 evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) /* get temperature in millidegrees */ int evergreen_get_temp(struct radeon_device *rdev) { - u32 temp, toffset, actual_temp = 0; + u32 temp, toffset; + int actual_temp = 0; if (rdev->family == CHIP_JUNIPER) { toffset = (RREG32(CG_THERMAL_CTRL) & TOFFSET_MASK) >> @@ -139,11 +140,17 @@ void evergreen_pm_misc(struct radeon_device *rdev) struct radeon_voltage *voltage = &ps->clock_info[req_cm_idx].voltage; if (voltage->type == VOLTAGE_SW) { + /* 0xff01 is a flag rather then an actual voltage */ + if (voltage->voltage == 0xff01) + return; if (voltage->voltage && (voltage->voltage != rdev->pm.current_vddc)) { radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC); rdev->pm.current_vddc = voltage->voltage; DRM_DEBUG("Setting: vddc: %d\n", voltage->voltage); } + /* 0xff01 is a flag rather then an actual voltage */ + if (voltage->vddci == 0xff01) + return; if (voltage->vddci && (voltage->vddci != rdev->pm.current_vddci)) { radeon_atom_set_voltage(rdev, voltage->vddci, SET_VOLTAGE_TYPE_ASIC_VDDCI); rdev->pm.current_vddci = voltage->vddci; @@ -2006,9 +2013,9 @@ static void evergreen_gpu_init(struct radeon_device *rdev) rdev->config.evergreen.tile_config |= (3 << 0); break; } - /* num banks is 8 on all fusion asics */ + /* num banks is 8 on all fusion asics. 0 = 4, 1 = 8, 2 = 16 */ if (rdev->flags & RADEON_IS_IGP) - rdev->config.evergreen.tile_config |= 8 << 4; + rdev->config.evergreen.tile_config |= 1 << 4; else rdev->config.evergreen.tile_config |= ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4; @@ -2694,28 +2701,25 @@ static inline u32 evergreen_get_ih_wptr(struct radeon_device *rdev) int evergreen_irq_process(struct radeon_device *rdev) { - u32 wptr = evergreen_get_ih_wptr(rdev); - u32 rptr = rdev->ih.rptr; + u32 wptr; + u32 rptr; u32 src_id, src_data; u32 ring_index; unsigned long flags; bool queue_hotplug = false; - DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr); - if (!rdev->ih.enabled) + if (!rdev->ih.enabled || rdev->shutdown) return IRQ_NONE; - spin_lock_irqsave(&rdev->ih.lock, flags); + wptr = evergreen_get_ih_wptr(rdev); + rptr = rdev->ih.rptr; + DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr); + spin_lock_irqsave(&rdev->ih.lock, flags); if (rptr == wptr) { spin_unlock_irqrestore(&rdev->ih.lock, flags); return IRQ_NONE; } - if (rdev->shutdown) { - spin_unlock_irqrestore(&rdev->ih.lock, flags); - return IRQ_NONE; - } - restart_ih: /* display interrupts */ evergreen_irq_ack(rdev); @@ -2944,7 +2948,7 @@ restart_ih: radeon_fence_process(rdev); break; case 233: /* GUI IDLE */ - DRM_DEBUG("IH: CP EOP\n"); + DRM_DEBUG("IH: GUI idle\n"); rdev->pm.gui_idle = true; wake_up(&rdev->irq.idle_queue); break; diff --git a/drivers/gpu/drm/radeon/r100_track.h b/drivers/gpu/drm/radeon/r100_track.h index 2fef9de..686f9dc 100644 --- a/drivers/gpu/drm/radeon/r100_track.h +++ b/drivers/gpu/drm/radeon/r100_track.h @@ -63,7 +63,7 @@ struct r100_cs_track { unsigned num_arrays; unsigned max_indx; unsigned color_channel_mask; - struct r100_cs_track_array arrays[11]; + struct r100_cs_track_array arrays[16]; struct r100_cs_track_cb cb[R300_MAX_CB]; struct r100_cs_track_cb zb; struct r100_cs_track_cb aa; @@ -146,6 +146,12 @@ static inline int r100_packet3_load_vbpntr(struct radeon_cs_parser *p, ib = p->ib->ptr; track = (struct r100_cs_track *)p->track; c = radeon_get_ib_value(p, idx++) & 0x1F; + if (c > 16) { + DRM_ERROR("Only 16 vertex buffers are allowed %d\n", + pkt->opcode); + r100_cs_dump_packet(p, pkt); + return -EINVAL; + } track->num_arrays = c; for (i = 0; i < (c - 1); i+=2, idx+=3) { r = r100_cs_packet_next_reloc(p, &reloc); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index d74d4d7..f79d2cc 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -590,6 +590,9 @@ void r600_pm_misc(struct radeon_device *rdev) struct radeon_voltage *voltage = &ps->clock_info[req_cm_idx].voltage; if ((voltage->type == VOLTAGE_SW) && voltage->voltage) { + /* 0xff01 is a flag rather then an actual voltage */ + if (voltage->voltage == 0xff01) + return; if (voltage->voltage != rdev->pm.current_vddc) { radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC); rdev->pm.current_vddc = voltage->voltage; @@ -3294,27 +3297,26 @@ static inline u32 r600_get_ih_wptr(struct radeon_device *rdev) int r600_irq_process(struct radeon_device *rdev) { - u32 wptr = r600_get_ih_wptr(rdev); - u32 rptr = rdev->ih.rptr; + u32 wptr; + u32 rptr; u32 src_id, src_data; u32 ring_index; unsigned long flags; bool queue_hotplug = false; - DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr); - if (!rdev->ih.enabled) + if (!rdev->ih.enabled || rdev->shutdown) return IRQ_NONE; + wptr = r600_get_ih_wptr(rdev); + rptr = rdev->ih.rptr; + DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr); + spin_lock_irqsave(&rdev->ih.lock, flags); if (rptr == wptr) { spin_unlock_irqrestore(&rdev->ih.lock, flags); return IRQ_NONE; } - if (rdev->shutdown) { - spin_unlock_irqrestore(&rdev->ih.lock, flags); - return IRQ_NONE; - } restart_ih: /* display interrupts */ @@ -3444,7 +3446,7 @@ restart_ih: radeon_fence_process(rdev); break; case 233: /* GUI IDLE */ - DRM_DEBUG("IH: CP EOP\n"); + DRM_DEBUG("IH: GUI idle\n"); rdev->pm.gui_idle = true; wake_up(&rdev->irq.idle_queue); break; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index ba643b5..ef0e0e0 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -165,6 +165,7 @@ struct radeon_clock { uint32_t default_sclk; uint32_t default_dispclk; uint32_t dp_extclk; + uint32_t max_pixel_clock; }; /* @@ -178,6 +179,7 @@ void radeon_pm_resume(struct radeon_device *rdev); void radeon_combios_get_power_modes(struct radeon_device *rdev); void radeon_atombios_get_power_modes(struct radeon_device *rdev); void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type); +int radeon_atom_get_max_vddc(struct radeon_device *rdev, u16 *voltage); void rs690_pm_info(struct radeon_device *rdev); extern int rv6xx_get_temp(struct radeon_device *rdev); extern int rv770_get_temp(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 9bd162f..b244962 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -938,6 +938,13 @@ static struct radeon_asic cayman_asic = { int radeon_asic_init(struct radeon_device *rdev) { radeon_register_accessor_init(rdev); + + /* set the number of crtcs */ + if (rdev->flags & RADEON_SINGLE_CRTC) + rdev->num_crtc = 1; + else + rdev->num_crtc = 2; + switch (rdev->family) { case CHIP_R100: case CHIP_RV100: @@ -1017,6 +1024,11 @@ int radeon_asic_init(struct radeon_device *rdev) case CHIP_JUNIPER: case CHIP_CYPRESS: case CHIP_HEMLOCK: + /* set num crtcs */ + if (rdev->family == CHIP_CEDAR) + rdev->num_crtc = 4; + else + rdev->num_crtc = 6; rdev->asic = &evergreen_asic; break; case CHIP_PALM: @@ -1027,10 +1039,17 @@ int radeon_asic_init(struct radeon_device *rdev) case CHIP_BARTS: case CHIP_TURKS: case CHIP_CAICOS: + /* set num crtcs */ + if (rdev->family == CHIP_CAICOS) + rdev->num_crtc = 4; + else + rdev->num_crtc = 6; rdev->asic = &btc_asic; break; case CHIP_CAYMAN: rdev->asic = &cayman_asic; + /* set num crtcs */ + rdev->num_crtc = 6; break; default: /* FIXME: not supported yet */ @@ -1042,18 +1061,6 @@ int radeon_asic_init(struct radeon_device *rdev) rdev->asic->set_memory_clock = NULL; } - /* set the number of crtcs */ - if (rdev->flags & RADEON_SINGLE_CRTC) - rdev->num_crtc = 1; - else { - if (ASIC_IS_DCE41(rdev)) - rdev->num_crtc = 2; - else if (ASIC_IS_DCE4(rdev)) - rdev->num_crtc = 6; - else - rdev->num_crtc = 2; - } - return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 90dfb2b..bf2b615 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1246,6 +1246,10 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) } *dcpll = *p1pll; + rdev->clock.max_pixel_clock = le16_to_cpu(firmware_info->info.usMaxPixelClock); + if (rdev->clock.max_pixel_clock == 0) + rdev->clock.max_pixel_clock = 40000; + return true; } @@ -2316,6 +2320,14 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev, le16_to_cpu(clock_info->r600.usVDDC); } + /* patch up vddc if necessary */ + if (rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage == 0xff01) { + u16 vddc; + + if (radeon_atom_get_max_vddc(rdev, &vddc) == 0) + rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = vddc; + } + if (rdev->flags & RADEON_IS_IGP) { /* skip invalid modes */ if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0) @@ -2603,6 +2615,10 @@ void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 v if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) return; + /* 0xff01 is a flag rather then an actual voltage */ + if (voltage_level == 0xff01) + return; + switch (crev) { case 1: args.v1.ucVoltageType = voltage_type; @@ -2622,7 +2638,35 @@ void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 v atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } +int radeon_atom_get_max_vddc(struct radeon_device *rdev, + u16 *voltage) +{ + union set_voltage args; + int index = GetIndexIntoMasterTable(COMMAND, SetVoltage); + u8 frev, crev; + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return -EINVAL; + switch (crev) { + case 1: + return -EINVAL; + case 2: + args.v2.ucVoltageType = SET_VOLTAGE_GET_MAX_VOLTAGE; + args.v2.ucVoltageMode = 0; + args.v2.usVoltageLevel = 0; + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + + *voltage = le16_to_cpu(args.v2.usVoltageLevel); + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + return -EINVAL; + } + + return 0; +} void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev) { diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index 1aba85c..3fc5fa1 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -104,7 +104,7 @@ static bool radeon_read_bios(struct radeon_device *rdev) static bool radeon_atrm_get_bios(struct radeon_device *rdev) { int ret; - int size = 64 * 1024; + int size = 256 * 1024; int i; if (!radeon_atrm_supported(rdev->pdev)) diff --git a/drivers/gpu/drm/radeon/radeon_clocks.c b/drivers/gpu/drm/radeon/radeon_clocks.c index 5249af8..2d48e7a 100644 --- a/drivers/gpu/drm/radeon/radeon_clocks.c +++ b/drivers/gpu/drm/radeon/radeon_clocks.c @@ -117,7 +117,7 @@ static bool __devinit radeon_read_clocks_OF(struct drm_device *dev) p1pll->reference_div = RREG32_PLL(RADEON_PPLL_REF_DIV) & 0x3ff; if (p1pll->reference_div < 2) p1pll->reference_div = 12; - p2pll->reference_div = p1pll->reference_div; + p2pll->reference_div = p1pll->reference_div; /* These aren't in the device-tree */ if (rdev->family >= CHIP_R420) { @@ -139,6 +139,8 @@ static bool __devinit radeon_read_clocks_OF(struct drm_device *dev) p2pll->pll_out_min = 12500; p2pll->pll_out_max = 35000; } + /* not sure what the max should be in all cases */ + rdev->clock.max_pixel_clock = 35000; spll->reference_freq = mpll->reference_freq = p1pll->reference_freq; spll->reference_div = mpll->reference_div = @@ -151,7 +153,7 @@ static bool __devinit radeon_read_clocks_OF(struct drm_device *dev) else rdev->clock.default_sclk = radeon_legacy_get_engine_clock(rdev); - + val = of_get_property(dp, "ATY,MCLK", NULL); if (val && *val) rdev->clock.default_mclk = (*val) / 10; @@ -160,7 +162,7 @@ static bool __devinit radeon_read_clocks_OF(struct drm_device *dev) radeon_legacy_get_memory_clock(rdev); DRM_INFO("Using device-tree clock info\n"); - + return true; } #else diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 5b991f7..e459467 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -866,6 +866,11 @@ bool radeon_combios_get_clock_info(struct drm_device *dev) rdev->clock.default_sclk = sclk; rdev->clock.default_mclk = mclk; + if (RBIOS32(pll_info + 0x16)) + rdev->clock.max_pixel_clock = RBIOS32(pll_info + 0x16); + else + rdev->clock.max_pixel_clock = 35000; /* might need something asic specific */ + return true; } return false; @@ -1548,10 +1553,12 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) (rdev->pdev->subsystem_device == 0x4a48)) { /* Mac X800 */ rdev->mode_info.connector_table = CT_MAC_X800; - } else if ((rdev->pdev->device == 0x4150) && + } else if ((of_machine_is_compatible("PowerMac7,2") || + of_machine_is_compatible("PowerMac7,3")) && + (rdev->pdev->device == 0x4150) && (rdev->pdev->subsystem_vendor == 0x1002) && (rdev->pdev->subsystem_device == 0x4150)) { - /* Mac G5 9600 */ + /* Mac G5 tower 9600 */ rdev->mode_info.connector_table = CT_MAC_G5_9600; } else #endif /* CONFIG_PPC_PMAC */ diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index ee1dccb..cbfca3a 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -44,6 +44,8 @@ extern void radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder, struct drm_connector *drm_connector); +bool radeon_connector_encoder_is_dp_bridge(struct drm_connector *connector); + void radeon_connector_hotplug(struct drm_connector *connector) { struct drm_device *dev = connector->dev; @@ -626,8 +628,14 @@ static int radeon_vga_get_modes(struct drm_connector *connector) static int radeon_vga_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct drm_device *dev = connector->dev; + struct radeon_device *rdev = dev->dev_private; + /* XXX check mode bandwidth */ - /* XXX verify against max DAC output frequency */ + + if ((mode->clock / 10) > rdev->clock.max_pixel_clock) + return MODE_CLOCK_HIGH; + return MODE_OK; } @@ -830,6 +838,13 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) if (!radeon_connector->edid) { DRM_ERROR("%s: probed a monitor but no|invalid EDID\n", drm_get_connector_name(connector)); + /* rs690 seems to have a problem with connectors not existing and always + * return a block of 0's. If we see this just stop polling on this output */ + if ((rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) && radeon_connector->base.null_edid_counter) { + ret = connector_status_disconnected; + DRM_ERROR("%s: detected RS690 floating bus bug, stopping ddc detect\n", drm_get_connector_name(connector)); + radeon_connector->ddc_bus = NULL; + } } else { radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); @@ -1015,6 +1030,11 @@ static int radeon_dvi_mode_valid(struct drm_connector *connector, } else return MODE_CLOCK_HIGH; } + + /* check against the max pixel clock */ + if ((mode->clock / 10) > rdev->clock.max_pixel_clock) + return MODE_CLOCK_HIGH; + return MODE_OK; } @@ -1052,10 +1072,11 @@ static int radeon_dp_get_modes(struct drm_connector *connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; + struct drm_encoder *encoder = radeon_best_single_encoder(connector); int ret; - if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { - struct drm_encoder *encoder; + if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) || + (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) { struct drm_display_mode *mode; if (!radeon_dig_connector->edp_on) @@ -1067,7 +1088,6 @@ static int radeon_dp_get_modes(struct drm_connector *connector) ATOM_TRANSMITTER_ACTION_POWER_OFF); if (ret > 0) { - encoder = radeon_best_single_encoder(connector); if (encoder) { radeon_fixup_lvds_native_mode(encoder, connector); /* add scaled modes */ @@ -1091,8 +1111,14 @@ static int radeon_dp_get_modes(struct drm_connector *connector) /* add scaled modes */ radeon_add_common_modes(encoder, connector); } - } else + } else { + /* need to setup ddc on the bridge */ + if (radeon_connector_encoder_is_dp_bridge(connector)) { + if (encoder) + radeon_atom_ext_encoder_setup_ddc(encoder); + } ret = radeon_ddc_get_modes(radeon_connector); + } return ret; } @@ -1176,14 +1202,15 @@ radeon_dp_detect(struct drm_connector *connector, bool force) struct radeon_connector *radeon_connector = to_radeon_connector(connector); enum drm_connector_status ret = connector_status_disconnected; struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; + struct drm_encoder *encoder = radeon_best_single_encoder(connector); if (radeon_connector->edid) { kfree(radeon_connector->edid); radeon_connector->edid = NULL; } - if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { - struct drm_encoder *encoder = radeon_best_single_encoder(connector); + if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) || + (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) { if (encoder) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct drm_display_mode *native_mode = &radeon_encoder->native_mode; @@ -1203,6 +1230,11 @@ radeon_dp_detect(struct drm_connector *connector, bool force) atombios_set_edp_panel_power(connector, ATOM_TRANSMITTER_ACTION_POWER_OFF); } else { + /* need to setup ddc on the bridge */ + if (radeon_connector_encoder_is_dp_bridge(connector)) { + if (encoder) + radeon_atom_ext_encoder_setup_ddc(encoder); + } radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector); if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) { ret = connector_status_connected; @@ -1217,6 +1249,16 @@ radeon_dp_detect(struct drm_connector *connector, bool force) ret = connector_status_connected; } } + + if ((ret == connector_status_disconnected) && + radeon_connector->dac_load_detect) { + struct drm_encoder *encoder = radeon_best_single_encoder(connector); + struct drm_encoder_helper_funcs *encoder_funcs; + if (encoder) { + encoder_funcs = encoder->helper_private; + ret = encoder_funcs->detect(encoder, connector); + } + } } radeon_connector_update_scratch_regs(connector, ret); @@ -1231,7 +1273,8 @@ static int radeon_dp_mode_valid(struct drm_connector *connector, /* XXX check mode bandwidth */ - if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) || + (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) { struct drm_encoder *encoder = radeon_best_single_encoder(connector); if ((mode->hdisplay < 320) || (mode->vdisplay < 240)) @@ -1241,7 +1284,7 @@ static int radeon_dp_mode_valid(struct drm_connector *connector, struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct drm_display_mode *native_mode = &radeon_encoder->native_mode; - /* AVIVO hardware supports downscaling modes larger than the panel + /* AVIVO hardware supports downscaling modes larger than the panel * to the panel size, but I'm not sure this is desirable. */ if ((mode->hdisplay > native_mode->hdisplay) || @@ -1390,6 +1433,10 @@ radeon_add_atom_connector(struct drm_device *dev, default: connector->interlace_allowed = true; connector->doublescan_allowed = true; + radeon_connector->dac_load_detect = true; + drm_connector_attach_property(&radeon_connector->base, + rdev->mode_info.load_detect_property, + 1); break; case DRM_MODE_CONNECTOR_DVII: case DRM_MODE_CONNECTOR_DVID: @@ -1411,6 +1458,12 @@ radeon_add_atom_connector(struct drm_device *dev, connector->doublescan_allowed = true; else connector->doublescan_allowed = false; + if (connector_type == DRM_MODE_CONNECTOR_DVII) { + radeon_connector->dac_load_detect = true; + drm_connector_attach_property(&radeon_connector->base, + rdev->mode_info.load_detect_property, + 1); + } break; case DRM_MODE_CONNECTOR_LVDS: case DRM_MODE_CONNECTOR_eDP: diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index e680501..7cfaa7e 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -215,6 +215,8 @@ int radeon_wb_init(struct radeon_device *rdev) return r; } + /* clear wb memory */ + memset((char *)rdev->wb.wb, 0, RADEON_GPU_PAGE_SIZE); /* disable event_write fences */ rdev->wb.use_event = false; /* disabled via module param */ diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 03f124d..b293487 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -367,7 +367,8 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, } if (ASIC_IS_DCE3(rdev) && - (radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT))) { + ((radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) || + radeon_encoder_is_dp_bridge(encoder))) { struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); radeon_dp_set_link_config(connector, mode); } @@ -660,21 +661,16 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) if (radeon_encoder_is_dp_bridge(encoder)) return ATOM_ENCODER_MODE_DP; + /* DVO is always DVO */ + if (radeon_encoder->encoder_id == ATOM_ENCODER_MODE_DVO) + return ATOM_ENCODER_MODE_DVO; + connector = radeon_get_connector_for_encoder(encoder); - if (!connector) { - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - return ATOM_ENCODER_MODE_DVI; - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: - default: - return ATOM_ENCODER_MODE_CRT; - } - } + /* if we don't have an active device yet, just use one of + * the connectors tied to the encoder. + */ + if (!connector) + connector = radeon_get_connector_for_encoder_init(encoder); radeon_connector = to_radeon_connector(connector); switch (connector->connector_type) { @@ -1094,9 +1090,10 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t break; } - if (is_dp) + if (is_dp) { args.v2.acConfig.fCoherentMode = 1; - else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { + args.v2.acConfig.fDPConnector = 1; + } else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { if (dig->coherent_mode) args.v2.acConfig.fCoherentMode = 1; if (radeon_encoder->pixel_clock > 165000) @@ -1435,7 +1432,11 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) if (is_dig) { switch (mode) { case DRM_MODE_DPMS_ON: - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); + /* some early dce3.2 boards have a bug in their transmitter control table */ + if ((rdev->family == CHIP_RV710) || (rdev->family == CHIP_RV730)) + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); + else + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) { struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); @@ -1526,26 +1527,29 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) } if (ext_encoder) { - int action; - switch (mode) { case DRM_MODE_DPMS_ON: default: - if (ASIC_IS_DCE41(rdev)) - action = EXTERNAL_ENCODER_ACTION_V3_ENABLE_OUTPUT; - else - action = ATOM_ENABLE; + if (ASIC_IS_DCE41(rdev)) { + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_ENABLE_OUTPUT); + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING_OFF); + } else + atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - if (ASIC_IS_DCE41(rdev)) - action = EXTERNAL_ENCODER_ACTION_V3_DISABLE_OUTPUT; - else - action = ATOM_DISABLE; + if (ASIC_IS_DCE41(rdev)) { + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING); + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_DISABLE_OUTPUT); + } else + atombios_external_encoder_setup(encoder, ext_encoder, ATOM_DISABLE); break; } - atombios_external_encoder_setup(encoder, ext_encoder, action); } radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); @@ -2004,6 +2008,65 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec return connector_status_disconnected; } +static enum drm_connector_status +radeon_atom_dig_detect(struct drm_encoder *encoder, struct drm_connector *connector) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); + u32 bios_0_scratch; + + if (!ASIC_IS_DCE4(rdev)) + return connector_status_unknown; + + if (!ext_encoder) + return connector_status_unknown; + + if ((radeon_connector->devices & ATOM_DEVICE_CRT_SUPPORT) == 0) + return connector_status_unknown; + + /* load detect on the dp bridge */ + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION); + + bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH); + + DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices); + if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) { + if (bios_0_scratch & ATOM_S0_CRT1_MASK) + return connector_status_connected; + } + if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) { + if (bios_0_scratch & ATOM_S0_CRT2_MASK) + return connector_status_connected; + } + if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { + if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A)) + return connector_status_connected; + } + if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { + if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) + return connector_status_connected; /* CTV */ + else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) + return connector_status_connected; /* STV */ + } + return connector_status_disconnected; +} + +void +radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder) +{ + struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); + + if (ext_encoder) + /* ddc_setup on the dp bridge */ + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP); + +} + static void radeon_atom_encoder_prepare(struct drm_encoder *encoder) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); @@ -2167,7 +2230,7 @@ static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = { .mode_set = radeon_atom_encoder_mode_set, .commit = radeon_atom_encoder_commit, .disable = radeon_atom_encoder_disable, - /* no detect for TMDS/LVDS yet */ + .detect = radeon_atom_dig_detect, }; static const struct drm_encoder_helper_funcs radeon_atom_dac_helper_funcs = { diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 1f82294..021d2b6 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -40,6 +40,35 @@ #include "radeon.h" #include "radeon_trace.h" +static void radeon_fence_write(struct radeon_device *rdev, u32 seq) +{ + if (rdev->wb.enabled) { + u32 scratch_index; + if (rdev->wb.use_event) + scratch_index = R600_WB_EVENT_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base; + else + scratch_index = RADEON_WB_SCRATCH_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base; + rdev->wb.wb[scratch_index/4] = cpu_to_le32(seq);; + } else + WREG32(rdev->fence_drv.scratch_reg, seq); +} + +static u32 radeon_fence_read(struct radeon_device *rdev) +{ + u32 seq; + + if (rdev->wb.enabled) { + u32 scratch_index; + if (rdev->wb.use_event) + scratch_index = R600_WB_EVENT_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base; + else + scratch_index = RADEON_WB_SCRATCH_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base; + seq = le32_to_cpu(rdev->wb.wb[scratch_index/4]); + } else + seq = RREG32(rdev->fence_drv.scratch_reg); + return seq; +} + int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence) { unsigned long irq_flags; @@ -50,12 +79,12 @@ int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence) return 0; } fence->seq = atomic_add_return(1, &rdev->fence_drv.seq); - if (!rdev->cp.ready) { + if (!rdev->cp.ready) /* FIXME: cp is not running assume everythings is done right * away */ - WREG32(rdev->fence_drv.scratch_reg, fence->seq); - } else + radeon_fence_write(rdev, fence->seq); + else radeon_fence_ring_emit(rdev, fence); trace_radeon_fence_emit(rdev->ddev, fence->seq); @@ -73,15 +102,7 @@ static bool radeon_fence_poll_locked(struct radeon_device *rdev) bool wake = false; unsigned long cjiffies; - if (rdev->wb.enabled) { - u32 scratch_index; - if (rdev->wb.use_event) - scratch_index = R600_WB_EVENT_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base; - else - scratch_index = RADEON_WB_SCRATCH_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base; - seq = le32_to_cpu(rdev->wb.wb[scratch_index/4]); - } else - seq = RREG32(rdev->fence_drv.scratch_reg); + seq = radeon_fence_read(rdev); if (seq != rdev->fence_drv.last_seq) { rdev->fence_drv.last_seq = seq; rdev->fence_drv.last_jiffies = jiffies; @@ -251,7 +272,7 @@ retry: r = radeon_gpu_reset(rdev); if (r) return r; - WREG32(rdev->fence_drv.scratch_reg, fence->seq); + radeon_fence_write(rdev, fence->seq); rdev->gpu_lockup = false; } timeout = RADEON_FENCE_JIFFIES_TIMEOUT; @@ -351,7 +372,7 @@ int radeon_fence_driver_init(struct radeon_device *rdev) write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); return r; } - WREG32(rdev->fence_drv.scratch_reg, 0); + radeon_fence_write(rdev, 0); atomic_set(&rdev->fence_drv.seq, 0); INIT_LIST_HEAD(&rdev->fence_drv.created); INIT_LIST_HEAD(&rdev->fence_drv.emited); @@ -391,7 +412,7 @@ static int radeon_debugfs_fence_info(struct seq_file *m, void *data) struct radeon_fence *fence; seq_printf(m, "Last signaled fence 0x%08X\n", - RREG32(rdev->fence_drv.scratch_reg)); + radeon_fence_read(rdev)); if (!list_empty(&rdev->fence_drv.emited)) { fence = list_entry(rdev->fence_drv.emited.prev, struct radeon_fence, list); diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 977a341..6df4e3c 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -483,6 +483,8 @@ extern void radeon_atom_encoder_init(struct radeon_device *rdev); extern void atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set); +extern void radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder); +extern struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder); extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, u8 write_byte, u8 *read_byte); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index ef8a5bab..6f508ff 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -105,6 +105,9 @@ void rv770_pm_misc(struct radeon_device *rdev) struct radeon_voltage *voltage = &ps->clock_info[req_cm_idx].voltage; if ((voltage->type == VOLTAGE_SW) && voltage->voltage) { + /* 0xff01 is a flag rather then an actual voltage */ + if (voltage->voltage == 0xff01) + return; if (voltage->voltage != rdev->pm.current_vddc) { radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC); rdev->pm.current_vddc = voltage->voltage; diff --git a/drivers/gpu/drm/savage/savage_bci.c b/drivers/gpu/drm/savage/savage_bci.c index bf5f83e..cb1ee4e 100644 --- a/drivers/gpu/drm/savage/savage_bci.c +++ b/drivers/gpu/drm/savage/savage_bci.c @@ -647,9 +647,6 @@ int savage_driver_firstopen(struct drm_device *dev) ret = drm_addmap(dev, aperture_base, SAVAGE_APERTURE_SIZE, _DRM_FRAME_BUFFER, _DRM_WRITE_COMBINING, &dev_priv->aperture); - if (ret) - return ret; - return ret; } diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 90e23e0..58c271e 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -31,6 +31,7 @@ #include <linux/sched.h> #include <linux/highmem.h> #include <linux/pagemap.h> +#include <linux/shmem_fs.h> #include <linux/file.h> #include <linux/swap.h> #include <linux/slab.h> @@ -484,7 +485,7 @@ static int ttm_tt_swapin(struct ttm_tt *ttm) swap_space = swap_storage->f_path.dentry->d_inode->i_mapping; for (i = 0; i < ttm->num_pages; ++i) { - from_page = read_mapping_page(swap_space, i, NULL); + from_page = shmem_read_mapping_page(swap_space, i); if (IS_ERR(from_page)) { ret = PTR_ERR(from_page); goto out_err; @@ -557,7 +558,7 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage) from_page = ttm->pages[i]; if (unlikely(from_page == NULL)) continue; - to_page = read_mapping_page(swap_space, i, NULL); + to_page = shmem_read_mapping_page(swap_space, i); if (unlikely(IS_ERR(to_page))) { ret = PTR_ERR(to_page); goto out_err; diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 67d2a75..36ca465 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -305,6 +305,7 @@ config HID_MULTITOUCH - 3M PCT touch screens - ActionStar dual touch panels - Cando dual touch panels + - Chunghwa panels - CVTouch panels - Cypress TrueTouch panels - Elo TouchSystems IntelliTouch Plus panels diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index c957c4b..6f3289a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1359,6 +1359,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) }, { HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, USB_DEVICE_ID_CVTOUCH_SCREEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, @@ -1422,6 +1423,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) }, { HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH_DUAL) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 0b374a6..a756ee6 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -173,6 +173,9 @@ #define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d #define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618 +#define USB_VENDOR_ID_CHUNGHWAT 0x2247 +#define USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH 0x0001 + #define USB_VENDOR_ID_CIDC 0x1677 #define USB_VENDOR_ID_CMEDIA 0x0d8c @@ -446,6 +449,7 @@ #define USB_VENDOR_ID_LUMIO 0x202e #define USB_DEVICE_ID_CRYSTALTOUCH 0x0006 +#define USB_DEVICE_ID_CRYSTALTOUCH_DUAL 0x0007 #define USB_VENDOR_ID_MCC 0x09db #define USB_DEVICE_ID_MCC_PMD1024LS 0x0076 @@ -622,6 +626,7 @@ #define USB_VENDOR_ID_UCLOGIC 0x5543 #define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209 0x0042 #define USB_DEVICE_ID_UCLOGIC_TABLET_KNA5 0x6001 +#define USB_DEVICE_ID_UCLOGIC_TABLET_TWA60 0x0064 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U 0x0003 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U 0x0004 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005 diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index a5eda4c..0ec91c1 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -501,17 +501,9 @@ static int magicmouse_probe(struct hid_device *hdev, } report->size = 6; - /* - * The device reponds with 'invalid report id' when feature - * report switching it into multitouch mode is sent to it. - * - * This results in -EIO from the _raw low-level transport callback, - * but there seems to be no other way of switching the mode. - * Thus the super-ugly hacky success check below. - */ ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature), HID_FEATURE_REPORT); - if (ret != -EIO) { + if (ret != sizeof(feature)) { hid_err(hdev, "unable to request touch data (%d)\n", ret); goto err_stop_hw; } diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index ecd4d2d..62cac4d 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -64,6 +64,7 @@ struct mt_device { struct mt_class *mtclass; /* our mt device class */ unsigned last_field_index; /* last field index of the report */ unsigned last_slot_field; /* the last field of a slot */ + int last_mt_collection; /* last known mt-related collection */ __s8 inputmode; /* InputMode HID feature, -1 if non-existent */ __u8 num_received; /* how many contacts we received */ __u8 num_expected; /* expected last contact index */ @@ -225,8 +226,10 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, cls->sn_move); /* touchscreen emulation */ set_abs(hi->input, ABS_X, field, cls->sn_move); - td->last_slot_field = usage->hid; - td->last_field_index = field->index; + if (td->last_mt_collection == usage->collection_index) { + td->last_slot_field = usage->hid; + td->last_field_index = field->index; + } return 1; case HID_GD_Y: if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP) @@ -237,8 +240,10 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, cls->sn_move); /* touchscreen emulation */ set_abs(hi->input, ABS_Y, field, cls->sn_move); - td->last_slot_field = usage->hid; - td->last_field_index = field->index; + if (td->last_mt_collection == usage->collection_index) { + td->last_slot_field = usage->hid; + td->last_field_index = field->index; + } return 1; } return 0; @@ -246,31 +251,42 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_UP_DIGITIZER: switch (usage->hid) { case HID_DG_INRANGE: - td->last_slot_field = usage->hid; - td->last_field_index = field->index; + if (td->last_mt_collection == usage->collection_index) { + td->last_slot_field = usage->hid; + td->last_field_index = field->index; + } return 1; case HID_DG_CONFIDENCE: - td->last_slot_field = usage->hid; - td->last_field_index = field->index; + if (td->last_mt_collection == usage->collection_index) { + td->last_slot_field = usage->hid; + td->last_field_index = field->index; + } return 1; case HID_DG_TIPSWITCH: hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); input_set_capability(hi->input, EV_KEY, BTN_TOUCH); - td->last_slot_field = usage->hid; - td->last_field_index = field->index; + if (td->last_mt_collection == usage->collection_index) { + td->last_slot_field = usage->hid; + td->last_field_index = field->index; + } return 1; case HID_DG_CONTACTID: + if (!td->maxcontacts) + td->maxcontacts = MT_DEFAULT_MAXCONTACT; input_mt_init_slots(hi->input, td->maxcontacts); td->last_slot_field = usage->hid; td->last_field_index = field->index; + td->last_mt_collection = usage->collection_index; return 1; case HID_DG_WIDTH: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MAJOR); set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, cls->sn_width); - td->last_slot_field = usage->hid; - td->last_field_index = field->index; + if (td->last_mt_collection == usage->collection_index) { + td->last_slot_field = usage->hid; + td->last_field_index = field->index; + } return 1; case HID_DG_HEIGHT: hid_map_usage(hi, usage, bit, max, @@ -279,8 +295,10 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, cls->sn_height); input_set_abs_params(hi->input, ABS_MT_ORIENTATION, 0, 1, 0, 0); - td->last_slot_field = usage->hid; - td->last_field_index = field->index; + if (td->last_mt_collection == usage->collection_index) { + td->last_slot_field = usage->hid; + td->last_field_index = field->index; + } return 1; case HID_DG_TIPPRESSURE: if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP) @@ -292,16 +310,20 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, /* touchscreen emulation */ set_abs(hi->input, ABS_PRESSURE, field, cls->sn_pressure); - td->last_slot_field = usage->hid; - td->last_field_index = field->index; + if (td->last_mt_collection == usage->collection_index) { + td->last_slot_field = usage->hid; + td->last_field_index = field->index; + } return 1; case HID_DG_CONTACTCOUNT: - td->last_field_index = field->index; + if (td->last_mt_collection == usage->collection_index) + td->last_field_index = field->index; return 1; case HID_DG_CONTACTMAX: /* we don't set td->last_slot_field as contactcount and * contact max are global to the report */ - td->last_field_index = field->index; + if (td->last_mt_collection == usage->collection_index) + td->last_field_index = field->index; return -1; } /* let hid-input decide for the others */ @@ -516,6 +538,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) } td->mtclass = mtclass; td->inputmode = -1; + td->last_mt_collection = -1; hid_set_drvdata(hdev, td); ret = hid_parse(hdev); @@ -526,9 +549,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) if (ret) goto fail; - if (!td->maxcontacts) - td->maxcontacts = MT_DEFAULT_MAXCONTACT; - td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot), GFP_KERNEL); if (!td->slots) { @@ -593,6 +613,11 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) }, + /* Chunghwa Telecom touch panels */ + { .driver_data = MT_CLS_DEFAULT, + HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, + USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) }, + /* CVTouch panels */ { .driver_data = MT_CLS_DEFAULT, HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, @@ -651,6 +676,9 @@ static const struct hid_device_id mt_devices[] = { { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH) }, + { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, + HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, + USB_DEVICE_ID_CRYSTALTOUCH_DUAL) }, /* MosArt panels */ { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, @@ -681,10 +709,10 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP)}, { .driver_data = MT_CLS_CONFIDENCE, - HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, + HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM)}, { .driver_data = MT_CLS_CONFIDENCE, - HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, + HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, USB_DEVICE_ID_MTP_SITRONIX)}, /* Touch International panels */ diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 0e30b14..621959d 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -74,6 +74,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWA60, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT }, diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index ff3c644..7c1188b 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -248,12 +248,15 @@ static int hiddev_release(struct inode * inode, struct file * file) usbhid_close(list->hiddev->hid); usbhid_put_power(list->hiddev->hid); } else { + mutex_unlock(&list->hiddev->existancelock); kfree(list->hiddev); + kfree(list); + return 0; } } - kfree(list); mutex_unlock(&list->hiddev->existancelock); + kfree(list); return 0; } @@ -923,10 +926,11 @@ void hiddev_disconnect(struct hid_device *hid) usb_deregister_dev(usbhid->intf, &hiddev_class); if (hiddev->open) { + mutex_unlock(&hiddev->existancelock); usbhid_close(hiddev->hid); wake_up_interruptible(&hiddev->wait); } else { + mutex_unlock(&hiddev->existancelock); kfree(hiddev); } - mutex_unlock(&hiddev->existancelock); } diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index b5e8920..dcb78a7 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -268,6 +268,7 @@ static struct device_attribute atk_name_attr = static void atk_init_attribute(struct device_attribute *attr, char *name, sysfs_show_func show) { + sysfs_attr_init(&attr->attr); attr->attr.name = name; attr->attr.mode = 0444; attr->show = show; @@ -1188,19 +1189,15 @@ static int atk_create_files(struct atk_data *data) int err; list_for_each_entry(s, &data->sensor_list, list) { - sysfs_attr_init(&s->input_attr.attr); err = device_create_file(data->hwmon_dev, &s->input_attr); if (err) return err; - sysfs_attr_init(&s->label_attr.attr); err = device_create_file(data->hwmon_dev, &s->label_attr); if (err) return err; - sysfs_attr_init(&s->limit1_attr.attr); err = device_create_file(data->hwmon_dev, &s->limit1_attr); if (err) return err; - sysfs_attr_init(&s->limit2_attr.attr); err = device_create_file(data->hwmon_dev, &s->limit2_attr); if (err) return err; diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 85e9379..0070d54 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -97,9 +97,7 @@ struct platform_data { struct pdev_entry { struct list_head list; struct platform_device *pdev; - unsigned int cpu; u16 phys_proc_id; - u16 cpu_core_id; }; static LIST_HEAD(pdev_list); @@ -653,9 +651,7 @@ static int __cpuinit coretemp_device_add(unsigned int cpu) } pdev_entry->pdev = pdev; - pdev_entry->cpu = cpu; pdev_entry->phys_proc_id = TO_PHYS_ID(cpu); - pdev_entry->cpu_core_id = TO_CORE_ID(cpu); list_add_tail(&pdev_entry->list, &pdev_list); mutex_unlock(&pdev_list_mutex); diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c index 537409d..1a409c5 100644 --- a/drivers/hwmon/ibmaem.c +++ b/drivers/hwmon/ibmaem.c @@ -947,6 +947,7 @@ static int aem_register_sensors(struct aem_data *data, /* Set up read-only sensors */ while (ro->label) { + sysfs_attr_init(&sensors->dev_attr.attr); sensors->dev_attr.attr.name = ro->label; sensors->dev_attr.attr.mode = S_IRUGO; sensors->dev_attr.show = ro->show; @@ -963,6 +964,7 @@ static int aem_register_sensors(struct aem_data *data, /* Set up read-write sensors */ while (rw->label) { + sysfs_attr_init(&sensors->dev_attr.attr); sensors->dev_attr.attr.name = rw->label; sensors->dev_attr.attr.mode = S_IRUGO | S_IWUSR; sensors->dev_attr.show = rw->show; diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c index 06d4eaf..41dbf81 100644 --- a/drivers/hwmon/ibmpex.c +++ b/drivers/hwmon/ibmpex.c @@ -358,6 +358,7 @@ static int create_sensor(struct ibmpex_bmc_data *data, int type, else if (type == POWER_SENSOR) sprintf(n, power_sensor_name_templates[func], "power", counter); + sysfs_attr_init(&data->sensors[sensor].attr[func].dev_attr.attr); data->sensors[sensor].attr[func].dev_attr.attr.name = n; data->sensors[sensor].attr[func].dev_attr.attr.mode = S_IRUGO; data->sensors[sensor].attr[func].dev_attr.show = ibmpex_show_sensor; diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c index 92b42db..b39f52e 100644 --- a/drivers/hwmon/s3c-hwmon.c +++ b/drivers/hwmon/s3c-hwmon.c @@ -232,6 +232,7 @@ static int s3c_hwmon_create_attr(struct device *dev, attr = &attrs->in; attr->index = channel; + sysfs_attr_init(&attr->dev_attr.attr); attr->dev_attr.attr.name = attrs->in_name; attr->dev_attr.attr.mode = S_IRUGO; attr->dev_attr.show = s3c_hwmon_ch_show; @@ -249,6 +250,7 @@ static int s3c_hwmon_create_attr(struct device *dev, attr = &attrs->label; attr->index = channel; + sysfs_attr_init(&attr->dev_attr.attr); attr->dev_attr.attr.name = attrs->label_name; attr->dev_attr.attr.mode = S_IRUGO; attr->dev_attr.show = s3c_hwmon_label_show; diff --git a/drivers/i2c/busses/i2c-taos-evm.c b/drivers/i2c/busses/i2c-taos-evm.c index dd39c1e..26c352a 100644 --- a/drivers/i2c/busses/i2c-taos-evm.c +++ b/drivers/i2c/busses/i2c-taos-evm.c @@ -234,7 +234,7 @@ static int taos_connect(struct serio *serio, struct serio_driver *drv) if (taos->state != TAOS_STATE_IDLE) { err = -ENODEV; - dev_dbg(&serio->dev, "TAOS EVM reset failed (state=%d, " + dev_err(&serio->dev, "TAOS EVM reset failed (state=%d, " "pos=%d)\n", taos->state, taos->pos); goto exit_close; } @@ -255,7 +255,7 @@ static int taos_connect(struct serio *serio, struct serio_driver *drv) msecs_to_jiffies(250)); if (taos->state != TAOS_STATE_IDLE) { err = -ENODEV; - dev_err(&adapter->dev, "Echo off failed " + dev_err(&serio->dev, "TAOS EVM echo off failed " "(state=%d)\n", taos->state); goto exit_close; } @@ -263,7 +263,7 @@ static int taos_connect(struct serio *serio, struct serio_driver *drv) err = i2c_add_adapter(adapter); if (err) goto exit_close; - dev_dbg(&serio->dev, "Connected to TAOS EVM\n"); + dev_info(&serio->dev, "Connected to TAOS EVM\n"); taos->client = taos_instantiate_device(adapter); return 0; @@ -288,7 +288,7 @@ static void taos_disconnect(struct serio *serio) serio_set_drvdata(serio, NULL); kfree(taos); - dev_dbg(&serio->dev, "Disconnected from TAOS EVM\n"); + dev_info(&serio->dev, "Disconnected from TAOS EVM\n"); } static struct serio_device_id taos_serio_ids[] = { diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c index 54e1ce7..6f89536 100644 --- a/drivers/i2c/muxes/pca954x.c +++ b/drivers/i2c/muxes/pca954x.c @@ -201,10 +201,11 @@ static int pca954x_probe(struct i2c_client *client, i2c_set_clientdata(client, data); - /* Read the mux register at addr to verify - * that the mux is in fact present. + /* Write the mux register at addr to verify + * that the mux is in fact present. This also + * initializes the mux to disconnected state. */ - if (i2c_smbus_read_byte(client) < 0) { + if (i2c_smbus_write_byte(client, 0) < 0) { dev_warn(&client->dev, "probe failed\n"); goto exit_free; } diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 144d272..04b0956 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -778,7 +778,8 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq, sector_t block) { struct ide_cmd cmd; - int uptodate = 0, nsectors; + int uptodate = 0; + unsigned int nsectors; ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, block: %llu", rq->cmd[0], (unsigned long long)block); diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index f660cd0..31fb440 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -1463,9 +1463,9 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb) struct c4iw_qp_attributes attrs; int disconnect = 1; int release = 0; - int abort = 0; struct tid_info *t = dev->rdev.lldi.tids; unsigned int tid = GET_TID(hdr); + int ret; ep = lookup_tid(t, tid); PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid); @@ -1501,10 +1501,12 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb) start_ep_timer(ep); __state_set(&ep->com, CLOSING); attrs.next_state = C4IW_QP_STATE_CLOSING; - abort = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, + ret = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); - peer_close_upcall(ep); - disconnect = 1; + if (ret != -ECONNRESET) { + peer_close_upcall(ep); + disconnect = 1; + } break; case ABORTING: disconnect = 0; @@ -2109,15 +2111,16 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp) break; } - mutex_unlock(&ep->com.mutex); if (close) { - if (abrupt) - ret = abort_connection(ep, NULL, gfp); - else + if (abrupt) { + close_complete_upcall(ep); + ret = send_abort(ep, NULL, gfp); + } else ret = send_halfclose(ep, gfp); if (ret) fatal = 1; } + mutex_unlock(&ep->com.mutex); if (fatal) release_ep_resources(ep); return ret; @@ -2301,6 +2304,31 @@ static int fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb) return 0; } +static int peer_abort_intr(struct c4iw_dev *dev, struct sk_buff *skb) +{ + struct cpl_abort_req_rss *req = cplhdr(skb); + struct c4iw_ep *ep; + struct tid_info *t = dev->rdev.lldi.tids; + unsigned int tid = GET_TID(req); + + ep = lookup_tid(t, tid); + if (is_neg_adv_abort(req->status)) { + PDBG("%s neg_adv_abort ep %p tid %u\n", __func__, ep, + ep->hwtid); + kfree_skb(skb); + return 0; + } + PDBG("%s ep %p tid %u state %u\n", __func__, ep, ep->hwtid, + ep->com.state); + + /* + * Wake up any threads in rdma_init() or rdma_fini(). + */ + c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET); + sched(dev, skb); + return 0; +} + /* * Most upcalls from the T4 Core go to sched() to * schedule the processing on a work queue. @@ -2317,7 +2345,7 @@ c4iw_handler_func c4iw_handlers[NUM_CPL_CMDS] = { [CPL_PASS_ESTABLISH] = sched, [CPL_PEER_CLOSE] = sched, [CPL_CLOSE_CON_RPL] = sched, - [CPL_ABORT_REQ_RSS] = sched, + [CPL_ABORT_REQ_RSS] = peer_abort_intr, [CPL_RDMA_TERMINATE] = sched, [CPL_FW4_ACK] = sched, [CPL_SET_TCB_RPL] = set_tcb_rpl, diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c index 8d8f8ad..1720dc7 100644 --- a/drivers/infiniband/hw/cxgb4/cq.c +++ b/drivers/infiniband/hw/cxgb4/cq.c @@ -801,6 +801,10 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries, if (ucontext) { memsize = roundup(memsize, PAGE_SIZE); hwentries = memsize / sizeof *chp->cq.queue; + while (hwentries > T4_MAX_IQ_SIZE) { + memsize -= PAGE_SIZE; + hwentries = memsize / sizeof *chp->cq.queue; + } } chp->cq.size = hwentries; chp->cq.memsize = memsize; diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c index 273ffe4..0347eed 100644 --- a/drivers/infiniband/hw/cxgb4/mem.c +++ b/drivers/infiniband/hw/cxgb4/mem.c @@ -625,7 +625,7 @@ pbl_done: mhp->attr.perms = c4iw_ib_to_tpt_access(acc); mhp->attr.va_fbo = virt; mhp->attr.page_size = shift - 12; - mhp->attr.len = (u32) length; + mhp->attr.len = length; err = register_mem(rhp, php, mhp, shift); if (err) diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 3b773b0..a41578e 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -1207,11 +1207,8 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, c4iw_get_ep(&qhp->ep->com); } ret = rdma_fini(rhp, qhp, ep); - if (ret) { - if (internal) - c4iw_get_ep(&qhp->ep->com); + if (ret) goto err; - } break; case C4IW_QP_STATE_TERMINATE: set_state(qhp, C4IW_QP_STATE_TERMINATE); diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 9f53e68..8ec5237 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -469,6 +469,8 @@ static u8 ib_rate_to_delay[IB_RATE_120_GBPS + 1] = { #define IB_7322_LT_STATE_RECOVERIDLE 0x0f #define IB_7322_LT_STATE_CFGENH 0x10 #define IB_7322_LT_STATE_CFGTEST 0x11 +#define IB_7322_LT_STATE_CFGWAITRMTTEST 0x12 +#define IB_7322_LT_STATE_CFGWAITENH 0x13 /* link state machine states from IBC */ #define IB_7322_L_STATE_DOWN 0x0 @@ -498,8 +500,10 @@ static const u8 qib_7322_physportstate[0x20] = { IB_PHYSPORTSTATE_LINK_ERR_RECOVER, [IB_7322_LT_STATE_CFGENH] = IB_PHYSPORTSTATE_CFG_ENH, [IB_7322_LT_STATE_CFGTEST] = IB_PHYSPORTSTATE_CFG_TRAIN, - [0x12] = IB_PHYSPORTSTATE_CFG_TRAIN, - [0x13] = IB_PHYSPORTSTATE_CFG_WAIT_ENH, + [IB_7322_LT_STATE_CFGWAITRMTTEST] = + IB_PHYSPORTSTATE_CFG_TRAIN, + [IB_7322_LT_STATE_CFGWAITENH] = + IB_PHYSPORTSTATE_CFG_WAIT_ENH, [0x14] = IB_PHYSPORTSTATE_CFG_TRAIN, [0x15] = IB_PHYSPORTSTATE_CFG_TRAIN, [0x16] = IB_PHYSPORTSTATE_CFG_TRAIN, @@ -1692,7 +1696,9 @@ static void handle_serdes_issues(struct qib_pportdata *ppd, u64 ibcst) break; } - if (ibclt == IB_7322_LT_STATE_CFGTEST && + if (((ibclt >= IB_7322_LT_STATE_CFGTEST && + ibclt <= IB_7322_LT_STATE_CFGWAITENH) || + ibclt == IB_7322_LT_STATE_LINKUP) && (ibcst & SYM_MASK(IBCStatusA_0, LinkSpeedQDR))) { force_h1(ppd); ppd->cpspec->qdr_reforce = 1; @@ -7301,12 +7307,17 @@ static void ibsd_wr_allchans(struct qib_pportdata *ppd, int addr, unsigned data, static void serdes_7322_los_enable(struct qib_pportdata *ppd, int enable) { u64 data = qib_read_kreg_port(ppd, krp_serdesctrl); - printk(KERN_INFO QIB_DRV_NAME " IB%u:%u Turning LOS %s\n", - ppd->dd->unit, ppd->port, (enable ? "on" : "off")); - if (enable) + u8 state = SYM_FIELD(data, IBSerdesCtrl_0, RXLOSEN); + + if (enable && !state) { + printk(KERN_INFO QIB_DRV_NAME " IB%u:%u Turning LOS on\n", + ppd->dd->unit, ppd->port); data |= SYM_MASK(IBSerdesCtrl_0, RXLOSEN); - else + } else if (!enable && state) { + printk(KERN_INFO QIB_DRV_NAME " IB%u:%u Turning LOS off\n", + ppd->dd->unit, ppd->port); data &= ~SYM_MASK(IBSerdesCtrl_0, RXLOSEN); + } qib_write_kreg_port(ppd, krp_serdesctrl, data); } diff --git a/drivers/infiniband/hw/qib/qib_intr.c b/drivers/infiniband/hw/qib/qib_intr.c index a693c56..6ae57d2 100644 --- a/drivers/infiniband/hw/qib/qib_intr.c +++ b/drivers/infiniband/hw/qib/qib_intr.c @@ -96,8 +96,12 @@ void qib_handle_e_ibstatuschanged(struct qib_pportdata *ppd, u64 ibcs) * states, or if it transitions from any of the up (INIT or better) * states into any of the down states (except link recovery), then * call the chip-specific code to take appropriate actions. + * + * ppd->lflags could be 0 if this is the first time the interrupt + * handlers has been called but the link is already up. */ - if (lstate >= IB_PORT_INIT && (ppd->lflags & QIBL_LINKDOWN) && + if (lstate >= IB_PORT_INIT && + (!ppd->lflags || (ppd->lflags & QIBL_LINKDOWN)) && ltstate == IB_PHYSPORTSTATE_LINKUP) { /* transitioned to UP */ if (dd->f_ib_updown(ppd, 1, ibcs)) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index be0921e..4cf2534 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -111,7 +111,8 @@ static void evdev_event(struct input_handle *handle, rcu_read_unlock(); - wake_up_interruptible(&evdev->wait); + if (type == EV_SYN && code == SYN_REPORT) + wake_up_interruptible(&evdev->wait); } static int evdev_fasync(int fd, struct file *file, int on) diff --git a/drivers/input/input.c b/drivers/input/input.c index 75e11c7..da38d97 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1756,7 +1756,7 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev) } else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) { mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum - dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1, - clamp(mt_slots, 2, 32); + mt_slots = clamp(mt_slots, 2, 32); } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) { mt_slots = 2; } else { diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index f23a743..33d0bdc 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -209,6 +209,7 @@ static void omap_kp_tasklet(unsigned long data) #endif } } + input_sync(omap_kp_data->input); memcpy(keypad_state, new_state, sizeof(keypad_state)); if (key_down) { diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index 834cf98..6876700 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -32,7 +32,7 @@ static const struct { [SH_KEYSC_MODE_3] = { 2, 4, 7 }, [SH_KEYSC_MODE_4] = { 3, 6, 6 }, [SH_KEYSC_MODE_5] = { 4, 6, 7 }, - [SH_KEYSC_MODE_6] = { 5, 7, 7 }, + [SH_KEYSC_MODE_6] = { 5, 8, 8 }, }; struct sh_keysc_priv { diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 257e033..0110b5a 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -187,7 +187,7 @@ static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, if (size == 0) size = xres ? : 1; - clamp(value, min, max); + value = clamp(value, min, max); mousedev->packet.x = ((value - min) * xres) / size; mousedev->packet.abs_event = 1; @@ -201,7 +201,7 @@ static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, if (size == 0) size = yres ? : 1; - clamp(value, min, max); + value = clamp(value, min, max); mousedev->packet.y = yres - ((value - min) * yres) / size; mousedev->packet.abs_event = 1; diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index 59de638..e35058b 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -156,8 +156,10 @@ static int if_open(struct tty_struct *tty, struct file *filp) if (!cs || !try_module_get(cs->driver->owner)) return -ENODEV; - if (mutex_lock_interruptible(&cs->mutex)) + if (mutex_lock_interruptible(&cs->mutex)) { + module_put(cs->driver->owner); return -ERESTARTSYS; + } tty->driver_data = cs; ++cs->open_count; diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c index 3ccbff1..71a8eb6 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c @@ -283,6 +283,7 @@ hfcsusb_ph_info(struct hfcsusb *hw) _queue_data(&dch->dev.D, MPH_INFORMATION_IND, MISDN_ID_ANY, sizeof(struct ph_info_dch) + dch->dev.nrbchan * sizeof(struct ph_info_ch), phi, GFP_ATOMIC); + kfree(phi); } /* diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 23f0d5e..713d43b 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -1,3 +1,10 @@ +config LEDS_GPIO_REGISTER + bool + help + This option provides the function gpio_led_register_device. + As this function is used by arch code it must not be compiled as a + module. + menuconfig NEW_LEDS bool "LED Support" help @@ -7,22 +14,14 @@ menuconfig NEW_LEDS This is not related to standard keyboard LEDs which are controlled via the input system. +if NEW_LEDS + config LEDS_CLASS bool "LED Class Support" - depends on NEW_LEDS help This option enables the led sysfs class in /sys/class/leds. You'll need this to do anything useful with LEDs. If unsure, say N. -config LEDS_GPIO_REGISTER - bool - help - This option provides the function gpio_led_register_device. - As this function is used by arch code it must not be compiled as a - module. - -if NEW_LEDS - comment "LED drivers" config LEDS_88PM860X @@ -391,6 +390,7 @@ config LEDS_NETXBIG config LEDS_ASIC3 bool "LED support for the HTC ASIC3" + depends on LEDS_CLASS depends on MFD_ASIC3 default y help diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index c0cff64..cc1dc48 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -593,7 +593,7 @@ static void lp5521_unregister_sysfs(struct i2c_client *client) &lp5521_led_attribute_group); } -static int __init lp5521_init_led(struct lp5521_led *led, +static int __devinit lp5521_init_led(struct lp5521_led *led, struct i2c_client *client, int chan, struct lp5521_platform_data *pdata) { @@ -637,7 +637,7 @@ static int __init lp5521_init_led(struct lp5521_led *led, return 0; } -static int lp5521_probe(struct i2c_client *client, +static int __devinit lp5521_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct lp5521_chip *chip; diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index e19fed2..5971e309 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -826,7 +826,7 @@ static int __init lp5523_init_engine(struct lp5523_engine *engine, int id) return 0; } -static int __init lp5523_init_led(struct lp5523_led *led, struct device *dev, +static int __devinit lp5523_init_led(struct lp5523_led *led, struct device *dev, int chan, struct lp5523_platform_data *pdata) { char name[32]; @@ -872,7 +872,7 @@ static int __init lp5523_init_led(struct lp5523_led *led, struct device *dev, static struct i2c_driver lp5523_driver; -static int lp5523_probe(struct i2c_client *client, +static int __devinit lp5523_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct lp5523_chip *chip; diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 70bd738..574b09a 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -534,6 +534,82 @@ void bitmap_print_sb(struct bitmap *bitmap) kunmap_atomic(sb, KM_USER0); } +/* + * bitmap_new_disk_sb + * @bitmap + * + * This function is somewhat the reverse of bitmap_read_sb. bitmap_read_sb + * reads and verifies the on-disk bitmap superblock and populates bitmap_info. + * This function verifies 'bitmap_info' and populates the on-disk bitmap + * structure, which is to be written to disk. + * + * Returns: 0 on success, -Exxx on error + */ +static int bitmap_new_disk_sb(struct bitmap *bitmap) +{ + bitmap_super_t *sb; + unsigned long chunksize, daemon_sleep, write_behind; + int err = -EINVAL; + + bitmap->sb_page = alloc_page(GFP_KERNEL); + if (IS_ERR(bitmap->sb_page)) { + err = PTR_ERR(bitmap->sb_page); + bitmap->sb_page = NULL; + return err; + } + bitmap->sb_page->index = 0; + + sb = kmap_atomic(bitmap->sb_page, KM_USER0); + + sb->magic = cpu_to_le32(BITMAP_MAGIC); + sb->version = cpu_to_le32(BITMAP_MAJOR_HI); + + chunksize = bitmap->mddev->bitmap_info.chunksize; + BUG_ON(!chunksize); + if (!is_power_of_2(chunksize)) { + kunmap_atomic(sb, KM_USER0); + printk(KERN_ERR "bitmap chunksize not a power of 2\n"); + return -EINVAL; + } + sb->chunksize = cpu_to_le32(chunksize); + + daemon_sleep = bitmap->mddev->bitmap_info.daemon_sleep; + if (!daemon_sleep || + (daemon_sleep < 1) || (daemon_sleep > MAX_SCHEDULE_TIMEOUT)) { + printk(KERN_INFO "Choosing daemon_sleep default (5 sec)\n"); + daemon_sleep = 5 * HZ; + } + sb->daemon_sleep = cpu_to_le32(daemon_sleep); + bitmap->mddev->bitmap_info.daemon_sleep = daemon_sleep; + + /* + * FIXME: write_behind for RAID1. If not specified, what + * is a good choice? We choose COUNTER_MAX / 2 arbitrarily. + */ + write_behind = bitmap->mddev->bitmap_info.max_write_behind; + if (write_behind > COUNTER_MAX) + write_behind = COUNTER_MAX / 2; + sb->write_behind = cpu_to_le32(write_behind); + bitmap->mddev->bitmap_info.max_write_behind = write_behind; + + /* keep the array size field of the bitmap superblock up to date */ + sb->sync_size = cpu_to_le64(bitmap->mddev->resync_max_sectors); + + memcpy(sb->uuid, bitmap->mddev->uuid, 16); + + bitmap->flags |= BITMAP_STALE; + sb->state |= cpu_to_le32(BITMAP_STALE); + bitmap->events_cleared = bitmap->mddev->events; + sb->events_cleared = cpu_to_le64(bitmap->mddev->events); + + bitmap->flags |= BITMAP_HOSTENDIAN; + sb->version = cpu_to_le32(BITMAP_MAJOR_HOSTENDIAN); + + kunmap_atomic(sb, KM_USER0); + + return 0; +} + /* read the superblock from the bitmap file and initialize some bitmap fields */ static int bitmap_read_sb(struct bitmap *bitmap) { @@ -575,7 +651,7 @@ static int bitmap_read_sb(struct bitmap *bitmap) reason = "unrecognized superblock version"; else if (chunksize < 512) reason = "bitmap chunksize too small"; - else if ((1 << ffz(~chunksize)) != chunksize) + else if (!is_power_of_2(chunksize)) reason = "bitmap chunksize not a power of 2"; else if (daemon_sleep < 1 || daemon_sleep > MAX_SCHEDULE_TIMEOUT) reason = "daemon sleep period out of range"; @@ -1076,8 +1152,8 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) } printk(KERN_INFO "%s: bitmap initialized from disk: " - "read %lu/%lu pages, set %lu bits\n", - bmname(bitmap), bitmap->file_pages, num_pages, bit_cnt); + "read %lu/%lu pages, set %lu of %lu bits\n", + bmname(bitmap), bitmap->file_pages, num_pages, bit_cnt, chunks); return 0; @@ -1332,7 +1408,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect return 0; } - if (unlikely((*bmc & COUNTER_MAX) == COUNTER_MAX)) { + if (unlikely(COUNTER(*bmc) == COUNTER_MAX)) { DEFINE_WAIT(__wait); /* note that it is safe to do the prepare_to_wait * after the test as long as we do it before dropping @@ -1404,10 +1480,10 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto sysfs_notify_dirent_safe(bitmap->sysfs_can_clear); } - if (!success && ! (*bmc & NEEDED_MASK)) + if (!success && !NEEDED(*bmc)) *bmc |= NEEDED_MASK; - if ((*bmc & COUNTER_MAX) == COUNTER_MAX) + if (COUNTER(*bmc) == COUNTER_MAX) wake_up(&bitmap->overflow_wait); (*bmc)--; @@ -1728,9 +1804,16 @@ int bitmap_create(mddev_t *mddev) vfs_fsync(file, 1); } /* read superblock from bitmap file (this sets mddev->bitmap_info.chunksize) */ - if (!mddev->bitmap_info.external) - err = bitmap_read_sb(bitmap); - else { + if (!mddev->bitmap_info.external) { + /* + * If 'MD_ARRAY_FIRST_USE' is set, then device-mapper is + * instructing us to create a new on-disk bitmap instance. + */ + if (test_and_clear_bit(MD_ARRAY_FIRST_USE, &mddev->flags)) + err = bitmap_new_disk_sb(bitmap); + else + err = bitmap_read_sb(bitmap); + } else { err = 0; if (mddev->bitmap_info.chunksize == 0 || mddev->bitmap_info.daemon_sleep == 0) @@ -1754,9 +1837,6 @@ int bitmap_create(mddev_t *mddev) bitmap->chunks = chunks; bitmap->pages = pages; bitmap->missing_pages = pages; - bitmap->counter_bits = COUNTER_BITS; - - bitmap->syncchunk = ~0UL; #ifdef INJECT_FATAL_FAULT_1 bitmap->bp = NULL; diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h index d0aeaf4..b2a127e 100644 --- a/drivers/md/bitmap.h +++ b/drivers/md/bitmap.h @@ -85,7 +85,6 @@ typedef __u16 bitmap_counter_t; #define COUNTER_BITS 16 #define COUNTER_BIT_SHIFT 4 -#define COUNTER_BYTE_RATIO (COUNTER_BITS / 8) #define COUNTER_BYTE_SHIFT (COUNTER_BIT_SHIFT - 3) #define NEEDED_MASK ((bitmap_counter_t) (1 << (COUNTER_BITS - 1))) @@ -196,19 +195,10 @@ struct bitmap { mddev_t *mddev; /* the md device that the bitmap is for */ - int counter_bits; /* how many bits per block counter */ - /* bitmap chunksize -- how much data does each bit represent? */ unsigned long chunkshift; /* chunksize = 2^chunkshift (for bitops) */ unsigned long chunks; /* total number of data chunks for the array */ - /* We hold a count on the chunk currently being synced, and drop - * it when the last block is started. If the resync is aborted - * midway, we need to be able to drop that count, so we remember - * the counted chunk.. - */ - unsigned long syncchunk; - __u64 events_cleared; int need_sync; diff --git a/drivers/md/md.c b/drivers/md/md.c index aa640a8..91e31e2 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -351,6 +351,9 @@ void mddev_resume(mddev_t *mddev) mddev->suspended = 0; wake_up(&mddev->sb_wait); mddev->pers->quiesce(mddev, 0); + + md_wakeup_thread(mddev->thread); + md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */ } EXPORT_SYMBOL_GPL(mddev_resume); @@ -1750,6 +1753,18 @@ static struct super_type super_types[] = { }, }; +static void sync_super(mddev_t *mddev, mdk_rdev_t *rdev) +{ + if (mddev->sync_super) { + mddev->sync_super(mddev, rdev); + return; + } + + BUG_ON(mddev->major_version >= ARRAY_SIZE(super_types)); + + super_types[mddev->major_version].sync_super(mddev, rdev); +} + static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2) { mdk_rdev_t *rdev, *rdev2; @@ -1781,8 +1796,8 @@ int md_integrity_register(mddev_t *mddev) if (list_empty(&mddev->disks)) return 0; /* nothing to do */ - if (blk_get_integrity(mddev->gendisk)) - return 0; /* already registered */ + if (!mddev->gendisk || blk_get_integrity(mddev->gendisk)) + return 0; /* shouldn't register, or already is */ list_for_each_entry(rdev, &mddev->disks, same_set) { /* skip spares and non-functional disks */ if (test_bit(Faulty, &rdev->flags)) @@ -2168,8 +2183,7 @@ static void sync_sbs(mddev_t * mddev, int nospares) /* Don't update this superblock */ rdev->sb_loaded = 2; } else { - super_types[mddev->major_version]. - sync_super(mddev, rdev); + sync_super(mddev, rdev); rdev->sb_loaded = 1; } } @@ -2462,7 +2476,7 @@ slot_store(mdk_rdev_t *rdev, const char *buf, size_t len) if (rdev->raid_disk == -1) return -EEXIST; /* personality does all needed checks */ - if (rdev->mddev->pers->hot_add_disk == NULL) + if (rdev->mddev->pers->hot_remove_disk == NULL) return -EINVAL; err = rdev->mddev->pers-> hot_remove_disk(rdev->mddev, rdev->raid_disk); @@ -4619,9 +4633,6 @@ int md_run(mddev_t *mddev) if (mddev->flags) md_update_sb(mddev, 0); - md_wakeup_thread(mddev->thread); - md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */ - md_new_event(mddev); sysfs_notify_dirent_safe(mddev->sysfs_state); sysfs_notify_dirent_safe(mddev->sysfs_action); @@ -4642,6 +4653,10 @@ static int do_md_run(mddev_t *mddev) bitmap_destroy(mddev); goto out; } + + md_wakeup_thread(mddev->thread); + md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */ + set_capacity(mddev->gendisk, mddev->array_sectors); revalidate_disk(mddev->gendisk); mddev->changed = 1; @@ -5259,6 +5274,8 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) if (mddev->degraded) set_bit(MD_RECOVERY_RECOVER, &mddev->recovery); set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); + if (!err) + md_new_event(mddev); md_wakeup_thread(mddev->thread); return err; } @@ -6866,8 +6883,8 @@ void md_do_sync(mddev_t *mddev) * Tune reconstruction: */ window = 32*(PAGE_SIZE/512); - printk(KERN_INFO "md: using %dk window, over a total of %llu blocks.\n", - window/2,(unsigned long long) max_sectors/2); + printk(KERN_INFO "md: using %dk window, over a total of %lluk.\n", + window/2, (unsigned long long)max_sectors/2); atomic_set(&mddev->recovery_active, 0); last_check = 0; @@ -7045,7 +7062,6 @@ void md_do_sync(mddev_t *mddev) } EXPORT_SYMBOL_GPL(md_do_sync); - static int remove_and_add_spares(mddev_t *mddev) { mdk_rdev_t *rdev; @@ -7072,6 +7088,7 @@ static int remove_and_add_spares(mddev_t *mddev) list_for_each_entry(rdev, &mddev->disks, same_set) { if (rdev->raid_disk >= 0 && !test_bit(In_sync, &rdev->flags) && + !test_bit(Faulty, &rdev->flags) && !test_bit(Blocked, &rdev->flags)) spares++; if (rdev->raid_disk < 0 @@ -7157,6 +7174,9 @@ static void reap_sync_thread(mddev_t *mddev) */ void md_check_recovery(mddev_t *mddev) { + if (mddev->suspended) + return; + if (mddev->bitmap) bitmap_daemon_work(mddev); diff --git a/drivers/md/md.h b/drivers/md/md.h index 0b1fd3f..1c26c7a 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -124,6 +124,7 @@ struct mddev_s #define MD_CHANGE_DEVS 0 /* Some device status has changed */ #define MD_CHANGE_CLEAN 1 /* transition to or from 'clean' */ #define MD_CHANGE_PENDING 2 /* switch from 'clean' to 'active' in progress */ +#define MD_ARRAY_FIRST_USE 3 /* First use of array, needs initialization */ int suspended; atomic_t active_io; @@ -330,6 +331,7 @@ struct mddev_s atomic_t flush_pending; struct work_struct flush_work; struct work_struct event_work; /* used by dm to report failure event */ + void (*sync_super)(mddev_t *mddev, mdk_rdev_t *rdev); }; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 5d09609..f7431b6 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -497,21 +497,19 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio) return best_disk; } -static int raid1_congested(void *data, int bits) +int md_raid1_congested(mddev_t *mddev, int bits) { - mddev_t *mddev = data; conf_t *conf = mddev->private; int i, ret = 0; - if (mddev_congested(mddev, bits)) - return 1; - rcu_read_lock(); for (i = 0; i < mddev->raid_disks; i++) { mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev); if (rdev && !test_bit(Faulty, &rdev->flags)) { struct request_queue *q = bdev_get_queue(rdev->bdev); + BUG_ON(!q); + /* Note the '|| 1' - when read_balance prefers * non-congested targets, it can be removed */ @@ -524,7 +522,15 @@ static int raid1_congested(void *data, int bits) rcu_read_unlock(); return ret; } +EXPORT_SYMBOL_GPL(md_raid1_congested); +static int raid1_congested(void *data, int bits) +{ + mddev_t *mddev = data; + + return mddev_congested(mddev, bits) || + md_raid1_congested(mddev, bits); +} static void flush_pending_writes(conf_t *conf) { @@ -1972,6 +1978,8 @@ static int run(mddev_t *mddev) return PTR_ERR(conf); list_for_each_entry(rdev, &mddev->disks, same_set) { + if (!mddev->gendisk) + continue; disk_stack_limits(mddev->gendisk, rdev->bdev, rdev->data_offset << 9); /* as we don't honour merge_bvec_fn, we must never risk @@ -2013,8 +2021,10 @@ static int run(mddev_t *mddev) md_set_array_sectors(mddev, raid1_size(mddev, 0, 0)); - mddev->queue->backing_dev_info.congested_fn = raid1_congested; - mddev->queue->backing_dev_info.congested_data = mddev; + if (mddev->queue) { + mddev->queue->backing_dev_info.congested_fn = raid1_congested; + mddev->queue->backing_dev_info.congested_data = mddev; + } return md_integrity_register(mddev); } diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h index 5fc4ca1..e743a64 100644 --- a/drivers/md/raid1.h +++ b/drivers/md/raid1.h @@ -126,4 +126,6 @@ struct r1bio_s { */ #define R1BIO_Returned 6 +extern int md_raid1_congested(mddev_t *mddev, int bits); + #endif diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 346e69b..b72edf3 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -129,7 +129,7 @@ static inline int raid5_dec_bi_hw_segments(struct bio *bio) static inline void raid5_set_bi_hw_segments(struct bio *bio, unsigned int cnt) { - bio->bi_phys_segments = raid5_bi_phys_segments(bio) || (cnt << 16); + bio->bi_phys_segments = raid5_bi_phys_segments(bio) | (cnt << 16); } /* Find first data disk in a raid6 stripe */ @@ -514,7 +514,7 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) bi = &sh->dev[i].req; bi->bi_rw = rw; - if (rw == WRITE) + if (rw & WRITE) bi->bi_end_io = raid5_end_write_request; else bi->bi_end_io = raid5_end_read_request; @@ -548,13 +548,13 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) bi->bi_io_vec[0].bv_offset = 0; bi->bi_size = STRIPE_SIZE; bi->bi_next = NULL; - if (rw == WRITE && + if ((rw & WRITE) && test_bit(R5_ReWrite, &sh->dev[i].flags)) atomic_add(STRIPE_SECTORS, &rdev->corrected_errors); generic_make_request(bi); } else { - if (rw == WRITE) + if (rw & WRITE) set_bit(STRIPE_DEGRADED, &sh->state); pr_debug("skip op %ld on disc %d for sector %llu\n", bi->bi_rw, i, (unsigned long long)sh->sector); @@ -585,7 +585,7 @@ async_copy_data(int frombio, struct bio *bio, struct page *page, init_async_submit(&submit, flags, tx, NULL, NULL, NULL); bio_for_each_segment(bvl, bio, i) { - int len = bio_iovec_idx(bio, i)->bv_len; + int len = bvl->bv_len; int clen; int b_offset = 0; @@ -601,8 +601,8 @@ async_copy_data(int frombio, struct bio *bio, struct page *page, clen = len; if (clen > 0) { - b_offset += bio_iovec_idx(bio, i)->bv_offset; - bio_page = bio_iovec_idx(bio, i)->bv_page; + b_offset += bvl->bv_offset; + bio_page = bvl->bv_page; if (frombio) tx = async_memcpy(page, bio_page, page_offset, b_offset, clen, &submit); @@ -4858,7 +4858,7 @@ static raid5_conf_t *setup_conf(mddev_t *mddev) printk(KERN_INFO "md/raid:%s: device %s operational as raid" " disk %d\n", mdname(mddev), bdevname(rdev->bdev, b), raid_disk); - } else + } else if (rdev->saved_raid_disk != raid_disk) /* Cannot rely on bitmap to complete recovery */ conf->fullsync = 1; } diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 2354336..934185c 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -25,8 +25,8 @@ #include <linux/delay.h> #include <media/cx25840.h> #include <linux/firmware.h> -#include <staging/altera.h> +#include "../../../staging/altera-stapl/altera.h" #include "cx23885.h" #include "tuner-xc2028.h" #include "netup-init.h" diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c index 200311f..e2a52e5 100644 --- a/drivers/misc/apds990x.c +++ b/drivers/misc/apds990x.c @@ -609,6 +609,7 @@ static int apds990x_detect(struct apds990x_chip *chip) return ret; } +#if defined(CONFIG_PM) || defined(CONFIG_PM_RUNTIME) static int apds990x_chip_on(struct apds990x_chip *chip) { int err = regulator_bulk_enable(ARRAY_SIZE(chip->regs), @@ -624,6 +625,7 @@ static int apds990x_chip_on(struct apds990x_chip *chip) apds990x_mode_on(chip); return 0; } +#endif static int apds990x_chip_off(struct apds990x_chip *chip) { diff --git a/drivers/misc/cb710/sgbuf2.c b/drivers/misc/cb710/sgbuf2.c index d019746..2a40d0e 100644 --- a/drivers/misc/cb710/sgbuf2.c +++ b/drivers/misc/cb710/sgbuf2.c @@ -47,7 +47,7 @@ static uint32_t sg_dwiter_read_buffer(struct sg_mapping_iter *miter) static inline bool needs_unaligned_copy(const void *ptr) { -#ifdef HAVE_EFFICIENT_UNALIGNED_ACCESS +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS return false; #else return ((ptr - NULL) & 3) != 0; diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c index e01e08c..bc685bfc 100644 --- a/drivers/misc/cs5535-mfgpt.c +++ b/drivers/misc/cs5535-mfgpt.c @@ -174,7 +174,7 @@ struct cs5535_mfgpt_timer *cs5535_mfgpt_alloc_timer(int timer_nr, int domain) timer_nr = t < max ? (int) t : -1; } else { /* check if the requested timer's available */ - if (test_bit(timer_nr, mfgpt->avail)) + if (!test_bit(timer_nr, mfgpt->avail)) timer_nr = -1; } diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c index 668d41e..df03dd3 100644 --- a/drivers/misc/ioc4.c +++ b/drivers/misc/ioc4.c @@ -270,7 +270,7 @@ ioc4_variant(struct ioc4_driver_data *idd) return IOC4_VARIANT_PCI_RT; } -static void __devinit +static void ioc4_load_modules(struct work_struct *work) { request_module("sgiioc4"); diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c index 81d7fa4..150cd70 100644 --- a/drivers/misc/lkdtm.c +++ b/drivers/misc/lkdtm.c @@ -120,6 +120,7 @@ static int recur_count = REC_NUM_DEFAULT; static enum cname cpoint = CN_INVALID; static enum ctype cptype = CT_NONE; static int count = DEFAULT_COUNT; +static DEFINE_SPINLOCK(count_lock); module_param(recur_count, int, 0644); MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\ @@ -230,11 +231,14 @@ static const char *cp_name_to_str(enum cname name) static int lkdtm_parse_commandline(void) { int i; + unsigned long flags; if (cpoint_count < 1 || recur_count < 1) return -EINVAL; + spin_lock_irqsave(&count_lock, flags); count = cpoint_count; + spin_unlock_irqrestore(&count_lock, flags); /* No special parameters */ if (!cpoint_type && !cpoint_name) @@ -349,6 +353,9 @@ static void lkdtm_do_action(enum ctype which) static void lkdtm_handler(void) { + unsigned long flags; + + spin_lock_irqsave(&count_lock, flags); count--; printk(KERN_INFO "lkdtm: Crash point %s of type %s hit, trigger in %d rounds\n", cp_name_to_str(cpoint), cp_type_to_str(cptype), count); @@ -357,6 +364,7 @@ static void lkdtm_handler(void) lkdtm_do_action(cptype); count = cpoint_count; } + spin_unlock_irqrestore(&count_lock, flags); } static int lkdtm_register_cpoint(enum cname which) diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index bb6f925..374dfcf 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -317,7 +317,8 @@ EXPORT_SYMBOL_GPL(pti_request_masterchannel); * a master, channel ID address * used to write to PTI HW. * - * @mc: master, channel apeture ID address to be released. + * @mc: master, channel apeture ID address to be released. This + * will de-allocate the structure via kfree(). */ void pti_release_masterchannel(struct pti_masterchannel *mc) { @@ -475,8 +476,10 @@ static int pti_tty_install(struct tty_driver *driver, struct tty_struct *tty) else pti_tty_data->mc = pti_request_masterchannel(2); - if (pti_tty_data->mc == NULL) + if (pti_tty_data->mc == NULL) { + kfree(pti_tty_data); return -ENXIO; + } tty->driver_data = pti_tty_data; } @@ -495,7 +498,7 @@ static void pti_tty_cleanup(struct tty_struct *tty) if (pti_tty_data == NULL) return; pti_release_masterchannel(pti_tty_data->mc); - kfree(tty->driver_data); + kfree(pti_tty_data); tty->driver_data = NULL; } @@ -581,7 +584,7 @@ static int pti_char_open(struct inode *inode, struct file *filp) static int pti_char_release(struct inode *inode, struct file *filp) { pti_release_masterchannel(filp->private_data); - kfree(filp->private_data); + filp->private_data = NULL; return 0; } diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index ee5109a..42f0673 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -495,14 +495,14 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } } + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + if (atomic_dec_return(&queued_msg->use_count) == 0) { dev_kfree_skb(skb); kfree(queued_msg); } - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - return NETDEV_TX_OK; } diff --git a/drivers/misc/spear13xx_pcie_gadget.c b/drivers/misc/spear13xx_pcie_gadget.c index 7aded90..cfbddbe 100644 --- a/drivers/misc/spear13xx_pcie_gadget.c +++ b/drivers/misc/spear13xx_pcie_gadget.c @@ -845,7 +845,7 @@ err_iounmap: err_iounmap_app: iounmap(config->va_app_base); err_kzalloc: - kfree(config); + kfree(target); err_rel_res: release_mem_region(res1->start, resource_size(res1)); err_rel_res0: diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c index f91f82e..54c91ff 100644 --- a/drivers/misc/ti-st/st_core.c +++ b/drivers/misc/ti-st/st_core.c @@ -605,7 +605,7 @@ long st_unregister(struct st_proto_s *proto) pr_debug("%s: %d ", __func__, proto->chnl_id); st_kim_ref(&st_gdata, 0); - if (proto->chnl_id >= ST_MAX_CHANNELS) { + if (!st_gdata || proto->chnl_id >= ST_MAX_CHANNELS) { pr_err(" chnl_id %d not supported", proto->chnl_id); return -EPROTONOSUPPORT; } diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 5da93ee..38fd2f0 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -245,9 +245,9 @@ void skip_change_remote_baud(unsigned char **ptr, long *len) pr_err("invalid action after change remote baud command"); } else { *ptr = *ptr + sizeof(struct bts_action) + - ((struct bts_action *)nxt_action)->size; + ((struct bts_action *)cur_action)->size; *len = *len - (sizeof(struct bts_action) + - ((struct bts_action *)nxt_action)->size); + ((struct bts_action *)cur_action)->size); /* warn user on not commenting these in firmware */ pr_warn("skipping the wait event of change remote baud"); } @@ -604,6 +604,10 @@ void st_kim_ref(struct st_data_s **core_data, int id) struct kim_data_s *kim_gdata; /* get kim_gdata reference from platform device */ pdev = st_get_plat_device(id); + if (!pdev) { + *core_data = NULL; + return; + } kim_gdata = dev_get_drvdata(&pdev->dev); *core_data = kim_gdata->core_data; } diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 71da564..f85e422 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1024,7 +1024,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, INIT_LIST_HEAD(&md->part); md->usage = 1; - ret = mmc_init_queue(&md->queue, card, &md->lock); + ret = mmc_init_queue(&md->queue, card, &md->lock, subname); if (ret) goto err_putdisk; @@ -1297,6 +1297,9 @@ static void mmc_blk_remove(struct mmc_card *card) struct mmc_blk_data *md = mmc_get_drvdata(card); mmc_blk_remove_parts(card, md); + mmc_claim_host(card->host); + mmc_blk_part_switch(card, md); + mmc_release_host(card->host); mmc_blk_remove_req(md); mmc_set_drvdata(card, NULL); } diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index c07322c..6413afa 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -106,10 +106,12 @@ static void mmc_request(struct request_queue *q) * @mq: mmc queue * @card: mmc card to attach this queue * @lock: queue lock + * @subname: partition subname * * Initialise a MMC card request queue. */ -int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock) +int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, + spinlock_t *lock, const char *subname) { struct mmc_host *host = card->host; u64 limit = BLK_BOUNCE_HIGH; @@ -133,12 +135,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock mq->queue->limits.max_discard_sectors = UINT_MAX; if (card->erased_byte == 0) mq->queue->limits.discard_zeroes_data = 1; - if (!mmc_can_trim(card) && is_power_of_2(card->erase_size)) { - mq->queue->limits.discard_granularity = - card->erase_size << 9; - mq->queue->limits.discard_alignment = - card->erase_size << 9; - } + mq->queue->limits.discard_granularity = card->pref_erase << 9; if (mmc_can_secure_erase_trim(card)) queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, mq->queue); @@ -209,8 +206,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock sema_init(&mq->thread_sem, 1); - mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d", - host->index); + mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d%s", + host->index, subname ? subname : ""); if (IS_ERR(mq->thread)) { ret = PTR_ERR(mq->thread); diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h index 64e66e0..6223ef8 100644 --- a/drivers/mmc/card/queue.h +++ b/drivers/mmc/card/queue.h @@ -19,7 +19,8 @@ struct mmc_queue { unsigned int bounce_sg_len; }; -extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *); +extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *, + const char *); extern void mmc_cleanup_queue(struct mmc_queue *); extern void mmc_queue_suspend(struct mmc_queue *); extern void mmc_queue_resume(struct mmc_queue *); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 68091dd..7843efe 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1245,7 +1245,7 @@ static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card, */ timeout_clks <<= 1; timeout_us += (timeout_clks * 1000) / - (card->host->ios.clock / 1000); + (mmc_host_clk_rate(card->host) / 1000); erase_timeout = timeout_us / 1000; diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 4d0c15b..262fff0 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -691,15 +691,54 @@ static int mmc_sdio_resume(struct mmc_host *host) static int mmc_sdio_power_restore(struct mmc_host *host) { int ret; + u32 ocr; BUG_ON(!host); BUG_ON(!host->card); mmc_claim_host(host); + + /* + * Reset the card by performing the same steps that are taken by + * mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe. + * + * sdio_reset() is technically not needed. Having just powered up the + * hardware, it should already be in reset state. However, some + * platforms (such as SD8686 on OLPC) do not instantly cut power, + * meaning that a reset is required when restoring power soon after + * powering off. It is harmless in other cases. + * + * The CMD5 reset (mmc_send_io_op_cond()), according to the SDIO spec, + * is not necessary for non-removable cards. However, it is required + * for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and + * harmless in other situations. + * + * With these steps taken, mmc_select_voltage() is also required to + * restore the correct voltage setting of the card. + */ + sdio_reset(host); + mmc_go_idle(host); + mmc_send_if_cond(host, host->ocr_avail); + + ret = mmc_send_io_op_cond(host, 0, &ocr); + if (ret) + goto out; + + if (host->ocr_avail_sdio) + host->ocr_avail = host->ocr_avail_sdio; + + host->ocr = mmc_select_voltage(host, ocr & ~0x7F); + if (!host->ocr) { + ret = -EINVAL; + goto out; + } + ret = mmc_sdio_init_card(host, host->ocr, host->card, mmc_card_keep_power(host)); if (!ret && host->sdio_irqs) mmc_signal_sdio_irq(host); + +out: mmc_release_host(host); return ret; diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index d29b9c3..d2565df 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -189,7 +189,7 @@ static int sdio_bus_remove(struct device *dev) /* Then undo the runtime PM settings in sdio_bus_probe() */ if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) - pm_runtime_put_noidle(dev); + pm_runtime_put_sync(dev); out: return ret; diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 5da5bea0..7721de9 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1144,9 +1144,17 @@ static int __devinit mmci_probe(struct amba_device *dev, else if (ret != -ENOSYS) goto err_gpio_cd; + /* + * A gpio pin that will detect cards when inserted and removed + * will most likely want to trigger on the edges if it is + * 0 when ejected and 1 when inserted (or mutatis mutandis + * for the inverted case) so we request triggers on both + * edges. + */ ret = request_any_context_irq(gpio_to_irq(plat->gpio_cd), - mmci_cd_irq, 0, - DRIVER_NAME " (cd)", host); + mmci_cd_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + DRIVER_NAME " (cd)", host); if (ret >= 0) host->gpio_cd_irq = gpio_to_irq(plat->gpio_cd); } diff --git a/drivers/mmc/host/of_mmc_spi.c b/drivers/mmc/host/of_mmc_spi.c index e2aecb7..ab66f24 100644 --- a/drivers/mmc/host/of_mmc_spi.c +++ b/drivers/mmc/host/of_mmc_spi.c @@ -25,6 +25,11 @@ #include <linux/mmc/core.h> #include <linux/mmc/host.h> +/* For archs that don't support NO_IRQ (such as mips), provide a dummy value */ +#ifndef NO_IRQ +#define NO_IRQ 0 +#endif + MODULE_LICENSE("GPL"); enum { diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 5b2e215..dedf3da 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -429,7 +429,6 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) return -EINVAL; } } - mmc_slot(host).ocr_mask = mmc_regulator_get_ocrmask(reg); /* Allow an aux regulator */ reg = regulator_get(host->dev, "vmmc_aux"); @@ -962,7 +961,8 @@ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) spin_unlock(&host->irq_lock); if (host->use_dma && dma_ch != -1) { - dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->dma_len, + dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, + host->data->sg_len, omap_hsmmc_get_dma_dir(host, host->data)); omap_free_dma(dma_ch); } @@ -1346,7 +1346,7 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) return; } - dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len, + dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, omap_hsmmc_get_dma_dir(host, data)); req_in_progress = host->req_in_progress; diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index b365429..ce500f0 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -92,7 +92,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) mmc_data->ocr_mask = p->tmio_ocr_mask; mmc_data->capabilities |= p->tmio_caps; - if (p->dma_slave_tx >= 0 && p->dma_slave_rx >= 0) { + if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) { priv->param_tx.slave_id = p->dma_slave_tx; priv->param_rx.slave_id = p->dma_slave_rx; priv->dma_priv.chan_priv_tx = &priv->param_tx; @@ -165,13 +165,14 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev) p->pdata = NULL; + tmio_mmc_host_remove(host); + for (i = 0; i < 3; i++) { irq = platform_get_irq(pdev, i); if (irq >= 0) free_irq(irq, host); } - tmio_mmc_host_remove(host); clk_disable(priv->clk); clk_put(priv->clk); kfree(priv); diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index ad6347b..0b09e82 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -824,8 +824,8 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc) struct tmio_mmc_host *host = mmc_priv(mmc); struct tmio_mmc_data *pdata = host->pdata; - return ((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) || - !(sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)); + return !((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) || + (sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)); } static int tmio_mmc_get_cd(struct mmc_host *mmc) diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index cbb0330..d4455ff 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -2096,7 +2096,7 @@ static struct mmc_host_ops vub300_mmc_ops = { static int vub300_probe(struct usb_interface *interface, const struct usb_device_id *id) { /* NOT irq */ - struct vub300_mmc_host *vub300 = NULL; + struct vub300_mmc_host *vub300; struct usb_host_interface *iface_desc; struct usb_device *udev = usb_get_dev(interface_to_usbdev(interface)); int i; @@ -2118,23 +2118,20 @@ static int vub300_probe(struct usb_interface *interface, command_out_urb = usb_alloc_urb(0, GFP_KERNEL); if (!command_out_urb) { retval = -ENOMEM; - dev_err(&vub300->udev->dev, - "not enough memory for the command_out_urb\n"); + dev_err(&udev->dev, "not enough memory for command_out_urb\n"); goto error0; } command_res_urb = usb_alloc_urb(0, GFP_KERNEL); if (!command_res_urb) { retval = -ENOMEM; - dev_err(&vub300->udev->dev, - "not enough memory for the command_res_urb\n"); + dev_err(&udev->dev, "not enough memory for command_res_urb\n"); goto error1; } /* this also allocates memory for our VUB300 mmc host device */ mmc = mmc_alloc_host(sizeof(struct vub300_mmc_host), &udev->dev); if (!mmc) { retval = -ENOMEM; - dev_err(&vub300->udev->dev, - "not enough memory for the mmc_host\n"); + dev_err(&udev->dev, "not enough memory for the mmc_host\n"); goto error4; } /* MMC core transfer sizes tunable parameters */ diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 0bb254c..33d8aad 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -339,9 +339,9 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, (FIR_OP_UA << FIR_OP1_SHIFT) | (FIR_OP_RBW << FIR_OP2_SHIFT)); out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT); - /* 5 bytes for manuf, device and exts */ - out_be32(&lbc->fbcr, 5); - elbc_fcm_ctrl->read_bytes = 5; + /* nand_get_flash_type() reads 8 bytes of entire ID string */ + out_be32(&lbc->fbcr, 8); + elbc_fcm_ctrl->read_bytes = 8; elbc_fcm_ctrl->use_mdr = 1; elbc_fcm_ctrl->mdr = 0; diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index d84f6e8..5b73298 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -412,7 +412,7 @@ el2_open(struct net_device *dev) outb_p(0x04 << ((*irqp == 9) ? 2 : *irqp), E33G_IDCFR); outb_p(0x00, E33G_IDCFR); msleep(1); - free_irq(*irqp, el2_probe_interrupt); + free_irq(*irqp, &seen); if (!seen) continue; @@ -422,6 +422,7 @@ el2_open(struct net_device *dev) continue; if (retval < 0) goto err_disable; + break; } while (*++irqp); if (*irqp == 0) { diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index 0c9217f..7b3e23f 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -50,7 +50,7 @@ static const char version[] = #ifdef __arm__ static void write_rreg(u_long base, u_int reg, u_int val) { - __asm__( + asm volatile( "str%?h %1, [%2] @ NET_RAP\n\t" "str%?h %0, [%2, #-4] @ NET_RDP" : @@ -60,7 +60,7 @@ static void write_rreg(u_long base, u_int reg, u_int val) static inline unsigned short read_rreg(u_long base_addr, u_int reg) { unsigned short v; - __asm__( + asm volatile( "str%?h %1, [%2] @ NET_RAP\n\t" "ldr%?h %0, [%2, #-4] @ NET_RDP" : "=r" (v) @@ -70,7 +70,7 @@ static inline unsigned short read_rreg(u_long base_addr, u_int reg) static inline void write_ireg(u_long base, u_int reg, u_int val) { - __asm__( + asm volatile( "str%?h %1, [%2] @ NET_RAP\n\t" "str%?h %0, [%2, #8] @ NET_IDP" : @@ -80,7 +80,7 @@ static inline void write_ireg(u_long base, u_int reg, u_int val) static inline unsigned short read_ireg(u_long base_addr, u_int reg) { u_short v; - __asm__( + asm volatile( "str%?h %1, [%2] @ NAT_RAP\n\t" "ldr%?h %0, [%2, #8] @ NET_IDP\n\t" : "=r" (v) @@ -91,47 +91,48 @@ static inline unsigned short read_ireg(u_long base_addr, u_int reg) #define am_writeword(dev,off,val) __raw_writew(val, ISAMEM_BASE + ((off) << 1)) #define am_readword(dev,off) __raw_readw(ISAMEM_BASE + ((off) << 1)) -static inline void +static void am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length) { offset = ISAMEM_BASE + (offset << 1); length = (length + 1) & ~1; if ((int)buf & 2) { - __asm__ __volatile__("str%?h %2, [%0], #4" + asm volatile("str%?h %2, [%0], #4" : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8))); buf += 2; length -= 2; } while (length > 8) { - unsigned int tmp, tmp2; - __asm__ __volatile__( - "ldm%?ia %1!, {%2, %3}\n\t" + register unsigned int tmp asm("r2"), tmp2 asm("r3"); + asm volatile( + "ldm%?ia %0!, {%1, %2}" + : "+r" (buf), "=&r" (tmp), "=&r" (tmp2)); + length -= 8; + asm volatile( + "str%?h %1, [%0], #4\n\t" + "mov%? %1, %1, lsr #16\n\t" + "str%?h %1, [%0], #4\n\t" "str%?h %2, [%0], #4\n\t" "mov%? %2, %2, lsr #16\n\t" - "str%?h %2, [%0], #4\n\t" - "str%?h %3, [%0], #4\n\t" - "mov%? %3, %3, lsr #16\n\t" - "str%?h %3, [%0], #4" - : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2) - : "0" (offset), "1" (buf)); - length -= 8; + "str%?h %2, [%0], #4" + : "+r" (offset), "=&r" (tmp), "=&r" (tmp2)); } while (length > 0) { - __asm__ __volatile__("str%?h %2, [%0], #4" + asm volatile("str%?h %2, [%0], #4" : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8))); buf += 2; length -= 2; } } -static inline void +static void am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length) { offset = ISAMEM_BASE + (offset << 1); length = (length + 1) & ~1; if ((int)buf & 2) { unsigned int tmp; - __asm__ __volatile__( + asm volatile( "ldr%?h %2, [%0], #4\n\t" "str%?b %2, [%1], #1\n\t" "mov%? %2, %2, lsr #8\n\t" @@ -140,12 +141,12 @@ am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned length -= 2; } while (length > 8) { - unsigned int tmp, tmp2, tmp3; - __asm__ __volatile__( + register unsigned int tmp asm("r2"), tmp2 asm("r3"), tmp3; + asm volatile( "ldr%?h %2, [%0], #4\n\t" + "ldr%?h %4, [%0], #4\n\t" "ldr%?h %3, [%0], #4\n\t" - "orr%? %2, %2, %3, lsl #16\n\t" - "ldr%?h %3, [%0], #4\n\t" + "orr%? %2, %2, %4, lsl #16\n\t" "ldr%?h %4, [%0], #4\n\t" "orr%? %3, %3, %4, lsl #16\n\t" "stm%?ia %1!, {%2, %3}" @@ -155,7 +156,7 @@ am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned } while (length > 0) { unsigned int tmp; - __asm__ __volatile__( + asm volatile( "ldr%?h %2, [%0], #4\n\t" "str%?b %2, [%1], #1\n\t" "mov%? %2, %2, lsr #8\n\t" @@ -196,6 +197,42 @@ am79c961_ramtest(struct net_device *dev, unsigned int val) return errorcount; } +static void am79c961_mc_hash(char *addr, u16 *hash) +{ + if (addr[0] & 0x01) { + int idx, bit; + u32 crc; + + crc = ether_crc_le(ETH_ALEN, addr); + + idx = crc >> 30; + bit = (crc >> 26) & 15; + + hash[idx] |= 1 << bit; + } +} + +static unsigned int am79c961_get_rx_mode(struct net_device *dev, u16 *hash) +{ + unsigned int mode = MODE_PORT_10BT; + + if (dev->flags & IFF_PROMISC) { + mode |= MODE_PROMISC; + memset(hash, 0xff, 4 * sizeof(*hash)); + } else if (dev->flags & IFF_ALLMULTI) { + memset(hash, 0xff, 4 * sizeof(*hash)); + } else { + struct netdev_hw_addr *ha; + + memset(hash, 0, 4 * sizeof(*hash)); + + netdev_for_each_mc_addr(ha, dev) + am79c961_mc_hash(ha->addr, hash); + } + + return mode; +} + static void am79c961_init_for_open(struct net_device *dev) { @@ -203,6 +240,7 @@ am79c961_init_for_open(struct net_device *dev) unsigned long flags; unsigned char *p; u_int hdr_addr, first_free_addr; + u16 multi_hash[4], mode = am79c961_get_rx_mode(dev, multi_hash); int i; /* @@ -218,16 +256,12 @@ am79c961_init_for_open(struct net_device *dev) write_ireg (dev->base_addr, 2, 0x0000); /* MODE register selects media */ for (i = LADRL; i <= LADRH; i++) - write_rreg (dev->base_addr, i, 0); + write_rreg (dev->base_addr, i, multi_hash[i - LADRL]); for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2) write_rreg (dev->base_addr, i, p[0] | (p[1] << 8)); - i = MODE_PORT_10BT; - if (dev->flags & IFF_PROMISC) - i |= MODE_PROMISC; - - write_rreg (dev->base_addr, MODE, i); + write_rreg (dev->base_addr, MODE, mode); write_rreg (dev->base_addr, POLLINT, 0); write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS); write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS); @@ -340,21 +374,6 @@ am79c961_close(struct net_device *dev) return 0; } -static void am79c961_mc_hash(char *addr, unsigned short *hash) -{ - if (addr[0] & 0x01) { - int idx, bit; - u32 crc; - - crc = ether_crc_le(ETH_ALEN, addr); - - idx = crc >> 30; - bit = (crc >> 26) & 15; - - hash[idx] |= 1 << bit; - } -} - /* * Set or clear promiscuous/multicast mode filter for this adapter. */ @@ -362,24 +381,9 @@ static void am79c961_setmulticastlist (struct net_device *dev) { struct dev_priv *priv = netdev_priv(dev); unsigned long flags; - unsigned short multi_hash[4], mode; + u16 multi_hash[4], mode = am79c961_get_rx_mode(dev, multi_hash); int i, stopped; - mode = MODE_PORT_10BT; - - if (dev->flags & IFF_PROMISC) { - mode |= MODE_PROMISC; - } else if (dev->flags & IFF_ALLMULTI) { - memset(multi_hash, 0xff, sizeof(multi_hash)); - } else { - struct netdev_hw_addr *ha; - - memset(multi_hash, 0x00, sizeof(multi_hash)); - - netdev_for_each_mc_addr(ha, dev) - am79c961_mc_hash(ha->addr, multi_hash); - } - spin_lock_irqsave(&priv->chip_lock, flags); stopped = read_rreg(dev->base_addr, CSR0) & CSR0_STOP; diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index 5a77001..0b46b8e 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -283,10 +283,14 @@ static int ep93xx_rx(struct net_device *dev, int processed, int budget) skb = dev_alloc_skb(length + 2); if (likely(skb != NULL)) { + struct ep93xx_rdesc *rxd = &ep->descs->rdesc[entry]; skb_reserve(skb, 2); - dma_sync_single_for_cpu(NULL, ep->descs->rdesc[entry].buf_addr, + dma_sync_single_for_cpu(dev->dev.parent, rxd->buf_addr, length, DMA_FROM_DEVICE); skb_copy_to_linear_data(skb, ep->rx_buf[entry], length); + dma_sync_single_for_device(dev->dev.parent, + rxd->buf_addr, length, + DMA_FROM_DEVICE); skb_put(skb, length); skb->protocol = eth_type_trans(skb, dev); @@ -348,6 +352,7 @@ poll_some_more: static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev) { struct ep93xx_priv *ep = netdev_priv(dev); + struct ep93xx_tdesc *txd; int entry; if (unlikely(skb->len > MAX_PKT_SIZE)) { @@ -359,11 +364,14 @@ static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev) entry = ep->tx_pointer; ep->tx_pointer = (ep->tx_pointer + 1) & (TX_QUEUE_ENTRIES - 1); - ep->descs->tdesc[entry].tdesc1 = - TDESC1_EOF | (entry << 16) | (skb->len & 0xfff); + txd = &ep->descs->tdesc[entry]; + + txd->tdesc1 = TDESC1_EOF | (entry << 16) | (skb->len & 0xfff); + dma_sync_single_for_cpu(dev->dev.parent, txd->buf_addr, skb->len, + DMA_TO_DEVICE); skb_copy_and_csum_dev(skb, ep->tx_buf[entry]); - dma_sync_single_for_cpu(NULL, ep->descs->tdesc[entry].buf_addr, - skb->len, DMA_TO_DEVICE); + dma_sync_single_for_device(dev->dev.parent, txd->buf_addr, skb->len, + DMA_TO_DEVICE); dev_kfree_skb(skb); spin_lock_irq(&ep->tx_pending_lock); @@ -457,89 +465,80 @@ static irqreturn_t ep93xx_irq(int irq, void *dev_id) static void ep93xx_free_buffers(struct ep93xx_priv *ep) { + struct device *dev = ep->dev->dev.parent; int i; - for (i = 0; i < RX_QUEUE_ENTRIES; i += 2) { + for (i = 0; i < RX_QUEUE_ENTRIES; i++) { dma_addr_t d; d = ep->descs->rdesc[i].buf_addr; if (d) - dma_unmap_single(NULL, d, PAGE_SIZE, DMA_FROM_DEVICE); + dma_unmap_single(dev, d, PKT_BUF_SIZE, DMA_FROM_DEVICE); if (ep->rx_buf[i] != NULL) - free_page((unsigned long)ep->rx_buf[i]); + kfree(ep->rx_buf[i]); } - for (i = 0; i < TX_QUEUE_ENTRIES; i += 2) { + for (i = 0; i < TX_QUEUE_ENTRIES; i++) { dma_addr_t d; d = ep->descs->tdesc[i].buf_addr; if (d) - dma_unmap_single(NULL, d, PAGE_SIZE, DMA_TO_DEVICE); + dma_unmap_single(dev, d, PKT_BUF_SIZE, DMA_TO_DEVICE); if (ep->tx_buf[i] != NULL) - free_page((unsigned long)ep->tx_buf[i]); + kfree(ep->tx_buf[i]); } - dma_free_coherent(NULL, sizeof(struct ep93xx_descs), ep->descs, + dma_free_coherent(dev, sizeof(struct ep93xx_descs), ep->descs, ep->descs_dma_addr); } -/* - * The hardware enforces a sub-2K maximum packet size, so we put - * two buffers on every hardware page. - */ static int ep93xx_alloc_buffers(struct ep93xx_priv *ep) { + struct device *dev = ep->dev->dev.parent; int i; - ep->descs = dma_alloc_coherent(NULL, sizeof(struct ep93xx_descs), - &ep->descs_dma_addr, GFP_KERNEL | GFP_DMA); + ep->descs = dma_alloc_coherent(dev, sizeof(struct ep93xx_descs), + &ep->descs_dma_addr, GFP_KERNEL); if (ep->descs == NULL) return 1; - for (i = 0; i < RX_QUEUE_ENTRIES; i += 2) { - void *page; + for (i = 0; i < RX_QUEUE_ENTRIES; i++) { + void *buf; dma_addr_t d; - page = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); - if (page == NULL) + buf = kmalloc(PKT_BUF_SIZE, GFP_KERNEL); + if (buf == NULL) goto err; - d = dma_map_single(NULL, page, PAGE_SIZE, DMA_FROM_DEVICE); - if (dma_mapping_error(NULL, d)) { - free_page((unsigned long)page); + d = dma_map_single(dev, buf, PKT_BUF_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(dev, d)) { + kfree(buf); goto err; } - ep->rx_buf[i] = page; + ep->rx_buf[i] = buf; ep->descs->rdesc[i].buf_addr = d; ep->descs->rdesc[i].rdesc1 = (i << 16) | PKT_BUF_SIZE; - - ep->rx_buf[i + 1] = page + PKT_BUF_SIZE; - ep->descs->rdesc[i + 1].buf_addr = d + PKT_BUF_SIZE; - ep->descs->rdesc[i + 1].rdesc1 = ((i + 1) << 16) | PKT_BUF_SIZE; } - for (i = 0; i < TX_QUEUE_ENTRIES; i += 2) { - void *page; + for (i = 0; i < TX_QUEUE_ENTRIES; i++) { + void *buf; dma_addr_t d; - page = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); - if (page == NULL) + buf = kmalloc(PKT_BUF_SIZE, GFP_KERNEL); + if (buf == NULL) goto err; - d = dma_map_single(NULL, page, PAGE_SIZE, DMA_TO_DEVICE); - if (dma_mapping_error(NULL, d)) { - free_page((unsigned long)page); + d = dma_map_single(dev, buf, PKT_BUF_SIZE, DMA_TO_DEVICE); + if (dma_mapping_error(dev, d)) { + kfree(buf); goto err; } - ep->tx_buf[i] = page; + ep->tx_buf[i] = buf; ep->descs->tdesc[i].buf_addr = d; - - ep->tx_buf[i + 1] = page + PKT_BUF_SIZE; - ep->descs->tdesc[i + 1].buf_addr = d + PKT_BUF_SIZE; } return 0; @@ -829,6 +828,7 @@ static int ep93xx_eth_probe(struct platform_device *pdev) } ep = netdev_priv(dev); ep->dev = dev; + SET_NETDEV_DEV(dev, &pdev->dev); netif_napi_add(dev, &ep->napi, ep93xx_poll, 64); platform_set_drvdata(pdev, dev); diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 68d45ba..6c019e1 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -52,13 +52,13 @@ MODULE_DESCRIPTION(DRV_DESC); MODULE_ALIAS("platform:bfin_mac"); #if defined(CONFIG_BFIN_MAC_USE_L1) -# define bfin_mac_alloc(dma_handle, size) l1_data_sram_zalloc(size) -# define bfin_mac_free(dma_handle, ptr) l1_data_sram_free(ptr) +# define bfin_mac_alloc(dma_handle, size, num) l1_data_sram_zalloc(size*num) +# define bfin_mac_free(dma_handle, ptr, num) l1_data_sram_free(ptr) #else -# define bfin_mac_alloc(dma_handle, size) \ - dma_alloc_coherent(NULL, size, dma_handle, GFP_KERNEL) -# define bfin_mac_free(dma_handle, ptr) \ - dma_free_coherent(NULL, sizeof(*ptr), ptr, dma_handle) +# define bfin_mac_alloc(dma_handle, size, num) \ + dma_alloc_coherent(NULL, size*num, dma_handle, GFP_KERNEL) +# define bfin_mac_free(dma_handle, ptr, num) \ + dma_free_coherent(NULL, sizeof(*ptr)*num, ptr, dma_handle) #endif #define PKT_BUF_SZ 1580 @@ -95,7 +95,7 @@ static void desc_list_free(void) t = t->next; } } - bfin_mac_free(dma_handle, tx_desc); + bfin_mac_free(dma_handle, tx_desc, CONFIG_BFIN_TX_DESC_NUM); } if (rx_desc) { @@ -109,7 +109,7 @@ static void desc_list_free(void) r = r->next; } } - bfin_mac_free(dma_handle, rx_desc); + bfin_mac_free(dma_handle, rx_desc, CONFIG_BFIN_RX_DESC_NUM); } } @@ -126,13 +126,13 @@ static int desc_list_init(void) #endif tx_desc = bfin_mac_alloc(&dma_handle, - sizeof(struct net_dma_desc_tx) * + sizeof(struct net_dma_desc_tx), CONFIG_BFIN_TX_DESC_NUM); if (tx_desc == NULL) goto init_error; rx_desc = bfin_mac_alloc(&dma_handle, - sizeof(struct net_dma_desc_rx) * + sizeof(struct net_dma_desc_rx), CONFIG_BFIN_RX_DESC_NUM); if (rx_desc == NULL) goto init_error; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 17b4dd9..eafe44a 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -388,6 +388,8 @@ struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr) return next; } +#define bond_queue_mapping(skb) (*(u16 *)((skb)->cb)) + /** * bond_dev_queue_xmit - Prepare skb for xmit. * @@ -400,6 +402,9 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, { skb->dev = slave_dev; skb->priority = 1; + + skb->queue_mapping = bond_queue_mapping(skb); + if (unlikely(netpoll_tx_running(slave_dev))) bond_netpoll_send_skb(bond_get_slave_by_dev(bond, slave_dev), skb); else @@ -1292,6 +1297,7 @@ static inline int slave_enable_netpoll(struct slave *slave) goto out; np->dev = slave->dev; + strlcpy(np->dev_name, slave->dev->name, IFNAMSIZ); err = __netpoll_setup(np); if (err) { kfree(np); @@ -4206,6 +4212,7 @@ static inline int bond_slave_override(struct bonding *bond, return res; } + static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb) { /* @@ -4216,6 +4223,11 @@ static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb) */ u16 txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0; + /* + * Save the original txq to restore before passing to the driver + */ + bond_queue_mapping(skb) = skb->queue_mapping; + if (unlikely(txq >= dev->real_num_tx_queues)) { do { txq -= dev->real_num_tx_queues; diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index c445457..23179db 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -346,7 +346,7 @@ parse_eeprom (struct net_device *dev) if (np->pdev->vendor == PCI_VENDOR_ID_DLINK) { /* D-Link Only */ /* Check CRC */ crc = ~ether_crc_le (256 - 4, sromdata); - if (psrom->crc != crc) { + if (psrom->crc != cpu_to_le32(crc)) { printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name); return -1; diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index 7a84e45..7583a95 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c @@ -105,7 +105,7 @@ static int do_pd_setup(struct fs_enet_private *fep) goto out_ep; fep->fcc.mem = (void __iomem *)cpm2_immr; - fpi->dpram_offset = cpm_dpalloc(128, 8); + fpi->dpram_offset = cpm_dpalloc(128, 32); if (IS_ERR_VALUE(fpi->dpram_offset)) { ret = fpi->dpram_offset; goto out_fcccp; diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index ff60b23..2dfcc80 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -10,7 +10,7 @@ * Maintainer: Kumar Gala * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com> * - * Copyright 2002-2009 Freescale Semiconductor, Inc. + * Copyright 2002-2009, 2011 Freescale Semiconductor, Inc. * Copyright 2007 MontaVista Software, Inc. * * This program is free software; you can redistribute it and/or modify it @@ -476,9 +476,6 @@ static const struct net_device_ops gfar_netdev_ops = { #endif }; -unsigned int ftp_rqfpr[MAX_FILER_IDX + 1]; -unsigned int ftp_rqfcr[MAX_FILER_IDX + 1]; - void lock_rx_qs(struct gfar_private *priv) { int i = 0x0; @@ -868,28 +865,28 @@ static u32 cluster_entry_per_class(struct gfar_private *priv, u32 rqfar, rqfar--; rqfcr = RQFCR_CLE | RQFCR_PID_MASK | RQFCR_CMP_EXACT; - ftp_rqfpr[rqfar] = rqfpr; - ftp_rqfcr[rqfar] = rqfcr; + priv->ftp_rqfpr[rqfar] = rqfpr; + priv->ftp_rqfcr[rqfar] = rqfcr; gfar_write_filer(priv, rqfar, rqfcr, rqfpr); rqfar--; rqfcr = RQFCR_CMP_NOMATCH; - ftp_rqfpr[rqfar] = rqfpr; - ftp_rqfcr[rqfar] = rqfcr; + priv->ftp_rqfpr[rqfar] = rqfpr; + priv->ftp_rqfcr[rqfar] = rqfcr; gfar_write_filer(priv, rqfar, rqfcr, rqfpr); rqfar--; rqfcr = RQFCR_CMP_EXACT | RQFCR_PID_PARSE | RQFCR_CLE | RQFCR_AND; rqfpr = class; - ftp_rqfcr[rqfar] = rqfcr; - ftp_rqfpr[rqfar] = rqfpr; + priv->ftp_rqfcr[rqfar] = rqfcr; + priv->ftp_rqfpr[rqfar] = rqfpr; gfar_write_filer(priv, rqfar, rqfcr, rqfpr); rqfar--; rqfcr = RQFCR_CMP_EXACT | RQFCR_PID_MASK | RQFCR_AND; rqfpr = class; - ftp_rqfcr[rqfar] = rqfcr; - ftp_rqfpr[rqfar] = rqfpr; + priv->ftp_rqfcr[rqfar] = rqfcr; + priv->ftp_rqfpr[rqfar] = rqfpr; gfar_write_filer(priv, rqfar, rqfcr, rqfpr); return rqfar; @@ -904,8 +901,8 @@ static void gfar_init_filer_table(struct gfar_private *priv) /* Default rule */ rqfcr = RQFCR_CMP_MATCH; - ftp_rqfcr[rqfar] = rqfcr; - ftp_rqfpr[rqfar] = rqfpr; + priv->ftp_rqfcr[rqfar] = rqfcr; + priv->ftp_rqfpr[rqfar] = rqfpr; gfar_write_filer(priv, rqfar, rqfcr, rqfpr); rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV6); @@ -921,8 +918,8 @@ static void gfar_init_filer_table(struct gfar_private *priv) /* Rest are masked rules */ rqfcr = RQFCR_CMP_NOMATCH; for (i = 0; i < rqfar; i++) { - ftp_rqfcr[i] = rqfcr; - ftp_rqfpr[i] = rqfpr; + priv->ftp_rqfcr[i] = rqfcr; + priv->ftp_rqfpr[i] = rqfpr; gfar_write_filer(priv, i, rqfcr, rqfpr); } } diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index fc86f51..ba36dc7 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -9,7 +9,7 @@ * Maintainer: Kumar Gala * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com> * - * Copyright 2002-2009 Freescale Semiconductor, Inc. + * Copyright 2002-2009, 2011 Freescale Semiconductor, Inc. * * 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 @@ -1107,10 +1107,12 @@ struct gfar_private { /* HW time stamping enabled flag */ int hwts_rx_en; int hwts_tx_en; + + /*Filer table*/ + unsigned int ftp_rqfpr[MAX_FILER_IDX + 1]; + unsigned int ftp_rqfcr[MAX_FILER_IDX + 1]; }; -extern unsigned int ftp_rqfpr[MAX_FILER_IDX + 1]; -extern unsigned int ftp_rqfcr[MAX_FILER_IDX + 1]; static inline int gfar_has_errata(struct gfar_private *priv, enum gfar_errata err) diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 493d743..239e333 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -9,7 +9,7 @@ * Maintainer: Kumar Gala * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com> * - * Copyright 2003-2006, 2008-2009 Freescale Semiconductor, Inc. + * Copyright 2003-2006, 2008-2009, 2011 Freescale Semiconductor, Inc. * * This software may be used and distributed according to * the terms of the GNU Public License, Version 2, incorporated herein @@ -609,15 +609,15 @@ static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow) if (ethflow & RXH_L2DA) { fcr = RQFCR_PID_DAH |RQFCR_CMP_NOMATCH | RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0; - ftp_rqfpr[priv->cur_filer_idx] = fpr; - ftp_rqfcr[priv->cur_filer_idx] = fcr; + priv->ftp_rqfpr[priv->cur_filer_idx] = fpr; + priv->ftp_rqfcr[priv->cur_filer_idx] = fcr; gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); priv->cur_filer_idx = priv->cur_filer_idx - 1; fcr = RQFCR_PID_DAL | RQFCR_AND | RQFCR_CMP_NOMATCH | RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0; - ftp_rqfpr[priv->cur_filer_idx] = fpr; - ftp_rqfcr[priv->cur_filer_idx] = fcr; + priv->ftp_rqfpr[priv->cur_filer_idx] = fpr; + priv->ftp_rqfcr[priv->cur_filer_idx] = fcr; gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); priv->cur_filer_idx = priv->cur_filer_idx - 1; } @@ -626,16 +626,16 @@ static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow) fcr = RQFCR_PID_VID | RQFCR_CMP_NOMATCH | RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0; gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); - ftp_rqfpr[priv->cur_filer_idx] = fpr; - ftp_rqfcr[priv->cur_filer_idx] = fcr; + priv->ftp_rqfpr[priv->cur_filer_idx] = fpr; + priv->ftp_rqfcr[priv->cur_filer_idx] = fcr; priv->cur_filer_idx = priv->cur_filer_idx - 1; } if (ethflow & RXH_IP_SRC) { fcr = RQFCR_PID_SIA | RQFCR_CMP_NOMATCH | RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0; - ftp_rqfpr[priv->cur_filer_idx] = fpr; - ftp_rqfcr[priv->cur_filer_idx] = fcr; + priv->ftp_rqfpr[priv->cur_filer_idx] = fpr; + priv->ftp_rqfcr[priv->cur_filer_idx] = fcr; gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); priv->cur_filer_idx = priv->cur_filer_idx - 1; } @@ -643,8 +643,8 @@ static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow) if (ethflow & (RXH_IP_DST)) { fcr = RQFCR_PID_DIA | RQFCR_CMP_NOMATCH | RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0; - ftp_rqfpr[priv->cur_filer_idx] = fpr; - ftp_rqfcr[priv->cur_filer_idx] = fcr; + priv->ftp_rqfpr[priv->cur_filer_idx] = fpr; + priv->ftp_rqfcr[priv->cur_filer_idx] = fcr; gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); priv->cur_filer_idx = priv->cur_filer_idx - 1; } @@ -652,8 +652,8 @@ static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow) if (ethflow & RXH_L3_PROTO) { fcr = RQFCR_PID_L4P | RQFCR_CMP_NOMATCH | RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0; - ftp_rqfpr[priv->cur_filer_idx] = fpr; - ftp_rqfcr[priv->cur_filer_idx] = fcr; + priv->ftp_rqfpr[priv->cur_filer_idx] = fpr; + priv->ftp_rqfcr[priv->cur_filer_idx] = fcr; gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); priv->cur_filer_idx = priv->cur_filer_idx - 1; } @@ -661,8 +661,8 @@ static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow) if (ethflow & RXH_L4_B_0_1) { fcr = RQFCR_PID_SPT | RQFCR_CMP_NOMATCH | RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0; - ftp_rqfpr[priv->cur_filer_idx] = fpr; - ftp_rqfcr[priv->cur_filer_idx] = fcr; + priv->ftp_rqfpr[priv->cur_filer_idx] = fpr; + priv->ftp_rqfcr[priv->cur_filer_idx] = fcr; gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); priv->cur_filer_idx = priv->cur_filer_idx - 1; } @@ -670,8 +670,8 @@ static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow) if (ethflow & RXH_L4_B_2_3) { fcr = RQFCR_PID_DPT | RQFCR_CMP_NOMATCH | RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0; - ftp_rqfpr[priv->cur_filer_idx] = fpr; - ftp_rqfcr[priv->cur_filer_idx] = fcr; + priv->ftp_rqfpr[priv->cur_filer_idx] = fpr; + priv->ftp_rqfcr[priv->cur_filer_idx] = fcr; gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); priv->cur_filer_idx = priv->cur_filer_idx - 1; } @@ -705,12 +705,12 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u } for (i = 0; i < MAX_FILER_IDX + 1; i++) { - local_rqfpr[j] = ftp_rqfpr[i]; - local_rqfcr[j] = ftp_rqfcr[i]; + local_rqfpr[j] = priv->ftp_rqfpr[i]; + local_rqfcr[j] = priv->ftp_rqfcr[i]; j--; - if ((ftp_rqfcr[i] == (RQFCR_PID_PARSE | + if ((priv->ftp_rqfcr[i] == (RQFCR_PID_PARSE | RQFCR_CLE |RQFCR_AND)) && - (ftp_rqfpr[i] == cmp_rqfpr)) + (priv->ftp_rqfpr[i] == cmp_rqfpr)) break; } @@ -724,20 +724,22 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u * if it was already programmed, we need to overwrite these rules */ for (l = i+1; l < MAX_FILER_IDX; l++) { - if ((ftp_rqfcr[l] & RQFCR_CLE) && - !(ftp_rqfcr[l] & RQFCR_AND)) { - ftp_rqfcr[l] = RQFCR_CLE | RQFCR_CMP_EXACT | + if ((priv->ftp_rqfcr[l] & RQFCR_CLE) && + !(priv->ftp_rqfcr[l] & RQFCR_AND)) { + priv->ftp_rqfcr[l] = RQFCR_CLE | RQFCR_CMP_EXACT | RQFCR_HASHTBL_0 | RQFCR_PID_MASK; - ftp_rqfpr[l] = FPR_FILER_MASK; - gfar_write_filer(priv, l, ftp_rqfcr[l], ftp_rqfpr[l]); + priv->ftp_rqfpr[l] = FPR_FILER_MASK; + gfar_write_filer(priv, l, priv->ftp_rqfcr[l], + priv->ftp_rqfpr[l]); break; } - if (!(ftp_rqfcr[l] & RQFCR_CLE) && (ftp_rqfcr[l] & RQFCR_AND)) + if (!(priv->ftp_rqfcr[l] & RQFCR_CLE) && + (priv->ftp_rqfcr[l] & RQFCR_AND)) continue; else { - local_rqfpr[j] = ftp_rqfpr[l]; - local_rqfcr[j] = ftp_rqfcr[l]; + local_rqfpr[j] = priv->ftp_rqfpr[l]; + local_rqfcr[j] = priv->ftp_rqfcr[l]; j--; } } @@ -750,8 +752,8 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u /* Write back the popped out rules again */ for (k = j+1; k < MAX_FILER_IDX; k++) { - ftp_rqfpr[priv->cur_filer_idx] = local_rqfpr[k]; - ftp_rqfcr[priv->cur_filer_idx] = local_rqfcr[k]; + priv->ftp_rqfpr[priv->cur_filer_idx] = local_rqfpr[k]; + priv->ftp_rqfcr[priv->cur_filer_idx] = local_rqfcr[k]; gfar_write_filer(priv, priv->cur_filer_idx, local_rqfcr[k], local_rqfpr[k]); if (!priv->cur_filer_idx) diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 8e10d2f..c3ecb11 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -1580,12 +1580,12 @@ static netdev_tx_t hp100_start_xmit_bm(struct sk_buff *skb, hp100_outl(ringptr->pdl_paddr, TX_PDA_L); /* Low Prio. Queue */ lp->txrcommit++; - spin_unlock_irqrestore(&lp->lock, flags); - /* Update statistics */ dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; + spin_unlock_irqrestore(&lp->lock, flags); + return NETDEV_TX_OK; drop: diff --git a/drivers/net/hplance.c b/drivers/net/hplance.c index b6060f7..a900d5b 100644 --- a/drivers/net/hplance.c +++ b/drivers/net/hplance.c @@ -135,7 +135,7 @@ static void __devexit hplance_remove_one(struct dio_dev *d) } /* Initialise a single lance board at the given DIO device */ -static void __init hplance_init(struct net_device *dev, struct dio_dev *d) +static void __devinit hplance_init(struct net_device *dev, struct dio_dev *d) { unsigned long va = (d->resource.start + DIO_VIRADDRBASE); struct hplance_private *lp; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 18fccf9..2c28621 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -2373,6 +2373,9 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter) } #endif /* CONFIG_PCI_IOV */ adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES, num_online_cpus()); + /* i350 cannot do RSS and SR-IOV at the same time */ + if (hw->mac.type == e1000_i350 && adapter->vfs_allocated_count) + adapter->rss_queues = 1; /* * if rss_queues > 4 or vfs are going to be allocated with rss_queues diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index b644383..c0788a3 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1965,11 +1965,11 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) netxen_tso_check(netdev, tx_ring, first_desc, skb); - netxen_nic_update_cmd_producer(adapter, tx_ring); - adapter->stats.txbytes += skb->len; adapter->stats.xmitcalled++; + netxen_nic_update_cmd_producer(adapter, tx_ring); + return NETDEV_TX_OK; drop_packet: diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 392a6c4..a702443 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -58,6 +58,7 @@ config BROADCOM_PHY config BCM63XX_PHY tristate "Drivers for Broadcom 63xx SOCs internal PHY" + depends on BCM63XX ---help--- Currently supports the 6348 and 6358 PHYs. diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index b0c9522..2cd8dc5 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -543,11 +543,20 @@ static void recalibrate(struct dp83640_clock *clock) /* time stamping methods */ -static void decode_evnt(struct dp83640_private *dp83640, - struct phy_txts *phy_txts, u16 ests) +static int decode_evnt(struct dp83640_private *dp83640, + void *data, u16 ests) { + struct phy_txts *phy_txts; struct ptp_clock_event event; int words = (ests >> EVNT_TS_LEN_SHIFT) & EVNT_TS_LEN_MASK; + u16 ext_status = 0; + + if (ests & MULT_EVNT) { + ext_status = *(u16 *) data; + data += sizeof(ext_status); + } + + phy_txts = data; switch (words) { /* fall through in every case */ case 3: @@ -565,6 +574,9 @@ static void decode_evnt(struct dp83640_private *dp83640, event.timestamp = phy2txts(&dp83640->edata); ptp_clock_event(dp83640->clock->ptp_clock, &event); + + words = ext_status ? words + 2 : words + 1; + return words * sizeof(u16); } static void decode_rxts(struct dp83640_private *dp83640, @@ -643,9 +655,7 @@ static void decode_status_frame(struct dp83640_private *dp83640, } else if (PSF_EVNT == type && len >= sizeof(*phy_txts)) { - phy_txts = (struct phy_txts *) ptr; - decode_evnt(dp83640, phy_txts, ests); - size = sizeof(*phy_txts); + size = decode_evnt(dp83640, ptr, ests); } else { size = 0; @@ -1034,8 +1044,8 @@ static bool dp83640_rxtstamp(struct phy_device *phydev, if (is_status_frame(skb, type)) { decode_status_frame(dp83640, skb); - /* Let the stack drop this frame. */ - return false; + kfree_skb(skb); + return true; } SKB_PTP_TYPE(skb) = type; diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index a1b82c9..c554a39 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -523,7 +523,7 @@ static void ppp_async_process(unsigned long arg) #define PUT_BYTE(ap, buf, c, islcp) do { \ if ((islcp && c < 0x20) || (ap->xaccm[c >> 5] & (1 << (c & 0x1f)))) {\ *buf++ = PPP_ESCAPE; \ - *buf++ = c ^ 0x20; \ + *buf++ = c ^ PPP_TRANS; \ } else \ *buf++ = c; \ } while (0) @@ -896,7 +896,7 @@ ppp_async_input(struct asyncppp *ap, const unsigned char *buf, sp = skb_put(skb, n); memcpy(sp, buf, n); if (ap->state & SC_ESCAPE) { - sp[0] ^= 0x20; + sp[0] ^= PPP_TRANS; ap->state &= ~SC_ESCAPE; } } diff --git a/drivers/net/pxa168_eth.c b/drivers/net/pxa168_eth.c index 89f7540..5f597ca5 100644 --- a/drivers/net/pxa168_eth.c +++ b/drivers/net/pxa168_eth.c @@ -1273,7 +1273,7 @@ static int pxa168_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) wmb(); wrl(pep, SDMA_CMD, SDMA_CMD_TXDH | SDMA_CMD_ERD); - stats->tx_bytes += skb->len; + stats->tx_bytes += length; stats->tx_packets++; dev->trans_start = jiffies; if (pep->tx_ring_size - pep->tx_desc_count <= 1) { diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index e965661..a5d9fbf 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -1406,6 +1406,7 @@ qlcnic_dump_que(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry, for (loop = 0; loop < que->no_ops; loop++) { QLCNIC_WR_DUMP_REG(que->sel_addr, base, que_id); + addr = que->read_addr; for (i = 0; i < cnt; i++) { QLCNIC_RD_DUMP_REG(addr, base, &data); *buffer++ = cpu_to_le32(data); diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 3ab7d2c..0f6af5c 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -2159,6 +2159,7 @@ qlcnic_unmap_buffers(struct pci_dev *pdev, struct sk_buff *skb, nf = &pbuf->frag_array[0]; pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE); + pbuf->skb = NULL; } static inline void diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index ef1ce2e..05d8178 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1621,7 +1621,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, * * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec */ - static const struct { + static const struct rtl_mac_info { u32 mask; u32 val; int mac_version; @@ -1689,7 +1689,8 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, /* Catch-all */ { 0x00000000, 0x00000000, RTL_GIGA_MAC_NONE } - }, *p = mac_info; + }; + const struct rtl_mac_info *p = mac_info; u32 reg; reg = RTL_R32(TxConfig); @@ -3681,7 +3682,7 @@ static void rtl_set_rx_max_size(void __iomem *ioaddr, unsigned int rx_buf_sz) static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version) { - static const struct { + static const struct rtl_cfg2_info { u32 mac_version; u32 clk; u32 val; @@ -3690,7 +3691,8 @@ static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version) { RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff }, { RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe { RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff } - }, *p = cfg2_info; + }; + const struct rtl_cfg2_info *p = cfg2_info; unsigned int i; u32 clk; diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index dc4805f..f628574 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -2400,8 +2400,10 @@ static const struct of_device_id smc91x_match[] = { { .compatible = "smsc,lan91c94", }, { .compatible = "smsc,lan91c111", }, {}, -} +}; MODULE_DEVICE_TABLE(of, smc91x_match); +#else +#define smc91x_match NULL #endif static struct dev_pm_ops smc_drv_pm_ops = { @@ -2416,9 +2418,7 @@ static struct platform_driver smc_driver = { .name = CARDNAME, .owner = THIS_MODULE, .pm = &smc_drv_pm_ops, -#ifdef CONFIG_OF .of_match_table = smc91x_match, -#endif }, }; diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 74e9405..5235f48 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -460,7 +460,23 @@ static u32 tun_net_fix_features(struct net_device *dev, u32 features) return (features & tun->set_features) | (features & ~TUN_USER_FEATURES); } - +#ifdef CONFIG_NET_POLL_CONTROLLER +static void tun_poll_controller(struct net_device *dev) +{ + /* + * Tun only receives frames when: + * 1) the char device endpoint gets data from user space + * 2) the tun socket gets a sendmsg call from user space + * Since both of those are syncronous operations, we are guaranteed + * never to have pending data when we poll for it + * so theres nothing to do here but return. + * We need this though so netpoll recognizes us as an interface that + * supports polling, which enables bridge devices in virt setups to + * still use netconsole + */ + return; +} +#endif static const struct net_device_ops tun_netdev_ops = { .ndo_uninit = tun_net_uninit, .ndo_open = tun_net_open, @@ -468,6 +484,9 @@ static const struct net_device_ops tun_netdev_ops = { .ndo_start_xmit = tun_net_xmit, .ndo_change_mtu = tun_net_change_mtu, .ndo_fix_features = tun_net_fix_features, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = tun_poll_controller, +#endif }; static const struct net_device_ops tap_netdev_ops = { @@ -480,6 +499,9 @@ static const struct net_device_ops tap_netdev_ops = { .ndo_set_multicast_list = tun_net_mclist, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = tun_poll_controller, +#endif }; /* Initialize net device. */ diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 9d4f911..84d4608 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -385,6 +385,16 @@ config USB_NET_CX82310_ETH router with USB ethernet port. This driver is for routers only, it will not work with ADSL modems (use cxacru driver instead). +config USB_NET_KALMIA + tristate "Samsung Kalmia based LTE USB modem" + depends on USB_USBNET + help + Choose this option if you have a Samsung Kalmia based USB modem + as Samsung GT-B3730. + + To compile this driver as a module, choose M here: the + module will be called kalmia. + config USB_HSO tristate "Option USB High Speed Mobile Devices" depends on USB && RFKILL diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile index c7ec8a5..c203fa2 100644 --- a/drivers/net/usb/Makefile +++ b/drivers/net/usb/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_USB_NET_MCS7830) += mcs7830.o obj-$(CONFIG_USB_USBNET) += usbnet.o obj-$(CONFIG_USB_NET_INT51X1) += int51x1.o obj-$(CONFIG_USB_CDC_PHONET) += cdc-phonet.o +obj-$(CONFIG_USB_NET_KALMIA) += kalmia.o obj-$(CONFIG_USB_IPHETH) += ipheth.o obj-$(CONFIG_USB_SIERRA_NET) += sierra_net.o obj-$(CONFIG_USB_NET_CX82310_ETH) += cx82310_eth.o diff --git a/drivers/net/usb/kalmia.c b/drivers/net/usb/kalmia.c new file mode 100644 index 0000000..d965fb1 --- /dev/null +++ b/drivers/net/usb/kalmia.c @@ -0,0 +1,384 @@ +/* + * USB network interface driver for Samsung Kalmia based LTE USB modem like the + * Samsung GT-B3730 and GT-B3710. + * + * Copyright (C) 2011 Marius Bjoernstad Kotsbak <marius@kotsbak.com> + * + * Sponsored by Quicklink Video Distribution Services Ltd. + * + * Based on the cdc_eem module. + * + * 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/module.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ctype.h> +#include <linux/ethtool.h> +#include <linux/workqueue.h> +#include <linux/mii.h> +#include <linux/usb.h> +#include <linux/crc32.h> +#include <linux/usb/cdc.h> +#include <linux/usb/usbnet.h> +#include <linux/gfp.h> + +/* + * The Samsung Kalmia based LTE USB modems have a CDC ACM port for modem control + * handled by the "option" module and an ethernet data port handled by this + * module. + * + * The stick must first be switched into modem mode by usb_modeswitch + * or similar tool. Then the modem gets sent two initialization packets by + * this module, which gives the MAC address of the device. User space can then + * connect the modem using AT commands through the ACM port and then use + * DHCP on the network interface exposed by this module. Network packets are + * sent to and from the modem in a proprietary format discovered after watching + * the behavior of the windows driver for the modem. + * + * More information about the use of the modem is available in usb_modeswitch + * forum and the project page: + * + * http://www.draisberghof.de/usb_modeswitch/bb/viewtopic.php?t=465 + * https://github.com/mkotsbak/Samsung-GT-B3730-linux-driver + */ + +/* #define DEBUG */ +/* #define VERBOSE */ + +#define KALMIA_HEADER_LENGTH 6 +#define KALMIA_ALIGN_SIZE 4 +#define KALMIA_USB_TIMEOUT 10000 + +/*-------------------------------------------------------------------------*/ + +static int +kalmia_send_init_packet(struct usbnet *dev, u8 *init_msg, u8 init_msg_len, + u8 *buffer, u8 expected_len) +{ + int act_len; + int status; + + netdev_dbg(dev->net, "Sending init packet"); + + status = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 0x02), + init_msg, init_msg_len, &act_len, KALMIA_USB_TIMEOUT); + if (status != 0) { + netdev_err(dev->net, + "Error sending init packet. Status %i, length %i\n", + status, act_len); + return status; + } + else if (act_len != init_msg_len) { + netdev_err(dev->net, + "Did not send all of init packet. Bytes sent: %i", + act_len); + } + else { + netdev_dbg(dev->net, "Successfully sent init packet."); + } + + status = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, 0x81), + buffer, expected_len, &act_len, KALMIA_USB_TIMEOUT); + + if (status != 0) + netdev_err(dev->net, + "Error receiving init result. Status %i, length %i\n", + status, act_len); + else if (act_len != expected_len) + netdev_err(dev->net, "Unexpected init result length: %i\n", + act_len); + + return status; +} + +static int +kalmia_init_and_get_ethernet_addr(struct usbnet *dev, u8 *ethernet_addr) +{ + char init_msg_1[] = + { 0x57, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00 }; + char init_msg_2[] = + { 0x57, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xf4, + 0x00, 0x00 }; + char receive_buf[28]; + int status; + + status = kalmia_send_init_packet(dev, init_msg_1, sizeof(init_msg_1) + / sizeof(init_msg_1[0]), receive_buf, 24); + if (status != 0) + return status; + + status = kalmia_send_init_packet(dev, init_msg_2, sizeof(init_msg_2) + / sizeof(init_msg_2[0]), receive_buf, 28); + if (status != 0) + return status; + + memcpy(ethernet_addr, receive_buf + 10, ETH_ALEN); + + return status; +} + +static int +kalmia_bind(struct usbnet *dev, struct usb_interface *intf) +{ + u8 status; + u8 ethernet_addr[ETH_ALEN]; + + /* Don't bind to AT command interface */ + if (intf->cur_altsetting->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC) + return -EINVAL; + + dev->in = usb_rcvbulkpipe(dev->udev, 0x81 & USB_ENDPOINT_NUMBER_MASK); + dev->out = usb_sndbulkpipe(dev->udev, 0x02 & USB_ENDPOINT_NUMBER_MASK); + dev->status = NULL; + + dev->net->hard_header_len += KALMIA_HEADER_LENGTH; + dev->hard_mtu = 1400; + dev->rx_urb_size = dev->hard_mtu * 10; // Found as optimal after testing + + status = kalmia_init_and_get_ethernet_addr(dev, ethernet_addr); + + if (status < 0) { + usb_set_intfdata(intf, NULL); + usb_driver_release_interface(driver_of(intf), intf); + return status; + } + + memcpy(dev->net->dev_addr, ethernet_addr, ETH_ALEN); + memcpy(dev->net->perm_addr, ethernet_addr, ETH_ALEN); + + return status; +} + +static struct sk_buff * +kalmia_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) +{ + struct sk_buff *skb2 = NULL; + u16 content_len; + unsigned char *header_start; + unsigned char ether_type_1, ether_type_2; + u8 remainder, padlen = 0; + + if (!skb_cloned(skb)) { + int headroom = skb_headroom(skb); + int tailroom = skb_tailroom(skb); + + if ((tailroom >= KALMIA_ALIGN_SIZE) && (headroom + >= KALMIA_HEADER_LENGTH)) + goto done; + + if ((headroom + tailroom) > (KALMIA_HEADER_LENGTH + + KALMIA_ALIGN_SIZE)) { + skb->data = memmove(skb->head + KALMIA_HEADER_LENGTH, + skb->data, skb->len); + skb_set_tail_pointer(skb, skb->len); + goto done; + } + } + + skb2 = skb_copy_expand(skb, KALMIA_HEADER_LENGTH, + KALMIA_ALIGN_SIZE, flags); + if (!skb2) + return NULL; + + dev_kfree_skb_any(skb); + skb = skb2; + + done: header_start = skb_push(skb, KALMIA_HEADER_LENGTH); + ether_type_1 = header_start[KALMIA_HEADER_LENGTH + 12]; + ether_type_2 = header_start[KALMIA_HEADER_LENGTH + 13]; + + netdev_dbg(dev->net, "Sending etherType: %02x%02x", ether_type_1, + ether_type_2); + + /* According to empiric data for data packages */ + header_start[0] = 0x57; + header_start[1] = 0x44; + content_len = skb->len - KALMIA_HEADER_LENGTH; + header_start[2] = (content_len & 0xff); /* low byte */ + header_start[3] = (content_len >> 8); /* high byte */ + + header_start[4] = ether_type_1; + header_start[5] = ether_type_2; + + /* Align to 4 bytes by padding with zeros */ + remainder = skb->len % KALMIA_ALIGN_SIZE; + if (remainder > 0) { + padlen = KALMIA_ALIGN_SIZE - remainder; + memset(skb_put(skb, padlen), 0, padlen); + } + + netdev_dbg( + dev->net, + "Sending package with length %i and padding %i. Header: %02x:%02x:%02x:%02x:%02x:%02x.", + content_len, padlen, header_start[0], header_start[1], + header_start[2], header_start[3], header_start[4], + header_start[5]); + + return skb; +} + +static int +kalmia_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + /* + * Our task here is to strip off framing, leaving skb with one + * data frame for the usbnet framework code to process. + */ + const u8 HEADER_END_OF_USB_PACKET[] = + { 0x57, 0x5a, 0x00, 0x00, 0x08, 0x00 }; + const u8 EXPECTED_UNKNOWN_HEADER_1[] = + { 0x57, 0x43, 0x1e, 0x00, 0x15, 0x02 }; + const u8 EXPECTED_UNKNOWN_HEADER_2[] = + { 0x57, 0x50, 0x0e, 0x00, 0x00, 0x00 }; + u8 i = 0; + + /* incomplete header? */ + if (skb->len < KALMIA_HEADER_LENGTH) + return 0; + + do { + struct sk_buff *skb2 = NULL; + u8 *header_start; + u16 usb_packet_length, ether_packet_length; + int is_last; + + header_start = skb->data; + + if (unlikely(header_start[0] != 0x57 || header_start[1] != 0x44)) { + if (!memcmp(header_start, EXPECTED_UNKNOWN_HEADER_1, + sizeof(EXPECTED_UNKNOWN_HEADER_1)) || !memcmp( + header_start, EXPECTED_UNKNOWN_HEADER_2, + sizeof(EXPECTED_UNKNOWN_HEADER_2))) { + netdev_dbg( + dev->net, + "Received expected unknown frame header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n", + header_start[0], header_start[1], + header_start[2], header_start[3], + header_start[4], header_start[5], + skb->len - KALMIA_HEADER_LENGTH); + } + else { + netdev_err( + dev->net, + "Received unknown frame header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n", + header_start[0], header_start[1], + header_start[2], header_start[3], + header_start[4], header_start[5], + skb->len - KALMIA_HEADER_LENGTH); + return 0; + } + } + else + netdev_dbg( + dev->net, + "Received header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n", + header_start[0], header_start[1], header_start[2], + header_start[3], header_start[4], header_start[5], + skb->len - KALMIA_HEADER_LENGTH); + + /* subtract start header and end header */ + usb_packet_length = skb->len - (2 * KALMIA_HEADER_LENGTH); + ether_packet_length = header_start[2] + (header_start[3] << 8); + skb_pull(skb, KALMIA_HEADER_LENGTH); + + /* Some small packets misses end marker */ + if (usb_packet_length < ether_packet_length) { + ether_packet_length = usb_packet_length + + KALMIA_HEADER_LENGTH; + is_last = true; + } + else { + netdev_dbg(dev->net, "Correct package length #%i", i + + 1); + + is_last = (memcmp(skb->data + ether_packet_length, + HEADER_END_OF_USB_PACKET, + sizeof(HEADER_END_OF_USB_PACKET)) == 0); + if (!is_last) { + header_start = skb->data + ether_packet_length; + netdev_dbg( + dev->net, + "End header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n", + header_start[0], header_start[1], + header_start[2], header_start[3], + header_start[4], header_start[5], + skb->len - KALMIA_HEADER_LENGTH); + } + } + + if (is_last) { + skb2 = skb; + } + else { + skb2 = skb_clone(skb, GFP_ATOMIC); + if (unlikely(!skb2)) + return 0; + } + + skb_trim(skb2, ether_packet_length); + + if (is_last) { + return 1; + } + else { + usbnet_skb_return(dev, skb2); + skb_pull(skb, ether_packet_length); + } + + i++; + } + while (skb->len); + + return 1; +} + +static const struct driver_info kalmia_info = { + .description = "Samsung Kalmia LTE USB dongle", + .flags = FLAG_WWAN, + .bind = kalmia_bind, + .rx_fixup = kalmia_rx_fixup, + .tx_fixup = kalmia_tx_fixup +}; + +/*-------------------------------------------------------------------------*/ + +static const struct usb_device_id products[] = { + /* The unswitched USB ID, to get the module auto loaded: */ + { USB_DEVICE(0x04e8, 0x689a) }, + /* The stick swithed into modem (by e.g. usb_modeswitch): */ + { USB_DEVICE(0x04e8, 0x6889), + .driver_info = (unsigned long) &kalmia_info, }, + { /* EMPTY == end of list */} }; +MODULE_DEVICE_TABLE( usb, products); + +static struct usb_driver kalmia_driver = { + .name = "kalmia", + .id_table = products, + .probe = usbnet_probe, + .disconnect = usbnet_disconnect, + .suspend = usbnet_suspend, + .resume = usbnet_resume +}; + +static int __init kalmia_init(void) +{ + return usb_register(&kalmia_driver); +} +module_init( kalmia_init); + +static void __exit kalmia_exit(void) +{ + usb_deregister(&kalmia_driver); +} +module_exit( kalmia_exit); + +MODULE_AUTHOR("Marius Bjoernstad Kotsbak <marius@kotsbak.com>"); +MODULE_DESCRIPTION("Samsung Kalmia USB network driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index e050bd6..777d1a4 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -2203,8 +2203,10 @@ fst_open(struct net_device *dev) if (port->mode != FST_RAW) { err = hdlc_open(dev); - if (err) + if (err) { + module_put(THIS_MODULE); return err; + } } fst_openport(port); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 2204762..b6c5d37 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -72,6 +72,11 @@ static int modparam_all_channels; module_param_named(all_channels, modparam_all_channels, bool, S_IRUGO); MODULE_PARM_DESC(all_channels, "Expose all channels the device can use."); +static int modparam_fastchanswitch; +module_param_named(fastchanswitch, modparam_fastchanswitch, bool, S_IRUGO); +MODULE_PARM_DESC(fastchanswitch, "Enable fast channel switching for AR2413/AR5413 radios."); + + /* Module info */ MODULE_AUTHOR("Jiri Slaby"); MODULE_AUTHOR("Nick Kossifidis"); @@ -2686,6 +2691,7 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan, struct ath5k_hw *ah = sc->ah; struct ath_common *common = ath5k_hw_common(ah); int ret, ani_mode; + bool fast; ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n"); @@ -2705,7 +2711,10 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan, ath5k_drain_tx_buffs(sc); if (chan) sc->curchan = chan; - ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL, + + fast = ((chan != NULL) && modparam_fastchanswitch) ? 1 : 0; + + ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, fast, skip_pcu); if (ret) { ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret); diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 3510de2..126a4ea 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -1124,8 +1124,11 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /* Non fatal, can happen eg. * on mode change */ ret = 0; - } else + } else { + ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_RESET, + "fast chan change successful\n"); return 0; + } } /* diff --git a/drivers/net/wireless/iwlegacy/iwl-4965.c b/drivers/net/wireless/iwlegacy/iwl-4965.c index f9db25b..facc94e 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965.c @@ -1218,10 +1218,10 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *c * receive commit_rxon request * abort any previous channel switch if still in process */ - if (priv->switch_rxon.switch_in_progress && - (priv->switch_rxon.channel != ctx->staging.channel)) { + if (test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status) && + (priv->switch_channel != ctx->staging.channel)) { IWL_DEBUG_11H(priv, "abort channel switch on %d\n", - le16_to_cpu(priv->switch_rxon.channel)); + le16_to_cpu(priv->switch_channel)); iwl_legacy_chswitch_done(priv, false); } @@ -1237,7 +1237,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *c memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon)); iwl_legacy_print_rx_config_cmd(priv, ctx); - return 0; + goto set_tx_power; } /* If we are currently associated and the new config requires @@ -1317,6 +1317,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *c iwl4965_init_sensitivity(priv); +set_tx_power: /* If we issue a new RXON command which required a tune then we must * send a new TXPOWER command or we won't be able to Tx any frames */ ret = iwl_legacy_set_tx_power(priv, priv->tx_power_next, true); @@ -1403,9 +1404,6 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, return rc; } - priv->switch_rxon.channel = cmd.channel; - priv->switch_rxon.switch_in_progress = true; - return iwl_legacy_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); } diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index 42df832..3be76bd 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c @@ -859,12 +859,8 @@ void iwl_legacy_chswitch_done(struct iwl_priv *priv, bool is_success) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - if (priv->switch_rxon.switch_in_progress) { + if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) ieee80211_chswitch_done(ctx->vif, is_success); - mutex_lock(&priv->mutex); - priv->switch_rxon.switch_in_progress = false; - mutex_unlock(&priv->mutex); - } } EXPORT_SYMBOL(iwl_legacy_chswitch_done); @@ -876,19 +872,19 @@ void iwl_legacy_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; struct iwl_legacy_rxon_cmd *rxon = (void *)&ctx->active; - if (priv->switch_rxon.switch_in_progress) { - if (!le32_to_cpu(csa->status) && - (csa->channel == priv->switch_rxon.channel)) { - rxon->channel = csa->channel; - ctx->staging.channel = csa->channel; - IWL_DEBUG_11H(priv, "CSA notif: channel %d\n", - le16_to_cpu(csa->channel)); - iwl_legacy_chswitch_done(priv, true); - } else { - IWL_ERR(priv, "CSA notif (fail) : channel %d\n", + if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) + return; + + if (!le32_to_cpu(csa->status) && csa->channel == priv->switch_channel) { + rxon->channel = csa->channel; + ctx->staging.channel = csa->channel; + IWL_DEBUG_11H(priv, "CSA notif: channel %d\n", le16_to_cpu(csa->channel)); - iwl_legacy_chswitch_done(priv, false); - } + iwl_legacy_chswitch_done(priv, true); + } else { + IWL_ERR(priv, "CSA notif (fail) : channel %d\n", + le16_to_cpu(csa->channel)); + iwl_legacy_chswitch_done(priv, false); } } EXPORT_SYMBOL(iwl_legacy_rx_csa); diff --git a/drivers/net/wireless/iwlegacy/iwl-core.h b/drivers/net/wireless/iwlegacy/iwl-core.h index bc66c60..c5fbda0 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.h +++ b/drivers/net/wireless/iwlegacy/iwl-core.h @@ -560,7 +560,7 @@ void iwl_legacy_free_geos(struct iwl_priv *priv); #define STATUS_SCAN_HW 15 #define STATUS_POWER_PMI 16 #define STATUS_FW_ERROR 17 - +#define STATUS_CHANNEL_SWITCH_PENDING 18 static inline int iwl_legacy_is_ready(struct iwl_priv *priv) { diff --git a/drivers/net/wireless/iwlegacy/iwl-dev.h b/drivers/net/wireless/iwlegacy/iwl-dev.h index be0106c..ea30122 100644 --- a/drivers/net/wireless/iwlegacy/iwl-dev.h +++ b/drivers/net/wireless/iwlegacy/iwl-dev.h @@ -855,17 +855,6 @@ struct traffic_stats { }; /* - * iwl_switch_rxon: "channel switch" structure - * - * @ switch_in_progress: channel switch in progress - * @ channel: new channel - */ -struct iwl_switch_rxon { - bool switch_in_progress; - __le16 channel; -}; - -/* * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds * to perform continuous uCode event logging operation if enabled */ @@ -1115,7 +1104,7 @@ struct iwl_priv { struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX]; - struct iwl_switch_rxon switch_rxon; + __le16 switch_channel; /* 1st responses from initialize and runtime uCode images. * _4965's initialize alive response contains some calibration data. */ diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c index af2ae22..7157ba5 100644 --- a/drivers/net/wireless/iwlegacy/iwl4965-base.c +++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c @@ -2861,16 +2861,13 @@ void iwl4965_mac_channel_switch(struct ieee80211_hw *hw, goto out; if (test_bit(STATUS_EXIT_PENDING, &priv->status) || - test_bit(STATUS_SCANNING, &priv->status)) + test_bit(STATUS_SCANNING, &priv->status) || + test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) goto out; if (!iwl_legacy_is_associated_ctx(ctx)) goto out; - /* channel switch in progress */ - if (priv->switch_rxon.switch_in_progress == true) - goto out; - if (priv->cfg->ops->lib->set_channel_switch) { ch = channel->hw_value; @@ -2919,15 +2916,18 @@ void iwl4965_mac_channel_switch(struct ieee80211_hw *hw, * at this point, staging_rxon has the * configuration for channel switch */ - if (priv->cfg->ops->lib->set_channel_switch(priv, - ch_switch)) - priv->switch_rxon.switch_in_progress = false; + set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status); + priv->switch_channel = cpu_to_le16(ch); + if (priv->cfg->ops->lib->set_channel_switch(priv, ch_switch)) { + clear_bit(STATUS_CHANNEL_SWITCH_PENDING, + &priv->status); + priv->switch_channel = 0; + ieee80211_chswitch_done(ctx->vif, false); + } } } out: mutex_unlock(&priv->mutex); - if (!priv->switch_rxon.switch_in_progress) - ieee80211_chswitch_done(ctx->vif, false); IWL_DEBUG_MAC80211(priv, "leave\n"); } diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 86feec8..2282279 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -177,79 +177,6 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) return 0; } -static int iwl2030_hw_channel_switch(struct iwl_priv *priv, - struct ieee80211_channel_switch *ch_switch) -{ - /* - * MULTI-FIXME - * See iwl_mac_channel_switch. - */ - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - struct iwl6000_channel_switch_cmd cmd; - const struct iwl_channel_info *ch_info; - u32 switch_time_in_usec, ucode_switch_time; - u16 ch; - u32 tsf_low; - u8 switch_count; - u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval); - struct ieee80211_vif *vif = ctx->vif; - struct iwl_host_cmd hcmd = { - .id = REPLY_CHANNEL_SWITCH, - .len = { sizeof(cmd), }, - .flags = CMD_SYNC, - .data = { &cmd, }, - }; - - cmd.band = priv->band == IEEE80211_BAND_2GHZ; - ch = ch_switch->channel->hw_value; - IWL_DEBUG_11H(priv, "channel switch from %u to %u\n", - ctx->active.channel, ch); - cmd.channel = cpu_to_le16(ch); - cmd.rxon_flags = ctx->staging.flags; - cmd.rxon_filter_flags = ctx->staging.filter_flags; - switch_count = ch_switch->count; - tsf_low = ch_switch->timestamp & 0x0ffffffff; - /* - * calculate the ucode channel switch time - * adding TSF as one of the factor for when to switch - */ - if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) { - if (switch_count > ((priv->ucode_beacon_time - tsf_low) / - beacon_interval)) { - switch_count -= (priv->ucode_beacon_time - - tsf_low) / beacon_interval; - } else - switch_count = 0; - } - if (switch_count <= 1) - cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); - else { - switch_time_in_usec = - vif->bss_conf.beacon_int * switch_count * TIME_UNIT; - ucode_switch_time = iwl_usecs_to_beacons(priv, - switch_time_in_usec, - beacon_interval); - cmd.switch_time = iwl_add_beacon_time(priv, - priv->ucode_beacon_time, - ucode_switch_time, - beacon_interval); - } - IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", - cmd.switch_time); - ch_info = iwl_get_channel_info(priv, priv->band, ch); - if (ch_info) - cmd.expect_beacon = is_channel_radar(ch_info); - else { - IWL_ERR(priv, "invalid channel switch from %u to %u\n", - ctx->active.channel, ch); - return -EFAULT; - } - priv->switch_rxon.channel = cmd.channel; - priv->switch_rxon.switch_in_progress = true; - - return iwl_send_cmd_sync(priv, &hcmd); -} - static struct iwl_lib_ops iwl2000_lib = { .set_hw_params = iwl2000_hw_set_hw_params, .rx_handler_setup = iwlagn_rx_handler_setup, @@ -258,7 +185,6 @@ static struct iwl_lib_ops iwl2000_lib = { .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, - .set_channel_switch = iwl2030_hw_channel_switch, .apm_ops = { .init = iwl_apm_init, .config = iwl2000_nic_config, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index a70b8cf..f99f9c1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -331,8 +331,6 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, ctx->active.channel, ch); return -EFAULT; } - priv->switch_rxon.channel = cmd.channel; - priv->switch_rxon.switch_in_progress = true; return iwl_send_cmd_sync(priv, &hcmd); } @@ -425,7 +423,6 @@ static struct iwl_base_params iwl5000_base_params = { }; static struct iwl_ht_params iwl5000_ht_params = { .ht_greenfield_support = true, - .use_rts_for_aggregation = true, /* use rts/cts protection */ }; #define IWL_DEVICE_5000 \ diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index fda6fe0..fbe565c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -270,8 +270,6 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, ctx->active.channel, ch); return -EFAULT; } - priv->switch_rxon.channel = cmd.channel; - priv->switch_rxon.switch_in_progress = true; return iwl_send_cmd_sync(priv, &hcmd); } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c index b12c72d..23fa93d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c @@ -163,17 +163,9 @@ static void iwlagn_tx_cmd_protection(struct iwl_priv *priv, __le16 fc, __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) { + info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT || + info->flags & IEEE80211_TX_CTL_AMPDU) *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK; - return; - } - - if (priv->cfg->ht_params && - priv->cfg->ht_params->use_rts_for_aggregation && - info->flags & IEEE80211_TX_CTL_AMPDU) { - *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK; - return; - } } /* Calc max signal level (dBm) among 3 possible receivers */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index a95ad84..09f679d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -325,6 +325,14 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) return 0; } + /* + * force CTS-to-self frames protection if RTS-CTS is not preferred + * one aggregation protection method + */ + if (!(priv->cfg->ht_params && + priv->cfg->ht_params->use_rts_for_aggregation)) + ctx->staging.flags |= RXON_FLG_SELF_CTS_EN; + if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) || !(ctx->staging.flags & RXON_FLG_BAND_24G_MSK)) ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; @@ -342,10 +350,10 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) * receive commit_rxon request * abort any previous channel switch if still in process */ - if (priv->switch_rxon.switch_in_progress && - (priv->switch_rxon.channel != ctx->staging.channel)) { + if (test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status) && + (priv->switch_channel != ctx->staging.channel)) { IWL_DEBUG_11H(priv, "abort channel switch on %d\n", - le16_to_cpu(priv->switch_rxon.channel)); + le16_to_cpu(priv->switch_channel)); iwl_chswitch_done(priv, false); } @@ -362,6 +370,11 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) } memcpy(active, &ctx->staging, sizeof(*active)); + /* + * We do not commit tx power settings while channel changing, + * do it now if after settings changed. + */ + iwl_set_tx_power(priv, priv->tx_power_next, false); return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index a662adc..8e1942e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2843,16 +2843,13 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, goto out; if (test_bit(STATUS_EXIT_PENDING, &priv->status) || - test_bit(STATUS_SCANNING, &priv->status)) + test_bit(STATUS_SCANNING, &priv->status) || + test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) goto out; if (!iwl_is_associated_ctx(ctx)) goto out; - /* channel switch in progress */ - if (priv->switch_rxon.switch_in_progress == true) - goto out; - if (priv->cfg->ops->lib->set_channel_switch) { ch = channel->hw_value; @@ -2901,15 +2898,19 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, * at this point, staging_rxon has the * configuration for channel switch */ + set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status); + priv->switch_channel = cpu_to_le16(ch); if (priv->cfg->ops->lib->set_channel_switch(priv, - ch_switch)) - priv->switch_rxon.switch_in_progress = false; + ch_switch)) { + clear_bit(STATUS_CHANNEL_SWITCH_PENDING, + &priv->status); + priv->switch_channel = 0; + ieee80211_chswitch_done(ctx->vif, false); + } } } out: mutex_unlock(&priv->mutex); - if (!priv->switch_rxon.switch_in_progress) - ieee80211_chswitch_done(ctx->vif, false); IWL_DEBUG_MAC80211(priv, "leave\n"); } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 4653dea..213c80c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -843,12 +843,8 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - if (priv->switch_rxon.switch_in_progress) { + if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) ieee80211_chswitch_done(ctx->vif, is_success); - mutex_lock(&priv->mutex); - priv->switch_rxon.switch_in_progress = false; - mutex_unlock(&priv->mutex); - } } #ifdef CONFIG_IWLWIFI_DEBUG diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 3bb76f6..a54d416 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -560,6 +560,7 @@ void iwlcore_free_geos(struct iwl_priv *priv); #define STATUS_POWER_PMI 16 #define STATUS_FW_ERROR 17 #define STATUS_DEVICE_ENABLED 18 +#define STATUS_CHANNEL_SWITCH_PENDING 19 static inline int iwl_is_ready(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 22a6e3e..c8de236 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -982,17 +982,6 @@ struct traffic_stats { }; /* - * iwl_switch_rxon: "channel switch" structure - * - * @ switch_in_progress: channel switch in progress - * @ channel: new channel - */ -struct iwl_switch_rxon { - bool switch_in_progress; - __le16 channel; -}; - -/* * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds * to perform continuous uCode event logging operation if enabled */ @@ -1287,7 +1276,7 @@ struct iwl_priv { struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX]; - struct iwl_switch_rxon switch_rxon; + __le16 switch_channel; struct { u32 error_event_table; diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 0053e9e..b774517 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -250,19 +250,19 @@ static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; struct iwl_rxon_cmd *rxon = (void *)&ctx->active; - if (priv->switch_rxon.switch_in_progress) { - if (!le32_to_cpu(csa->status) && - (csa->channel == priv->switch_rxon.channel)) { - rxon->channel = csa->channel; - ctx->staging.channel = csa->channel; - IWL_DEBUG_11H(priv, "CSA notif: channel %d\n", - le16_to_cpu(csa->channel)); - iwl_chswitch_done(priv, true); - } else { - IWL_ERR(priv, "CSA notif (fail) : channel %d\n", + if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) + return; + + if (!le32_to_cpu(csa->status) && csa->channel == priv->switch_channel) { + rxon->channel = csa->channel; + ctx->staging.channel = csa->channel; + IWL_DEBUG_11H(priv, "CSA notif: channel %d\n", le16_to_cpu(csa->channel)); - iwl_chswitch_done(priv, false); - } + iwl_chswitch_done(priv, true); + } else { + IWL_ERR(priv, "CSA notif (fail) : channel %d\n", + le16_to_cpu(csa->channel)); + iwl_chswitch_done(priv, false); } } diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index a7b5cb0..224e985 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -907,7 +907,7 @@ static void if_sdio_interrupt(struct sdio_func *func) card = sdio_get_drvdata(func); cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret); - if (ret) + if (ret || !cause) goto out; lbs_deb_sdio("interrupt: 0x%X\n", (unsigned)cause); @@ -1008,10 +1008,6 @@ static int if_sdio_probe(struct sdio_func *func, if (ret) goto release; - ret = sdio_claim_irq(func, if_sdio_interrupt); - if (ret) - goto disable; - /* For 1-bit transfers to the 8686 model, we need to enable the * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0 * bit to allow access to non-vendor registers. */ @@ -1083,6 +1079,21 @@ static int if_sdio_probe(struct sdio_func *func, card->rx_unit = 0; /* + * Set up the interrupt handler late. + * + * If we set it up earlier, the (buggy) hardware generates a spurious + * interrupt, even before the interrupt has been enabled, with + * CCCR_INTx = 0. + * + * We register the interrupt handler late so that we can handle any + * spurious interrupts, and also to avoid generation of that known + * spurious interrupt in the first place. + */ + ret = sdio_claim_irq(func, if_sdio_interrupt); + if (ret) + goto disable; + + /* * Enable interrupts now that everything is set up */ sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret); diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 660831c..687c1f2 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1288,6 +1288,8 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, *(unsigned long *) wdev_priv = (unsigned long) priv; + set_wiphy_dev(wdev->wiphy, (struct device *) priv->adapter->dev); + ret = wiphy_register(wdev->wiphy); if (ret < 0) { dev_err(priv->adapter->dev, "%s: registering cfg80211 device\n", diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 3226118..aeac3cc 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2474,6 +2474,7 @@ struct mwl8k_cmd_set_hw_spec { * faster client. */ #define MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY 0x00000400 +#define MWL8K_SET_HW_SPEC_FLAG_GENERATE_CCMP_HDR 0x00000200 #define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020 #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010 @@ -2510,7 +2511,8 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON | - MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY); + MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY | + MWL8K_SET_HW_SPEC_FLAG_GENERATE_CCMP_HDR); cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 555180d..b704e5b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -250,7 +250,8 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) rt2x00link_reset_tuner(rt2x00dev, false); - if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && + if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && + test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && (ieee80211_flags & IEEE80211_CONF_CHANGE_PS) && (conf->flags & IEEE80211_CONF_PS)) { beacon_diff = (long)jiffies - (long)rt2x00dev->last_beacon; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index c018d67a..939821b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -146,6 +146,9 @@ static void rt2x00lib_autowakeup(struct work_struct *work) struct rt2x00_dev *rt2x00dev = container_of(work, struct rt2x00_dev, autowakeup_work.work); + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) + return; + if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) ERROR(rt2x00dev, "Device failed to wakeup.\n"); clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); @@ -1160,6 +1163,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) * Stop all work. */ cancel_work_sync(&rt2x00dev->intf_work); + cancel_delayed_work_sync(&rt2x00dev->autowakeup_work); if (rt2x00_is_usb(rt2x00dev)) { del_timer_sync(&rt2x00dev->txstatus_timer); cancel_work_sync(&rt2x00dev->rxdone_work); diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 89100e7..9f8ccae93 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -669,6 +669,19 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) &rx_status, (u8 *) pdesc, skb); + new_skb = dev_alloc_skb(rtlpci->rxbuffersize); + if (unlikely(!new_skb)) { + RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV), + DBG_DMESG, + ("can't alloc skb for rx\n")); + goto done; + } + + pci_unmap_single(rtlpci->pdev, + *((dma_addr_t *) skb->cb), + rtlpci->rxbuffersize, + PCI_DMA_FROMDEVICE); + skb_put(skb, rtlpriv->cfg->ops->get_desc((u8 *) pdesc, false, HW_DESC_RXPKT_LEN)); @@ -685,22 +698,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) hdr = rtl_get_hdr(skb); fc = rtl_get_fc(skb); - /* try for new buffer - if allocation fails, drop - * frame and reuse old buffer - */ - new_skb = dev_alloc_skb(rtlpci->rxbuffersize); - if (unlikely(!new_skb)) { - RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV), - DBG_DMESG, - ("can't alloc skb for rx\n")); - goto done; - } - pci_unmap_single(rtlpci->pdev, - *((dma_addr_t *) skb->cb), - rtlpci->rxbuffersize, - PCI_DMA_FROMDEVICE); - - if (!stats.crc || !stats.hwerror) { + if (!stats.crc && !stats.hwerror) { memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index a3984f4..f34b5b2 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -141,6 +141,13 @@ static struct notifier_block module_load_nb = { .notifier_call = module_load_notify, }; +static void free_all_tasks(void) +{ + /* make sure we don't leak task structs */ + process_task_mortuary(); + process_task_mortuary(); +} + int sync_start(void) { int err; @@ -148,8 +155,6 @@ int sync_start(void) if (!zalloc_cpumask_var(&marked_cpus, GFP_KERNEL)) return -ENOMEM; - mutex_lock(&buffer_mutex); - err = task_handoff_register(&task_free_nb); if (err) goto out1; @@ -166,7 +171,6 @@ int sync_start(void) start_cpu_work(); out: - mutex_unlock(&buffer_mutex); return err; out4: profile_event_unregister(PROFILE_MUNMAP, &munmap_nb); @@ -174,6 +178,7 @@ out3: profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb); out2: task_handoff_unregister(&task_free_nb); + free_all_tasks(); out1: free_cpumask_var(marked_cpus); goto out; @@ -182,20 +187,16 @@ out1: void sync_stop(void) { - /* flush buffers */ - mutex_lock(&buffer_mutex); end_cpu_work(); unregister_module_notifier(&module_load_nb); profile_event_unregister(PROFILE_MUNMAP, &munmap_nb); profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb); task_handoff_unregister(&task_free_nb); - mutex_unlock(&buffer_mutex); - flush_cpu_work(); + barrier(); /* do all of the above first */ - /* make sure we don't leak task structs */ - process_task_mortuary(); - process_task_mortuary(); + flush_cpu_work(); + free_all_tasks(); free_cpumask_var(marked_cpus); } diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index c85f744..094308e 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_X86_VISWS) += setup-irq.o obj-$(CONFIG_MN10300) += setup-bus.o obj-$(CONFIG_MICROBLAZE) += setup-bus.o obj-$(CONFIG_TILE) += setup-bus.o setup-irq.o +obj-$(CONFIG_SPARC_LEON) += setup-bus.o setup-irq.o # # ACPI Related PCI FW Functions diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 135df16..46767c5 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -624,7 +624,7 @@ static int pci_pm_prepare(struct device *dev) * system from the sleep state, we'll have to prevent it from signaling * wake-up. */ - pm_runtime_resume(dev); + pm_runtime_get_sync(dev); if (drv && drv->pm && drv->pm->prepare) error = drv->pm->prepare(dev); @@ -638,6 +638,8 @@ static void pci_pm_complete(struct device *dev) if (drv && drv->pm && drv->pm->complete) drv->pm->complete(dev); + + pm_runtime_put_sync(dev); } #else /* !CONFIG_PM_SLEEP */ diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 56098b3..2c5b9b9 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3271,11 +3271,11 @@ void __init pci_register_set_vga_state(arch_set_vga_state_t func) } static int pci_set_vga_state_arch(struct pci_dev *dev, bool decode, - unsigned int command_bits, bool change_bridge) + unsigned int command_bits, u32 flags) { if (arch_set_vga_state) return arch_set_vga_state(dev, decode, command_bits, - change_bridge); + flags); return 0; } @@ -3284,7 +3284,7 @@ static int pci_set_vga_state_arch(struct pci_dev *dev, bool decode, * @dev: the PCI device * @decode: true = enable decoding, false = disable decoding * @command_bits: PCI_COMMAND_IO and/or PCI_COMMAND_MEMORY - * @change_bridge_flags: traverse ancestors and change bridges + * @flags: traverse ancestors and change bridges * CHANGE_BRIDGE_ONLY / CHANGE_BRIDGE */ int pci_set_vga_state(struct pci_dev *dev, bool decode, diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 48849ff..bafb3c3 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -168,7 +168,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN; if (type == pci_bar_io) { l &= PCI_BASE_ADDRESS_IO_MASK; - mask = PCI_BASE_ADDRESS_IO_MASK & IO_SPACE_LIMIT; + mask = PCI_BASE_ADDRESS_IO_MASK & (u32) IO_SPACE_LIMIT; } else { l &= PCI_BASE_ADDRESS_MEM_MASK; mask = (u32)PCI_BASE_ADDRESS_MEM_MASK; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index e8a1406..02145e9 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2761,6 +2761,8 @@ static void ricoh_mmc_fixup_r5c832(struct pci_dev *dev) } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5CE823, ricoh_mmc_fixup_r5c832); +DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5CE823, ricoh_mmc_fixup_r5c832); #endif /*CONFIG_MMC_RICOH_MMC*/ #if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP) diff --git a/drivers/pcmcia/pxa2xx_vpac270.c b/drivers/pcmcia/pxa2xx_vpac270.c index 435002d..712baab 100644 --- a/drivers/pcmcia/pxa2xx_vpac270.c +++ b/drivers/pcmcia/pxa2xx_vpac270.c @@ -11,6 +11,7 @@ * */ +#include <linux/gpio.h> #include <linux/module.h> #include <linux/platform_device.h> diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c index a8d03ae..e7f301da2 100644 --- a/drivers/ptp/ptp_chardev.c +++ b/drivers/ptp/ptp_chardev.c @@ -46,7 +46,8 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg) caps.n_ext_ts = ptp->info->n_ext_ts; caps.n_per_out = ptp->info->n_per_out; caps.pps = ptp->info->pps; - err = copy_to_user((void __user *)arg, &caps, sizeof(caps)); + if (copy_to_user((void __user *)arg, &caps, sizeof(caps))) + err = -EFAULT; break; case PTP_EXTTS_REQUEST: @@ -129,8 +130,10 @@ ssize_t ptp_read(struct posix_clock *pc, return -ERESTARTSYS; } - if (ptp->defunct) + if (ptp->defunct) { + mutex_unlock(&ptp->tsevq_mux); return -ENODEV; + } spin_lock_irqsave(&queue->lock, flags); @@ -150,10 +153,8 @@ ssize_t ptp_read(struct posix_clock *pc, mutex_unlock(&ptp->tsevq_mux); - if (copy_to_user(buf, event, cnt)) { - mutex_unlock(&ptp->tsevq_mux); + if (copy_to_user(buf, event, cnt)) return -EFAULT; - } return cnt; } diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index f822e13..ce2aabf 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1051,4 +1051,13 @@ config RTC_DRV_TILE Enable support for the Linux driver side of the Tilera hypervisor's real-time clock interface. +config RTC_DRV_PUV3 + tristate "PKUnity v3 RTC support" + depends on ARCH_PUV3 + help + This enables support for the RTC in the PKUnity-v3 SoCs. + + This drive can also be built as a module. If so, the module + will be called rtc-puv3. + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 213d725..0ffefe8 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -78,6 +78,7 @@ obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o +obj-$(CONFIG_RTC_DRV_PUV3) += rtc-puv3.o obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c01.o diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index ef6316a..df68618 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -318,7 +318,7 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) } EXPORT_SYMBOL_GPL(rtc_read_alarm); -int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) +static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { struct rtc_time tm; long now, scheduled; diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index d0e06ed..cace6d3 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -421,7 +421,8 @@ static long rtc_dev_ioctl(struct file *file, err = ops->ioctl(rtc->dev.parent, cmd, arg); if (err == -ENOIOCTLCMD) err = -ENOTTY; - } + } else + err = -ENOTTY; break; } diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 4724ba3..b2005b4 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -149,6 +149,7 @@ static const struct i2c_device_id ds1307_id[] = { { "ds1340", ds_1340 }, { "ds3231", ds_3231 }, { "m41t00", m41t00 }, + { "pt7c4338", ds_1307 }, { "rx8025", rx_8025 }, { } }; diff --git a/drivers/rtc/rtc-puv3.c b/drivers/rtc/rtc-puv3.c new file mode 100644 index 0000000..46f14b8 --- /dev/null +++ b/drivers/rtc/rtc-puv3.c @@ -0,0 +1,359 @@ +/* + * RTC driver code specific to PKUnity SoC and UniCore ISA + * + * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> + * Copyright (C) 2001-2010 Guan Xuetao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/rtc.h> +#include <linux/bcd.h> +#include <linux/clk.h> +#include <linux/log2.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/io.h> + +#include <asm/irq.h> +#include <mach/hardware.h> + +static struct resource *puv3_rtc_mem; + +static int puv3_rtc_alarmno = IRQ_RTCAlarm; +static int puv3_rtc_tickno = IRQ_RTC; + +static DEFINE_SPINLOCK(puv3_rtc_pie_lock); + +/* IRQ Handlers */ +static irqreturn_t puv3_rtc_alarmirq(int irq, void *id) +{ + struct rtc_device *rdev = id; + + writel(readl(RTC_RTSR) | RTC_RTSR_AL, RTC_RTSR); + rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF); + return IRQ_HANDLED; +} + +static irqreturn_t puv3_rtc_tickirq(int irq, void *id) +{ + struct rtc_device *rdev = id; + + writel(readl(RTC_RTSR) | RTC_RTSR_HZ, RTC_RTSR); + rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF); + return IRQ_HANDLED; +} + +/* Update control registers */ +static void puv3_rtc_setaie(int to) +{ + unsigned int tmp; + + pr_debug("%s: aie=%d\n", __func__, to); + + tmp = readl(RTC_RTSR) & ~RTC_RTSR_ALE; + + if (to) + tmp |= RTC_RTSR_ALE; + + writel(tmp, RTC_RTSR); +} + +static int puv3_rtc_setpie(struct device *dev, int enabled) +{ + unsigned int tmp; + + pr_debug("%s: pie=%d\n", __func__, enabled); + + spin_lock_irq(&puv3_rtc_pie_lock); + tmp = readl(RTC_RTSR) & ~RTC_RTSR_HZE; + + if (enabled) + tmp |= RTC_RTSR_HZE; + + writel(tmp, RTC_RTSR); + spin_unlock_irq(&puv3_rtc_pie_lock); + + return 0; +} + +/* Time read/write */ +static int puv3_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) +{ + rtc_time_to_tm(readl(RTC_RCNR), rtc_tm); + + pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n", + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, + rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); + + return 0; +} + +static int puv3_rtc_settime(struct device *dev, struct rtc_time *tm) +{ + unsigned long rtc_count = 0; + + pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n", + tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + rtc_tm_to_time(tm, &rtc_count); + writel(rtc_count, RTC_RCNR); + + return 0; +} + +static int puv3_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct rtc_time *alm_tm = &alrm->time; + + rtc_time_to_tm(readl(RTC_RTAR), alm_tm); + + alrm->enabled = readl(RTC_RTSR) & RTC_RTSR_ALE; + + pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n", + alrm->enabled, + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, + alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); + + return 0; +} + +static int puv3_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct rtc_time *tm = &alrm->time; + unsigned long rtcalarm_count = 0; + + pr_debug("puv3_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n", + alrm->enabled, + tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff, + tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec); + + rtc_tm_to_time(tm, &rtcalarm_count); + writel(rtcalarm_count, RTC_RTAR); + + puv3_rtc_setaie(alrm->enabled); + + if (alrm->enabled) + enable_irq_wake(puv3_rtc_alarmno); + else + disable_irq_wake(puv3_rtc_alarmno); + + return 0; +} + +static int puv3_rtc_proc(struct device *dev, struct seq_file *seq) +{ + seq_printf(seq, "periodic_IRQ\t: %s\n", + (readl(RTC_RTSR) & RTC_RTSR_HZE) ? "yes" : "no"); + return 0; +} + +static int puv3_rtc_open(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtc_device *rtc_dev = platform_get_drvdata(pdev); + int ret; + + ret = request_irq(puv3_rtc_alarmno, puv3_rtc_alarmirq, + IRQF_DISABLED, "pkunity-rtc alarm", rtc_dev); + + if (ret) { + dev_err(dev, "IRQ%d error %d\n", puv3_rtc_alarmno, ret); + return ret; + } + + ret = request_irq(puv3_rtc_tickno, puv3_rtc_tickirq, + IRQF_DISABLED, "pkunity-rtc tick", rtc_dev); + + if (ret) { + dev_err(dev, "IRQ%d error %d\n", puv3_rtc_tickno, ret); + goto tick_err; + } + + return ret; + + tick_err: + free_irq(puv3_rtc_alarmno, rtc_dev); + return ret; +} + +static void puv3_rtc_release(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtc_device *rtc_dev = platform_get_drvdata(pdev); + + /* do not clear AIE here, it may be needed for wake */ + puv3_rtc_setpie(dev, 0); + free_irq(puv3_rtc_alarmno, rtc_dev); + free_irq(puv3_rtc_tickno, rtc_dev); +} + +static const struct rtc_class_ops puv3_rtcops = { + .open = puv3_rtc_open, + .release = puv3_rtc_release, + .read_time = puv3_rtc_gettime, + .set_time = puv3_rtc_settime, + .read_alarm = puv3_rtc_getalarm, + .set_alarm = puv3_rtc_setalarm, + .proc = puv3_rtc_proc, +}; + +static void puv3_rtc_enable(struct platform_device *pdev, int en) +{ + if (!en) { + writel(readl(RTC_RTSR) & ~RTC_RTSR_HZE, RTC_RTSR); + } else { + /* re-enable the device, and check it is ok */ + if ((readl(RTC_RTSR) & RTC_RTSR_HZE) == 0) { + dev_info(&pdev->dev, "rtc disabled, re-enabling\n"); + writel(readl(RTC_RTSR) | RTC_RTSR_HZE, RTC_RTSR); + } + } +} + +static int puv3_rtc_remove(struct platform_device *dev) +{ + struct rtc_device *rtc = platform_get_drvdata(dev); + + platform_set_drvdata(dev, NULL); + rtc_device_unregister(rtc); + + puv3_rtc_setpie(&dev->dev, 0); + puv3_rtc_setaie(0); + + release_resource(puv3_rtc_mem); + kfree(puv3_rtc_mem); + + return 0; +} + +static int puv3_rtc_probe(struct platform_device *pdev) +{ + struct rtc_device *rtc; + struct resource *res; + int ret; + + pr_debug("%s: probe=%p\n", __func__, pdev); + + /* find the IRQs */ + puv3_rtc_tickno = platform_get_irq(pdev, 1); + if (puv3_rtc_tickno < 0) { + dev_err(&pdev->dev, "no irq for rtc tick\n"); + return -ENOENT; + } + + puv3_rtc_alarmno = platform_get_irq(pdev, 0); + if (puv3_rtc_alarmno < 0) { + dev_err(&pdev->dev, "no irq for alarm\n"); + return -ENOENT; + } + + pr_debug("PKUnity_rtc: tick irq %d, alarm irq %d\n", + puv3_rtc_tickno, puv3_rtc_alarmno); + + /* get the memory region */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "failed to get memory region resource\n"); + return -ENOENT; + } + + puv3_rtc_mem = request_mem_region(res->start, + res->end-res->start+1, + pdev->name); + + if (puv3_rtc_mem == NULL) { + dev_err(&pdev->dev, "failed to reserve memory region\n"); + ret = -ENOENT; + goto err_nores; + } + + puv3_rtc_enable(pdev, 1); + + /* register RTC and exit */ + rtc = rtc_device_register("pkunity", &pdev->dev, &puv3_rtcops, + THIS_MODULE); + + if (IS_ERR(rtc)) { + dev_err(&pdev->dev, "cannot attach rtc\n"); + ret = PTR_ERR(rtc); + goto err_nortc; + } + + /* platform setup code should have handled this; sigh */ + if (!device_can_wakeup(&pdev->dev)) + device_init_wakeup(&pdev->dev, 1); + + platform_set_drvdata(pdev, rtc); + return 0; + + err_nortc: + puv3_rtc_enable(pdev, 0); + release_resource(puv3_rtc_mem); + + err_nores: + return ret; +} + +#ifdef CONFIG_PM + +static int ticnt_save; + +static int puv3_rtc_suspend(struct platform_device *pdev, pm_message_t state) +{ + /* save RTAR for anyone using periodic interrupts */ + ticnt_save = readl(RTC_RTAR); + puv3_rtc_enable(pdev, 0); + return 0; +} + +static int puv3_rtc_resume(struct platform_device *pdev) +{ + puv3_rtc_enable(pdev, 1); + writel(ticnt_save, RTC_RTAR); + return 0; +} +#else +#define puv3_rtc_suspend NULL +#define puv3_rtc_resume NULL +#endif + +static struct platform_driver puv3_rtcdrv = { + .probe = puv3_rtc_probe, + .remove = __devexit_p(puv3_rtc_remove), + .suspend = puv3_rtc_suspend, + .resume = puv3_rtc_resume, + .driver = { + .name = "PKUnity-v3-RTC", + .owner = THIS_MODULE, + } +}; + +static char __initdata banner[] = "PKUnity-v3 RTC, (c) 2009 PKUnity Co.\n"; + +static int __init puv3_rtc_init(void) +{ + printk(banner); + return platform_driver_register(&puv3_rtcdrv); +} + +static void __exit puv3_rtc_exit(void) +{ + platform_driver_unregister(&puv3_rtcdrv); +} + +module_init(puv3_rtc_init); +module_exit(puv3_rtc_exit); + +MODULE_DESCRIPTION("RTC Driver for the PKUnity v3 chip"); +MODULE_AUTHOR("Hu Dongliang"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c index b8bc862..efd6066 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c @@ -78,7 +78,6 @@ struct vt8500_rtc { void __iomem *regbase; struct resource *res; int irq_alarm; - int irq_hz; struct rtc_device *rtc; spinlock_t lock; /* Protects this structure */ }; @@ -100,10 +99,6 @@ static irqreturn_t vt8500_rtc_irq(int irq, void *dev_id) if (isr & 1) events |= RTC_AF | RTC_IRQF; - /* Only second/minute interrupts are supported */ - if (isr & 2) - events |= RTC_UF | RTC_IRQF; - rtc_update_irq(vt8500_rtc->rtc, 1, events); return IRQ_HANDLED; @@ -199,27 +194,12 @@ static int vt8500_alarm_irq_enable(struct device *dev, unsigned int enabled) return 0; } -static int vt8500_update_irq_enable(struct device *dev, unsigned int enabled) -{ - struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev); - unsigned long tmp = readl(vt8500_rtc->regbase + VT8500_RTC_CR); - - if (enabled) - tmp |= VT8500_RTC_CR_SM_SEC | VT8500_RTC_CR_SM_ENABLE; - else - tmp &= ~VT8500_RTC_CR_SM_ENABLE; - - writel(tmp, vt8500_rtc->regbase + VT8500_RTC_CR); - return 0; -} - static const struct rtc_class_ops vt8500_rtc_ops = { .read_time = vt8500_rtc_read_time, .set_time = vt8500_rtc_set_time, .read_alarm = vt8500_rtc_read_alarm, .set_alarm = vt8500_rtc_set_alarm, .alarm_irq_enable = vt8500_alarm_irq_enable, - .update_irq_enable = vt8500_update_irq_enable, }; static int __devinit vt8500_rtc_probe(struct platform_device *pdev) @@ -248,13 +228,6 @@ static int __devinit vt8500_rtc_probe(struct platform_device *pdev) goto err_free; } - vt8500_rtc->irq_hz = platform_get_irq(pdev, 1); - if (vt8500_rtc->irq_hz < 0) { - dev_err(&pdev->dev, "No 1Hz IRQ resource defined\n"); - ret = -ENXIO; - goto err_free; - } - vt8500_rtc->res = request_mem_region(vt8500_rtc->res->start, resource_size(vt8500_rtc->res), "vt8500-rtc"); @@ -272,9 +245,8 @@ static int __devinit vt8500_rtc_probe(struct platform_device *pdev) goto err_release; } - /* Enable the second/minute interrupt generation and enable RTC */ - writel(VT8500_RTC_CR_ENABLE | VT8500_RTC_CR_24H - | VT8500_RTC_CR_SM_ENABLE | VT8500_RTC_CR_SM_SEC, + /* Enable RTC and set it to 24-hour mode */ + writel(VT8500_RTC_CR_ENABLE | VT8500_RTC_CR_24H, vt8500_rtc->regbase + VT8500_RTC_CR); vt8500_rtc->rtc = rtc_device_register("vt8500-rtc", &pdev->dev, @@ -286,26 +258,16 @@ static int __devinit vt8500_rtc_probe(struct platform_device *pdev) goto err_unmap; } - ret = request_irq(vt8500_rtc->irq_hz, vt8500_rtc_irq, 0, - "rtc 1Hz", vt8500_rtc); - if (ret < 0) { - dev_err(&pdev->dev, "can't get irq %i, err %d\n", - vt8500_rtc->irq_hz, ret); - goto err_unreg; - } - ret = request_irq(vt8500_rtc->irq_alarm, vt8500_rtc_irq, 0, "rtc alarm", vt8500_rtc); if (ret < 0) { dev_err(&pdev->dev, "can't get irq %i, err %d\n", vt8500_rtc->irq_alarm, ret); - goto err_free_hz; + goto err_unreg; } return 0; -err_free_hz: - free_irq(vt8500_rtc->irq_hz, vt8500_rtc); err_unreg: rtc_device_unregister(vt8500_rtc->rtc); err_unmap: @@ -323,7 +285,6 @@ static int __devexit vt8500_rtc_remove(struct platform_device *pdev) struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev); free_irq(vt8500_rtc->irq_alarm, vt8500_rtc); - free_irq(vt8500_rtc->irq_hz, vt8500_rtc); rtc_device_unregister(vt8500_rtc->rtc); diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c index 4f64183..7e9c399 100644 --- a/drivers/sh/clk/core.c +++ b/drivers/sh/clk/core.c @@ -635,7 +635,7 @@ static void clks_core_resume(void) struct clk *clkp; list_for_each_entry(clkp, &clock_list, node) { - if (likely(clkp->ops)) { + if (likely(clkp->usecount && clkp->ops)) { unsigned long rate = clkp->rate; if (likely(clkp->ops->set_parent)) diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c index 6a9e58d..d18ce9e 100644 --- a/drivers/spi/amba-pl022.c +++ b/drivers/spi/amba-pl022.c @@ -1861,6 +1861,7 @@ static int pl022_setup(struct spi_device *spi) } if ((clk_freq.cpsdvsr < CPSDVR_MIN) || (clk_freq.cpsdvsr > CPSDVR_MAX)) { + status = -EINVAL; dev_err(&spi->dev, "cpsdvsr is configured incorrectly\n"); goto err_config_params; diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index f706dba..cc880c9 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -681,13 +681,14 @@ static void bfin_spi_pump_transfers(unsigned long data) drv_data->cs_change = transfer->cs_change; /* Bits per word setup */ - bits_per_word = transfer->bits_per_word ? : message->spi->bits_per_word; - if ((bits_per_word > 0) && (bits_per_word % 16 == 0)) { + bits_per_word = transfer->bits_per_word ? : + message->spi->bits_per_word ? : 8; + if (bits_per_word % 16 == 0) { drv_data->n_bytes = bits_per_word/8; drv_data->len = (transfer->len) >> 1; cr_width = BIT_CTL_WORDSIZE; drv_data->ops = &bfin_bfin_spi_transfer_ops_u16; - } else if ((bits_per_word > 0) && (bits_per_word % 8 == 0)) { + } else if (bits_per_word % 8 == 0) { drv_data->n_bytes = bits_per_word/8; drv_data->len = transfer->len; cr_width = 0; diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 82feb34..2a20dab 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -539,10 +539,12 @@ void ssb_pcicore_init(struct ssb_pcicore *pc) if (!pc->hostmode) ssb_pcicore_init_clientmode(pc); - /* Additional always once-executed workarounds */ - ssb_pcicore_serdes_workaround(pc); - /* TODO: ASPM */ - /* TODO: Clock Request Update */ + /* Additional PCIe always once-executed workarounds */ + if (dev->id.coreid == SSB_DEV_PCIE) { + ssb_pcicore_serdes_workaround(pc); + /* TODO: ASPM */ + /* TODO: Clock Request Update */ + } } static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address) diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index dfc16f9..196284d 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -24,23 +24,6 @@ menuconfig STAGING if STAGING -config STAGING_EXCLUDE_BUILD - bool "Exclude Staging drivers from being built" if STAGING - default y - ---help--- - Are you sure you really want to build the staging drivers? - They taint your kernel, don't live up to the normal Linux - kernel quality standards, are a bit crufty around the edges, - and might go off and kick your dog when you aren't paying - attention. - - Say N here to be able to select and build the Staging drivers. - This option is primarily here to prevent them from being built - when selecting 'make allyesconfg' and 'make allmodconfig' so - don't be all that put off, your dog will be just fine. - -if !STAGING_EXCLUDE_BUILD - source "drivers/staging/tty/Kconfig" source "drivers/staging/generic_serial/Kconfig" @@ -177,5 +160,4 @@ source "drivers/staging/mei/Kconfig" source "drivers/staging/nvec/Kconfig" -endif # !STAGING_EXCLUDE_BUILD endif # STAGING diff --git a/drivers/staging/altera-stapl/altera-jtag.c b/drivers/staging/altera-stapl/altera-jtag.c index 8763088..8b1620b 100644 --- a/drivers/staging/altera-stapl/altera-jtag.c +++ b/drivers/staging/altera-stapl/altera-jtag.c @@ -26,7 +26,7 @@ #include <linux/delay.h> #include <linux/firmware.h> #include <linux/slab.h> -#include <staging/altera.h> +#include "altera.h" #include "altera-exprt.h" #include "altera-jtag.h" diff --git a/drivers/staging/altera-stapl/altera.c b/drivers/staging/altera-stapl/altera.c index 05aad35..9cd5e76 100644 --- a/drivers/staging/altera-stapl/altera.c +++ b/drivers/staging/altera-stapl/altera.c @@ -28,7 +28,7 @@ #include <linux/string.h> #include <linux/firmware.h> #include <linux/slab.h> -#include <staging/altera.h> +#include "altera.h" #include "altera-exprt.h" #include "altera-jtag.h" diff --git a/drivers/staging/altera-stapl/altera.h b/drivers/staging/altera-stapl/altera.h new file mode 100644 index 0000000..94c0c61 --- /dev/null +++ b/drivers/staging/altera-stapl/altera.h @@ -0,0 +1,49 @@ +/* + * altera.h + * + * altera FPGA driver + * + * Copyright (C) Altera Corporation 1998-2001 + * Copyright (C) 2010 NetUP Inc. + * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru> + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _ALTERA_H_ +#define _ALTERA_H_ + +struct altera_config { + void *dev; + u8 *action; + int (*jtag_io) (void *dev, int tms, int tdi, int tdo); +}; + +#if defined(CONFIG_ALTERA_STAPL) || \ + (defined(CONFIG_ALTERA_STAPL_MODULE) && defined(MODULE)) + +extern int altera_init(struct altera_config *config, const struct firmware *fw); +#else + +static inline int altera_init(struct altera_config *config, + const struct firmware *fw) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} +#endif /* CONFIG_ALTERA_STAPL */ + +#endif /* _ALTERA_H_ */ diff --git a/drivers/staging/ath6kl/Kconfig b/drivers/staging/ath6kl/Kconfig index 1f15e1f..afd6cc1 100644 --- a/drivers/staging/ath6kl/Kconfig +++ b/drivers/staging/ath6kl/Kconfig @@ -1,6 +1,7 @@ config ATH6K_LEGACY tristate "Atheros AR6003 support (non mac80211)" depends on MMC && WLAN + depends on CFG80211 select WIRELESS_EXT select WEXT_PRIV help diff --git a/drivers/staging/ath6kl/os/linux/cfg80211.c b/drivers/staging/ath6kl/os/linux/cfg80211.c index 77dfb40..d3a774d 100644 --- a/drivers/staging/ath6kl/os/linux/cfg80211.c +++ b/drivers/staging/ath6kl/os/linux/cfg80211.c @@ -870,7 +870,8 @@ ar6k_cfg80211_scanComplete_event(struct ar6_softc *ar, int status) if(ar->scan_request) { /* Translate data to cfg80211 mgmt format */ - wmi_iterate_nodes(ar->arWmi, ar6k_cfg80211_scan_node, ar->wdev->wiphy); + if (ar->arWmi) + wmi_iterate_nodes(ar->arWmi, ar6k_cfg80211_scan_node, ar->wdev->wiphy); cfg80211_scan_done(ar->scan_request, ((status & A_ECANCELED) || (status & A_EBUSY)) ? true : false); diff --git a/drivers/staging/brcm80211/Kconfig b/drivers/staging/brcm80211/Kconfig index f4cf9b2..379cf16 100644 --- a/drivers/staging/brcm80211/Kconfig +++ b/drivers/staging/brcm80211/Kconfig @@ -7,6 +7,7 @@ config BRCMSMAC default n depends on PCI depends on WLAN && MAC80211 + depends on X86 || MIPS select BRCMUTIL select FW_LOADER select CRC_CCITT @@ -20,6 +21,7 @@ config BRCMFMAC default n depends on MMC depends on WLAN && CFG80211 + depends on X86 || MIPS select BRCMUTIL select FW_LOADER select WIRELESS_EXT diff --git a/drivers/staging/brcm80211/brcmfmac/wl_iw.c b/drivers/staging/brcm80211/brcmfmac/wl_iw.c index 929ceaf..15e1b05 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_iw.c +++ b/drivers/staging/brcm80211/brcmfmac/wl_iw.c @@ -64,8 +64,6 @@ wl_iw_extra_params_t g_wl_iw_params; extern bool wl_iw_conn_status_str(u32 event_type, u32 status, u32 reason, char *stringBuf, uint buflen); -uint wl_msg_level = WL_ERROR_VAL; - #define MAX_WLIW_IOCTL_LEN 1024 #ifdef CONFIG_WIRELESS_EXT diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 1502d80..20008a4 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -2,6 +2,7 @@ config COMEDI tristate "Data acquisition support (comedi)" default N depends on m + depends on BROKEN || FRV || M32R || MN10300 || SUPERH || TILE || X86 ---help--- Enable support a wide range of data acquisition devices for Linux. @@ -160,6 +161,7 @@ config COMEDI_PCL730 config COMEDI_PCL812 tristate "Advantech PCL-812/813 and ADlink ACL-8112/8113/8113/8216" + depends on VIRT_TO_BUS default N ---help--- Enable support for Advantech PCL-812/PG, PCL-813/B, ADLink @@ -171,6 +173,7 @@ config COMEDI_PCL812 config COMEDI_PCL816 tristate "Advantech PCL-814 and PCL-816 ISA card support" + depends on VIRT_TO_BUS default N ---help--- Enable support for Advantech PCL-814 and PCL-816 ISA cards @@ -180,6 +183,7 @@ config COMEDI_PCL816 config COMEDI_PCL818 tristate "Advantech PCL-718 and PCL-818 ISA card support" + depends on VIRT_TO_BUS default N ---help--- Enable support for Advantech PCL-818 ISA cards @@ -269,6 +273,7 @@ config COMEDI_DAS800 config COMEDI_DAS1800 tristate "DAS1800 and compatible ISA card support" + depends on VIRT_TO_BUS select COMEDI_FC default N ---help--- @@ -340,6 +345,7 @@ config COMEDI_DT2817 config COMEDI_DT282X tristate "Data Translation DT2821 series and DT-EZ ISA card support" select COMEDI_FC + depends on VIRT_TO_BUS default N ---help--- Enable support for Data Translation DT2821 series including DT-EZ @@ -419,6 +425,7 @@ config COMEDI_ADQ12B config COMEDI_NI_AT_A2150 tristate "NI AT-A2150 ISA card support" depends on COMEDI_NI_COMMON + depends on VIRT_TO_BUS default N ---help--- Enable support for National Instruments AT-A2150 cards @@ -536,6 +543,7 @@ if COMEDI_PCI_DRIVERS && PCI config COMEDI_ADDI_APCI_035 tristate "ADDI-DATA APCI_035 support" + depends on VIRT_TO_BUS default N ---help--- Enable support for ADDI-DATA APCI_035 cards @@ -545,6 +553,7 @@ config COMEDI_ADDI_APCI_035 config COMEDI_ADDI_APCI_1032 tristate "ADDI-DATA APCI_1032 support" + depends on VIRT_TO_BUS default N ---help--- Enable support for ADDI-DATA APCI_1032 cards @@ -554,6 +563,7 @@ config COMEDI_ADDI_APCI_1032 config COMEDI_ADDI_APCI_1500 tristate "ADDI-DATA APCI_1500 support" + depends on VIRT_TO_BUS default N ---help--- Enable support for ADDI-DATA APCI_1500 cards @@ -563,6 +573,7 @@ config COMEDI_ADDI_APCI_1500 config COMEDI_ADDI_APCI_1516 tristate "ADDI-DATA APCI_1516 support" + depends on VIRT_TO_BUS default N ---help--- Enable support for ADDI-DATA APCI_1516 cards @@ -572,6 +583,7 @@ config COMEDI_ADDI_APCI_1516 config COMEDI_ADDI_APCI_1564 tristate "ADDI-DATA APCI_1564 support" + depends on VIRT_TO_BUS default N ---help--- Enable support for ADDI-DATA APCI_1564 cards @@ -581,6 +593,7 @@ config COMEDI_ADDI_APCI_1564 config COMEDI_ADDI_APCI_16XX tristate "ADDI-DATA APCI_16xx support" + depends on VIRT_TO_BUS default N ---help--- Enable support for ADDI-DATA APCI_16xx cards @@ -590,6 +603,7 @@ config COMEDI_ADDI_APCI_16XX config COMEDI_ADDI_APCI_2016 tristate "ADDI-DATA APCI_2016 support" + depends on VIRT_TO_BUS default N ---help--- Enable support for ADDI-DATA APCI_2016 cards @@ -599,6 +613,7 @@ config COMEDI_ADDI_APCI_2016 config COMEDI_ADDI_APCI_2032 tristate "ADDI-DATA APCI_2032 support" + depends on VIRT_TO_BUS default N ---help--- Enable support for ADDI-DATA APCI_2032 cards @@ -608,6 +623,7 @@ config COMEDI_ADDI_APCI_2032 config COMEDI_ADDI_APCI_2200 tristate "ADDI-DATA APCI_2200 support" + depends on VIRT_TO_BUS default N ---help--- Enable support for ADDI-DATA APCI_2200 cards @@ -617,6 +633,7 @@ config COMEDI_ADDI_APCI_2200 config COMEDI_ADDI_APCI_3001 tristate "ADDI-DATA APCI_3001 support" + depends on VIRT_TO_BUS select COMEDI_FC default N ---help--- @@ -627,6 +644,7 @@ config COMEDI_ADDI_APCI_3001 config COMEDI_ADDI_APCI_3120 tristate "ADDI-DATA APCI_3520 support" + depends on VIRT_TO_BUS select COMEDI_FC default N ---help--- @@ -637,6 +655,7 @@ config COMEDI_ADDI_APCI_3120 config COMEDI_ADDI_APCI_3501 tristate "ADDI-DATA APCI_3501 support" + depends on VIRT_TO_BUS default N ---help--- Enable support for ADDI-DATA APCI_3501 cards @@ -646,6 +665,7 @@ config COMEDI_ADDI_APCI_3501 config COMEDI_ADDI_APCI_3XXX tristate "ADDI-DATA APCI_3xxx support" + depends on VIRT_TO_BUS default N ---help--- Enable support for ADDI-DATA APCI_3xxx cards @@ -712,6 +732,7 @@ config COMEDI_ADL_PCI9111 config COMEDI_ADL_PCI9118 tristate "ADLink PCI-9118DG, PCI-9118HG, PCI-9118HR support" select COMEDI_FC + depends on VIRT_TO_BUS default N ---help--- Enable support for ADlink PCI-9118DG, PCI-9118HG, PCI-9118HR cards @@ -1287,6 +1308,7 @@ config COMEDI_NI_LABPC depends on COMEDI_MITE select COMEDI_8255 select COMEDI_FC + depends on VIRT_TO_BUS default N ---help--- Enable support for National Instruments Lab-PC and compatibles diff --git a/drivers/staging/gma500/psb_drv.c b/drivers/staging/gma500/psb_drv.c index 1c45c11..aa87b1b 100644 --- a/drivers/staging/gma500/psb_drv.c +++ b/drivers/staging/gma500/psb_drv.c @@ -542,6 +542,8 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) unsigned long irqflags; int ret = -ENOMEM; uint32_t tt_pages; + struct drm_connector *connector; + struct psb_intel_output *psb_intel_output; dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); if (dev_priv == NULL) @@ -663,7 +665,18 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) drm_kms_helper_poll_init(dev); } - ret = psb_backlight_init(dev); + /* Only add backlight support if we have LVDS output */ + list_for_each_entry(connector, &dev->mode_config.connector_list, + head) { + psb_intel_output = to_psb_intel_output(connector); + + switch (psb_intel_output->type) { + case INTEL_OUTPUT_LVDS: + ret = psb_backlight_init(dev); + break; + } + } + if (ret) return ret; #if 0 diff --git a/drivers/staging/gma500/psb_fb.c b/drivers/staging/gma500/psb_fb.c index 99c03a2..084c36b 100644 --- a/drivers/staging/gma500/psb_fb.c +++ b/drivers/staging/gma500/psb_fb.c @@ -441,6 +441,16 @@ static int psbfb_create(struct psb_fbdev *fbdev, info->screen_size = size; memset(info->screen_base, 0, size); + if (dev_priv->pg->stolen_size) { + info->apertures = alloc_apertures(1); + if (!info->apertures) { + ret = -ENOMEM; + goto out_err0; + } + info->apertures->ranges[0].base = dev->mode_config.fb_base; + info->apertures->ranges[0].size = dev_priv->pg->stolen_size; + } + drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); drm_fb_helper_fill_var(info, &fbdev->psb_fb_helper, sizes->fb_width, sizes->fb_height); diff --git a/drivers/staging/gma500/psb_intel_bios.c b/drivers/staging/gma500/psb_intel_bios.c index 48ac8ba..417965d 100644 --- a/drivers/staging/gma500/psb_intel_bios.c +++ b/drivers/staging/gma500/psb_intel_bios.c @@ -154,10 +154,15 @@ static void parse_lfp_panel_data(struct drm_psb_private *dev_priv, fill_detail_timing_data(panel_fixed_mode, dvo_timing); - dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode; - - DRM_DEBUG("Found panel mode in BIOS VBT tables:\n"); - drm_mode_debug_printmodeline(panel_fixed_mode); + if (panel_fixed_mode->htotal > 0 && panel_fixed_mode->vtotal > 0) { + dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode; + DRM_DEBUG("Found panel mode in BIOS VBT tables:\n"); + drm_mode_debug_printmodeline(panel_fixed_mode); + } else { + DRM_DEBUG("Ignoring bogus LVDS VBT mode.\n"); + dev_priv->lvds_vbt = 0; + kfree(panel_fixed_mode); + } return; } diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index f96d5b5..d329635 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -4,7 +4,7 @@ menuconfig IIO tristate "Industrial I/O support" - depends on !S390 + depends on GENERIC_HARDIRQS help The industrial I/O subsystem provides a unified framework for drivers for many different types of embedded sensors using a diff --git a/drivers/staging/iio/accel/adis16201.h b/drivers/staging/iio/accel/adis16201.h index 0b9b854..4cc1a5b 100644 --- a/drivers/staging/iio/accel/adis16201.h +++ b/drivers/staging/iio/accel/adis16201.h @@ -81,7 +81,6 @@ struct adis16201_state { int adis16201_set_irq(struct iio_dev *indio_dev, bool enable); -#ifdef CONFIG_IIO_RING_BUFFER enum adis16201_scan { ADIS16201_SCAN_SUPPLY, ADIS16201_SCAN_ACC_X, @@ -92,6 +91,7 @@ enum adis16201_scan { ADIS16201_SCAN_INCLI_Y, }; +#ifdef CONFIG_IIO_RING_BUFFER void adis16201_remove_trigger(struct iio_dev *indio_dev); int adis16201_probe_trigger(struct iio_dev *indio_dev); diff --git a/drivers/staging/iio/accel/adis16203.h b/drivers/staging/iio/accel/adis16203.h index 8bb8ce5..175e21b 100644 --- a/drivers/staging/iio/accel/adis16203.h +++ b/drivers/staging/iio/accel/adis16203.h @@ -76,7 +76,6 @@ struct adis16203_state { int adis16203_set_irq(struct iio_dev *indio_dev, bool enable); -#ifdef CONFIG_IIO_RING_BUFFER enum adis16203_scan { ADIS16203_SCAN_SUPPLY, ADIS16203_SCAN_AUX_ADC, @@ -85,6 +84,7 @@ enum adis16203_scan { ADIS16203_SCAN_INCLI_Y, }; +#ifdef CONFIG_IIO_RING_BUFFER void adis16203_remove_trigger(struct iio_dev *indio_dev); int adis16203_probe_trigger(struct iio_dev *indio_dev); diff --git a/drivers/staging/iio/accel/adis16204.h b/drivers/staging/iio/accel/adis16204.h index 5310a42..1690c0d 100644 --- a/drivers/staging/iio/accel/adis16204.h +++ b/drivers/staging/iio/accel/adis16204.h @@ -84,7 +84,6 @@ struct adis16204_state { int adis16204_set_irq(struct iio_dev *indio_dev, bool enable); -#ifdef CONFIG_IIO_RING_BUFFER enum adis16204_scan { ADIS16204_SCAN_SUPPLY, ADIS16204_SCAN_ACC_X, @@ -93,6 +92,7 @@ enum adis16204_scan { ADIS16204_SCAN_TEMP, }; +#ifdef CONFIG_IIO_RING_BUFFER void adis16204_remove_trigger(struct iio_dev *indio_dev); int adis16204_probe_trigger(struct iio_dev *indio_dev); diff --git a/drivers/staging/iio/accel/adis16209.h b/drivers/staging/iio/accel/adis16209.h index 58d08db..3153cbe 100644 --- a/drivers/staging/iio/accel/adis16209.h +++ b/drivers/staging/iio/accel/adis16209.h @@ -121,8 +121,6 @@ struct adis16209_state { int adis16209_set_irq(struct iio_dev *indio_dev, bool enable); -#ifdef CONFIG_IIO_RING_BUFFER - #define ADIS16209_SCAN_SUPPLY 0 #define ADIS16209_SCAN_ACC_X 1 #define ADIS16209_SCAN_ACC_Y 2 @@ -132,6 +130,8 @@ int adis16209_set_irq(struct iio_dev *indio_dev, bool enable); #define ADIS16209_SCAN_INCLI_Y 6 #define ADIS16209_SCAN_ROT 7 +#ifdef CONFIG_IIO_RING_BUFFER + void adis16209_remove_trigger(struct iio_dev *indio_dev); int adis16209_probe_trigger(struct iio_dev *indio_dev); diff --git a/drivers/staging/iio/dac/max517.c b/drivers/staging/iio/dac/max517.c index 881768d..2fe34d2 100644 --- a/drivers/staging/iio/dac/max517.c +++ b/drivers/staging/iio/dac/max517.c @@ -195,7 +195,7 @@ static const struct iio_info max517_info = { }; static const struct iio_info max518_info = { - .attrs = &max517_attribute_group, + .attrs = &max518_attribute_group, .driver_module = THIS_MODULE, }; diff --git a/drivers/staging/iio/gyro/adis16260.h b/drivers/staging/iio/gyro/adis16260.h index 702dc98..24bf70e 100644 --- a/drivers/staging/iio/gyro/adis16260.h +++ b/drivers/staging/iio/gyro/adis16260.h @@ -104,7 +104,6 @@ struct adis16260_state { int adis16260_set_irq(struct iio_dev *indio_dev, bool enable); -#ifdef CONFIG_IIO_RING_BUFFER /* At the moment triggers are only used for ring buffer * filling. This may change! */ @@ -115,6 +114,7 @@ int adis16260_set_irq(struct iio_dev *indio_dev, bool enable); #define ADIS16260_SCAN_TEMP 3 #define ADIS16260_SCAN_ANGL 4 +#ifdef CONFIG_IIO_RING_BUFFER void adis16260_remove_trigger(struct iio_dev *indio_dev); int adis16260_probe_trigger(struct iio_dev *indio_dev); diff --git a/drivers/staging/iio/imu/adis16400.h b/drivers/staging/iio/imu/adis16400.h index db184d1..e87715b9 100644 --- a/drivers/staging/iio/imu/adis16400.h +++ b/drivers/staging/iio/imu/adis16400.h @@ -158,7 +158,6 @@ struct adis16400_state { int adis16400_set_irq(struct iio_dev *indio_dev, bool enable); -#ifdef CONFIG_IIO_RING_BUFFER /* At the moment triggers are only used for ring buffer * filling. This may change! */ @@ -182,6 +181,7 @@ int adis16400_set_irq(struct iio_dev *indio_dev, bool enable); #define ADIS16300_SCAN_INCLI_X 12 #define ADIS16300_SCAN_INCLI_Y 13 +#ifdef CONFIG_IIO_RING_BUFFER void adis16400_remove_trigger(struct iio_dev *indio_dev); int adis16400_probe_trigger(struct iio_dev *indio_dev); diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c index 2589a7e..3612373 100644 --- a/drivers/staging/iio/imu/adis16400_ring.c +++ b/drivers/staging/iio/imu/adis16400_ring.c @@ -137,13 +137,13 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p) if (st->variant->flags & ADIS16400_NO_BURST) { ret = adis16350_spi_read_all(&indio_dev->dev, st->rx); if (ret < 0) - return ret; + goto err; for (; i < ring->scan_count; i++) data[i] = *(s16 *)(st->rx + i*2); } else { ret = adis16400_spi_read_burst(&indio_dev->dev, st->rx); if (ret < 0) - return ret; + goto err; for (; i < indio_dev->ring->scan_count; i++) { j = __ffs(mask); mask &= ~(1 << j); @@ -158,9 +158,13 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p) ring->access->store_to(indio_dev->ring, (u8 *) data, pf->timestamp); iio_trigger_notify_done(indio_dev->trig); - kfree(data); + kfree(data); return IRQ_HANDLED; + +err: + kfree(data); + return ret; } void adis16400_unconfigure_ring(struct iio_dev *indio_dev) diff --git a/drivers/staging/iio/industrialio-trigger.c b/drivers/staging/iio/industrialio-trigger.c index 6159023..d504aa2 100644 --- a/drivers/staging/iio/industrialio-trigger.c +++ b/drivers/staging/iio/industrialio-trigger.c @@ -294,6 +294,7 @@ struct iio_poll_func pf->h = h; pf->thread = thread; pf->type = type; + pf->private_data = private; return pf; } diff --git a/drivers/staging/mei/init.c b/drivers/staging/mei/init.c index 2818851..685fcf6 100644 --- a/drivers/staging/mei/init.c +++ b/drivers/staging/mei/init.c @@ -189,7 +189,7 @@ int mei_hw_init(struct mei_device *dev) mutex_lock(&dev->device_lock); } - if (!err && !dev->recvd_msg) { + if (err <= 0 && !dev->recvd_msg) { dev->mei_state = MEI_DISABLED; dev_dbg(&dev->pdev->dev, "wait_event_interruptible_timeout failed" @@ -205,10 +205,10 @@ int mei_hw_init(struct mei_device *dev) "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", dev->host_hw_state, dev->me_hw_state); - if (!(dev->host_hw_state & H_RDY) != H_RDY) + if (!(dev->host_hw_state & H_RDY)) dev_dbg(&dev->pdev->dev, "host turn off H_RDY.\n"); - if (!(dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA) + if (!(dev->me_hw_state & ME_RDY_HRA)) dev_dbg(&dev->pdev->dev, "ME turn off ME_RDY.\n"); printk(KERN_ERR "mei: link layer initialization failed.\n"); diff --git a/drivers/staging/mei/wd.c b/drivers/staging/mei/wd.c index 2564b03..fff53d0 100644 --- a/drivers/staging/mei/wd.c +++ b/drivers/staging/mei/wd.c @@ -169,10 +169,15 @@ int mei_wd_stop(struct mei_device *dev, bool preserve) ret = wait_event_interruptible_timeout(dev->wait_stop_wd, dev->wd_stopped, 10 * HZ); mutex_lock(&dev->device_lock); - if (!dev->wd_stopped) - dev_dbg(&dev->pdev->dev, "stop wd failed to complete.\n"); - else - dev_dbg(&dev->pdev->dev, "stop wd complete.\n"); + if (dev->wd_stopped) { + dev_dbg(&dev->pdev->dev, "stop wd complete ret=%d.\n", ret); + ret = 0; + } else { + if (!ret) + ret = -ETIMEDOUT; + dev_warn(&dev->pdev->dev, + "stop wd failed to complete ret=%d.\n", ret); + } if (preserve) dev->wd_timeout = wd_timeout; diff --git a/drivers/staging/olpc_dcon/Kconfig b/drivers/staging/olpc_dcon/Kconfig index b053067..fe40e0b 100644 --- a/drivers/staging/olpc_dcon/Kconfig +++ b/drivers/staging/olpc_dcon/Kconfig @@ -2,6 +2,7 @@ config FB_OLPC_DCON tristate "One Laptop Per Child Display CONtroller support" depends on OLPC && FB select I2C + select BACKLIGHT_CLASS_DEVICE ---help--- Add support for the OLPC XO DCON controller. This controller is only available on OLPC platforms. Unless you have one of these diff --git a/drivers/staging/rts_pstor/sd.c b/drivers/staging/rts_pstor/sd.c index bddb031..cdae497 100644 --- a/drivers/staging/rts_pstor/sd.c +++ b/drivers/staging/rts_pstor/sd.c @@ -2328,7 +2328,7 @@ Switch_Fail: retval = sd_send_cmd_get_rsp(chip, IO_SEND_OP_COND, 0, SD_RSP_TYPE_R4, rsp, 5); if (retval == STATUS_SUCCESS) { - int func_num = (rsp[1] >> 4) && 0x07; + int func_num = (rsp[1] >> 4) & 0x07; if (func_num) { RTSX_DEBUGP("SD_IO card (Function number: %d)!\n", func_num); chip->sd_io = 1; diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c index 6e99ec8..8cbea42 100644 --- a/drivers/staging/usbip/stub_dev.c +++ b/drivers/staging/usbip/stub_dev.c @@ -26,6 +26,8 @@ static int stub_probe(struct usb_interface *interface, const struct usb_device_id *id); static void stub_disconnect(struct usb_interface *interface); +static int stub_pre_reset(struct usb_interface *interface); +static int stub_post_reset(struct usb_interface *interface); /* * Define device IDs here if you want to explicitly limit exportable devices. @@ -59,6 +61,8 @@ struct usb_driver stub_driver = { .probe = stub_probe, .disconnect = stub_disconnect, .id_table = stub_table, + .pre_reset = stub_pre_reset, + .post_reset = stub_post_reset, }; /* @@ -541,3 +545,20 @@ static void stub_disconnect(struct usb_interface *interface) del_match_busid((char *)udev_busid); } } + +/* + * Presence of pre_reset and post_reset prevents the driver from being unbound + * when the device is being reset + */ + +int stub_pre_reset(struct usb_interface *interface) +{ + dev_dbg(&interface->dev, "pre_reset\n"); + return 0; +} + +int stub_post_reset(struct usb_interface *interface) +{ + dev_dbg(&interface->dev, "post_reset\n"); + return 0; +} diff --git a/drivers/staging/usbip/stub_rx.c b/drivers/staging/usbip/stub_rx.c index a5c1fa1..bc57844 100644 --- a/drivers/staging/usbip/stub_rx.c +++ b/drivers/staging/usbip/stub_rx.c @@ -175,16 +175,18 @@ static int tweak_reset_device_cmd(struct urb *urb) dev_info(&urb->dev->dev, "usb_queue_reset_device\n"); /* - * usb_lock_device_for_reset caused a deadlock: it causes the driver - * to unbind. In the shutdown the rx thread is signalled to shut down - * but this thread is pending in the usb_lock_device_for_reset. - * - * Instead queue the reset. - * - * Unfortunatly an existing usbip connection will be dropped due to - * driver unbinding. + * With the implementation of pre_reset and post_reset the driver no + * longer unbinds. This allows the use of synchronous reset. */ - usb_queue_reset_device(sdev->interface); + + if (usb_lock_device_for_reset(sdev->udev, sdev->interface)<0) + { + dev_err(&urb->dev->dev, "could not obtain lock to reset device\n"); + return 0; + } + usb_reset_device(sdev->udev); + usb_unlock_device(sdev->udev); + return 0; } diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index dee2a2c..70c2e7f 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -386,7 +386,7 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc) */ se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd, (void *)tl_tmr, TMR_LUN_RESET); - if (!se_cmd->se_tmr_req) + if (IS_ERR(se_cmd->se_tmr_req)) goto release; /* * Locate the underlying TCM struct se_lun from sc->device->lun @@ -1017,6 +1017,7 @@ static int tcm_loop_make_nexus( struct se_portal_group *se_tpg; struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; struct tcm_loop_nexus *tl_nexus; + int ret = -ENOMEM; if (tl_tpg->tl_hba->tl_nexus) { printk(KERN_INFO "tl_tpg->tl_hba->tl_nexus already exists\n"); @@ -1033,8 +1034,10 @@ static int tcm_loop_make_nexus( * Initialize the struct se_session pointer */ tl_nexus->se_sess = transport_init_session(); - if (!tl_nexus->se_sess) + if (IS_ERR(tl_nexus->se_sess)) { + ret = PTR_ERR(tl_nexus->se_sess); goto out; + } /* * Since we are running in 'demo mode' this call with generate a * struct se_node_acl for the tcm_loop struct se_portal_group with the SCSI @@ -1060,7 +1063,7 @@ static int tcm_loop_make_nexus( out: kfree(tl_nexus); - return -ENOMEM; + return ret; } static int tcm_loop_drop_nexus( @@ -1140,7 +1143,7 @@ static ssize_t tcm_loop_tpg_store_nexus( * the fabric protocol_id set in tcm_loop_make_scsi_hba(), and call * tcm_loop_make_nexus() */ - if (strlen(page) > TL_WWN_ADDR_LEN) { + if (strlen(page) >= TL_WWN_ADDR_LEN) { printk(KERN_ERR "Emulated NAA Sas Address: %s, exceeds" " max: %d\n", page, TL_WWN_ADDR_LEN); return -EINVAL; @@ -1321,7 +1324,7 @@ struct se_wwn *tcm_loop_make_scsi_hba( return ERR_PTR(-EINVAL); check_len: - if (strlen(name) > TL_WWN_ADDR_LEN) { + if (strlen(name) >= TL_WWN_ADDR_LEN) { printk(KERN_ERR "Emulated NAA %s Address: %s, exceeds" " max: %d\n", name, tcm_loop_dump_proto_id(tl_hba), TL_WWN_ADDR_LEN); diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index ee6fad9..25c1f49 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -304,7 +304,7 @@ struct target_fabric_configfs *target_fabric_configfs_init( printk(KERN_ERR "Unable to locate passed fabric name\n"); return NULL; } - if (strlen(name) > TARGET_FABRIC_NAME_SIZE) { + if (strlen(name) >= TARGET_FABRIC_NAME_SIZE) { printk(KERN_ERR "Passed name: %s exceeds TARGET_FABRIC" "_NAME_SIZE\n", name); return NULL; @@ -312,7 +312,7 @@ struct target_fabric_configfs *target_fabric_configfs_init( tf = kzalloc(sizeof(struct target_fabric_configfs), GFP_KERNEL); if (!(tf)) - return ERR_PTR(-ENOMEM); + return NULL; INIT_LIST_HEAD(&tf->tf_list); atomic_set(&tf->tf_access_cnt, 0); @@ -851,7 +851,7 @@ static ssize_t target_core_dev_wwn_store_attr_vpd_unit_serial( return -EOPNOTSUPP; } - if ((strlen(page) + 1) > INQUIRY_VPD_SERIAL_LEN) { + if (strlen(page) >= INQUIRY_VPD_SERIAL_LEN) { printk(KERN_ERR "Emulated VPD Unit Serial exceeds" " INQUIRY_VPD_SERIAL_LEN: %d\n", INQUIRY_VPD_SERIAL_LEN); return -EOVERFLOW; @@ -917,7 +917,7 @@ static ssize_t target_core_dev_wwn_show_attr_vpd_protocol_identifier( transport_dump_vpd_proto_id(vpd, buf, VPD_TMP_BUF_SIZE); - if ((len + strlen(buf) > PAGE_SIZE)) + if ((len + strlen(buf) >= PAGE_SIZE)) break; len += sprintf(page+len, "%s", buf); @@ -962,19 +962,19 @@ static ssize_t target_core_dev_wwn_show_attr_##_name( \ \ memset(buf, 0, VPD_TMP_BUF_SIZE); \ transport_dump_vpd_assoc(vpd, buf, VPD_TMP_BUF_SIZE); \ - if ((len + strlen(buf) > PAGE_SIZE)) \ + if ((len + strlen(buf) >= PAGE_SIZE)) \ break; \ len += sprintf(page+len, "%s", buf); \ \ memset(buf, 0, VPD_TMP_BUF_SIZE); \ transport_dump_vpd_ident_type(vpd, buf, VPD_TMP_BUF_SIZE); \ - if ((len + strlen(buf) > PAGE_SIZE)) \ + if ((len + strlen(buf) >= PAGE_SIZE)) \ break; \ len += sprintf(page+len, "%s", buf); \ \ memset(buf, 0, VPD_TMP_BUF_SIZE); \ transport_dump_vpd_ident(vpd, buf, VPD_TMP_BUF_SIZE); \ - if ((len + strlen(buf) > PAGE_SIZE)) \ + if ((len + strlen(buf) >= PAGE_SIZE)) \ break; \ len += sprintf(page+len, "%s", buf); \ } \ @@ -1299,7 +1299,7 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts( &i_buf[0] : "", pr_reg->pr_res_key, pr_reg->pr_res_generation); - if ((len + strlen(buf) > PAGE_SIZE)) + if ((len + strlen(buf) >= PAGE_SIZE)) break; len += sprintf(page+len, "%s", buf); @@ -1496,7 +1496,7 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( ret = -ENOMEM; goto out; } - if (strlen(i_port) > PR_APTPL_MAX_IPORT_LEN) { + if (strlen(i_port) >= PR_APTPL_MAX_IPORT_LEN) { printk(KERN_ERR "APTPL metadata initiator_node=" " exceeds PR_APTPL_MAX_IPORT_LEN: %d\n", PR_APTPL_MAX_IPORT_LEN); @@ -1510,7 +1510,7 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( ret = -ENOMEM; goto out; } - if (strlen(isid) > PR_REG_ISID_LEN) { + if (strlen(isid) >= PR_REG_ISID_LEN) { printk(KERN_ERR "APTPL metadata initiator_isid" "= exceeds PR_REG_ISID_LEN: %d\n", PR_REG_ISID_LEN); @@ -1571,7 +1571,7 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( ret = -ENOMEM; goto out; } - if (strlen(t_port) > PR_APTPL_MAX_TPORT_LEN) { + if (strlen(t_port) >= PR_APTPL_MAX_TPORT_LEN) { printk(KERN_ERR "APTPL metadata target_node=" " exceeds PR_APTPL_MAX_TPORT_LEN: %d\n", PR_APTPL_MAX_TPORT_LEN); @@ -3052,7 +3052,7 @@ static struct config_group *target_core_call_addhbatotarget( int ret; memset(buf, 0, TARGET_CORE_NAME_MAX_LEN); - if (strlen(name) > TARGET_CORE_NAME_MAX_LEN) { + if (strlen(name) >= TARGET_CORE_NAME_MAX_LEN) { printk(KERN_ERR "Passed *name strlen(): %d exceeds" " TARGET_CORE_NAME_MAX_LEN: %d\n", (int)strlen(name), TARGET_CORE_NAME_MAX_LEN); diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 8407f9c..ba698ea 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -192,7 +192,7 @@ int transport_get_lun_for_tmr( &SE_NODE_ACL(se_sess)->device_list[unpacked_lun]; if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) { se_lun = se_cmd->se_lun = se_tmr->tmr_lun = deve->se_lun; - dev = se_tmr->tmr_dev = se_lun->lun_se_dev; + dev = se_lun->lun_se_dev; se_cmd->pr_res_key = deve->pr_res_key; se_cmd->orig_fe_lun = unpacked_lun; se_cmd->se_orig_obj_ptr = SE_LUN(se_cmd)->lun_se_dev; @@ -216,6 +216,7 @@ int transport_get_lun_for_tmr( se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; return -1; } + se_tmr->tmr_dev = dev; spin_lock(&dev->se_tmr_lock); list_add_tail(&se_tmr->tmr_list, &dev->dev_tmr_list); @@ -1430,7 +1431,7 @@ struct se_lun_acl *core_dev_init_initiator_node_lun_acl( struct se_lun_acl *lacl; struct se_node_acl *nacl; - if (strlen(initiatorname) > TRANSPORT_IQN_LEN) { + if (strlen(initiatorname) >= TRANSPORT_IQN_LEN) { printk(KERN_ERR "%s InitiatorName exceeds maximum size.\n", TPG_TFO(tpg)->get_fabric_name()); *ret = -EOVERFLOW; diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index a79f518..b662db3 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -1916,7 +1916,7 @@ static int __core_scsi3_update_aptpl_buf( pr_reg->pr_res_mapped_lun); } - if ((len + strlen(tmp) > pr_aptpl_buf_len)) { + if ((len + strlen(tmp) >= pr_aptpl_buf_len)) { printk(KERN_ERR "Unable to update renaming" " APTPL metadata\n"); spin_unlock(&T10_RES(su_dev)->registration_lock); @@ -1934,7 +1934,7 @@ static int __core_scsi3_update_aptpl_buf( TPG_TFO(tpg)->tpg_get_tag(tpg), lun->lun_sep->sep_rtpi, lun->unpacked_lun, reg_count); - if ((len + strlen(tmp) > pr_aptpl_buf_len)) { + if ((len + strlen(tmp) >= pr_aptpl_buf_len)) { printk(KERN_ERR "Unable to update renaming" " APTPL metadata\n"); spin_unlock(&T10_RES(su_dev)->registration_lock); @@ -1986,7 +1986,7 @@ static int __core_scsi3_write_aptpl_to_file( memset(iov, 0, sizeof(struct iovec)); memset(path, 0, 512); - if (strlen(&wwn->unit_serial[0]) > 512) { + if (strlen(&wwn->unit_serial[0]) >= 512) { printk(KERN_ERR "WWN value for struct se_device does not fit" " into path buffer\n"); return -1; diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 59b8b9c..179063d 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -75,10 +75,16 @@ void core_tmr_release_req( { struct se_device *dev = tmr->tmr_dev; + if (!dev) { + kmem_cache_free(se_tmr_req_cache, tmr); + return; + } + spin_lock(&dev->se_tmr_lock); list_del(&tmr->tmr_list); - kmem_cache_free(se_tmr_req_cache, tmr); spin_unlock(&dev->se_tmr_lock); + + kmem_cache_free(se_tmr_req_cache, tmr); } static void core_tmr_handle_tas_abort( diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 4dafeb8..4b9b716 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -536,13 +536,13 @@ EXPORT_SYMBOL(transport_register_session); void transport_deregister_session_configfs(struct se_session *se_sess) { struct se_node_acl *se_nacl; - + unsigned long flags; /* * Used by struct se_node_acl's under ConfigFS to locate active struct se_session */ se_nacl = se_sess->se_node_acl; if ((se_nacl)) { - spin_lock_irq(&se_nacl->nacl_sess_lock); + spin_lock_irqsave(&se_nacl->nacl_sess_lock, flags); list_del(&se_sess->sess_acl_list); /* * If the session list is empty, then clear the pointer. @@ -556,7 +556,7 @@ void transport_deregister_session_configfs(struct se_session *se_sess) se_nacl->acl_sess_list.prev, struct se_session, sess_acl_list); } - spin_unlock_irq(&se_nacl->nacl_sess_lock); + spin_unlock_irqrestore(&se_nacl->nacl_sess_lock, flags); } } EXPORT_SYMBOL(transport_deregister_session_configfs); diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h index defff32..7b82f1b 100644 --- a/drivers/target/tcm_fc/tcm_fc.h +++ b/drivers/target/tcm_fc/tcm_fc.h @@ -144,7 +144,7 @@ enum ft_cmd_state { */ struct ft_cmd { enum ft_cmd_state state; - u16 lun; /* LUN from request */ + u32 lun; /* LUN from request */ struct ft_sess *sess; /* session held for cmd */ struct fc_seq *seq; /* sequence in exchange mgr */ struct se_cmd se_cmd; /* Local TCM I/O descriptor */ diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index c056a11..b2a1067 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -94,29 +94,6 @@ void ft_dump_cmd(struct ft_cmd *cmd, const char *caller) 16, 4, cmd->cdb, MAX_COMMAND_SIZE, 0); } -/* - * Get LUN from CDB. - */ -static int ft_get_lun_for_cmd(struct ft_cmd *cmd, u8 *lunp) -{ - u64 lun; - - lun = lunp[1]; - switch (lunp[0] >> 6) { - case 0: - break; - case 1: - lun |= (lunp[0] & 0x3f) << 8; - break; - default: - return -1; - } - if (lun >= TRANSPORT_MAX_LUNS_PER_TPG) - return -1; - cmd->lun = lun; - return transport_get_lun_for_cmd(&cmd->se_cmd, NULL, lun); -} - static void ft_queue_cmd(struct ft_sess *sess, struct ft_cmd *cmd) { struct se_queue_obj *qobj; @@ -418,6 +395,7 @@ static void ft_send_tm(struct ft_cmd *cmd) { struct se_tmr_req *tmr; struct fcp_cmnd *fcp; + struct ft_sess *sess; u8 tm_func; fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp)); @@ -425,13 +403,6 @@ static void ft_send_tm(struct ft_cmd *cmd) switch (fcp->fc_tm_flags) { case FCP_TMF_LUN_RESET: tm_func = TMR_LUN_RESET; - if (ft_get_lun_for_cmd(cmd, fcp->fc_lun) < 0) { - ft_dump_cmd(cmd, __func__); - transport_send_check_condition_and_sense(&cmd->se_cmd, - cmd->se_cmd.scsi_sense_reason, 0); - ft_sess_put(cmd->sess); - return; - } break; case FCP_TMF_TGT_RESET: tm_func = TMR_TARGET_WARM_RESET; @@ -463,6 +434,36 @@ static void ft_send_tm(struct ft_cmd *cmd) return; } cmd->se_cmd.se_tmr_req = tmr; + + switch (fcp->fc_tm_flags) { + case FCP_TMF_LUN_RESET: + cmd->lun = scsilun_to_int((struct scsi_lun *)fcp->fc_lun); + if (transport_get_lun_for_tmr(&cmd->se_cmd, cmd->lun) < 0) { + /* + * Make sure to clean up newly allocated TMR request + * since "unable to handle TMR request because failed + * to get to LUN" + */ + FT_TM_DBG("Failed to get LUN for TMR func %d, " + "se_cmd %p, unpacked_lun %d\n", + tm_func, &cmd->se_cmd, cmd->lun); + ft_dump_cmd(cmd, __func__); + sess = cmd->sess; + transport_send_check_condition_and_sense(&cmd->se_cmd, + cmd->se_cmd.scsi_sense_reason, 0); + transport_generic_free_cmd(&cmd->se_cmd, 0, 1, 0); + ft_sess_put(sess); + return; + } + break; + case FCP_TMF_TGT_RESET: + case FCP_TMF_CLR_TASK_SET: + case FCP_TMF_ABT_TASK_SET: + case FCP_TMF_CLR_ACA: + break; + default: + return; + } transport_generic_handle_tmr(&cmd->se_cmd); } @@ -635,7 +636,8 @@ static void ft_send_cmd(struct ft_cmd *cmd) fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd); - ret = ft_get_lun_for_cmd(cmd, fcp->fc_lun); + cmd->lun = scsilun_to_int((struct scsi_lun *)fcp->fc_lun); + ret = transport_get_lun_for_cmd(&cmd->se_cmd, NULL, cmd->lun); if (ret < 0) { ft_dump_cmd(cmd, __func__); transport_send_check_condition_and_sense(&cmd->se_cmd, diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c index 4c3c0ef..8c4a240 100644 --- a/drivers/target/tcm_fc/tfc_io.c +++ b/drivers/target/tcm_fc/tfc_io.c @@ -203,7 +203,7 @@ int ft_queue_data_in(struct se_cmd *se_cmd) /* XXX For now, initiator will retry */ if (printk_ratelimit()) printk(KERN_ERR "%s: Failed to send frame %p, " - "xid <0x%x>, remaining <0x%x>, " + "xid <0x%x>, remaining %zu, " "lso_max <0x%x>\n", __func__, fp, ep->xid, remaining, lport->lso_max); diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index a3bd57f..7491e21 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -229,7 +229,7 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id, return NULL; sess->se_sess = transport_init_session(); - if (!sess->se_sess) { + if (IS_ERR(sess->se_sess)) { kfree(sess); return NULL; } @@ -332,7 +332,7 @@ void ft_sess_close(struct se_session *se_sess) lport = sess->tport->lport; port_id = sess->port_id; if (port_id == -1) { - mutex_lock(&ft_lport_lock); + mutex_unlock(&ft_lport_lock); return; } FT_SESS_DBG("port_id %x\n", port_id); diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 09e8c7d..19b4ae0 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -875,7 +875,8 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm, *dp++ = last << 7 | first << 6 | 1; /* EA */ len--; } - memcpy(dp, skb_pull(dlci->skb, len), len); + memcpy(dp, dlci->skb->data, len); + skb_pull(dlci->skb, len); __gsm_data_queue(dlci, msg); if (last) dlci->skb = NULL; @@ -984,10 +985,22 @@ static void gsm_control_reply(struct gsm_mux *gsm, int cmd, u8 *data, */ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci, - u32 modem) + u32 modem, int clen) { int mlines = 0; - u8 brk = modem >> 6; + u8 brk = 0; + + /* The modem status command can either contain one octet (v.24 signals) + or two octets (v.24 signals + break signals). The length field will + either be 2 or 3 respectively. This is specified in section + 5.4.6.3.7 of the 27.010 mux spec. */ + + if (clen == 2) + modem = modem & 0x7f; + else { + brk = modem & 0x7f; + modem = (modem >> 7) & 0x7f; + }; /* Flow control/ready to communicate */ if (modem & MDM_FC) { @@ -1061,7 +1074,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen) return; } tty = tty_port_tty_get(&dlci->port); - gsm_process_modem(tty, dlci, modem); + gsm_process_modem(tty, dlci, modem, clen); if (tty) { tty_wakeup(tty); tty_kref_put(tty); @@ -1482,12 +1495,13 @@ static void gsm_dlci_begin_close(struct gsm_dlci *dlci) * open we shovel the bits down it, if not we drop them. */ -static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int len) +static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int clen) { /* krefs .. */ struct tty_port *port = &dlci->port; struct tty_struct *tty = tty_port_tty_get(port); unsigned int modem = 0; + int len = clen; if (debug & 16) pr_debug("%d bytes for tty %p\n", len, tty); @@ -1507,7 +1521,7 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int len) if (len == 0) return; } - gsm_process_modem(tty, dlci, modem); + gsm_process_modem(tty, dlci, modem, clen); /* Line state will go via DLCI 0 controls only */ case 1: default: diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 0ad3288..c3954fb 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1815,6 +1815,7 @@ do_it_again: /* FIXME: does n_tty_set_room need locking ? */ n_tty_set_room(tty); timeout = schedule_timeout(timeout); + BUG_ON(!tty->read_buf); continue; } __set_current_state(TASK_RUNNING); diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c index b40f7b9..b4129f5 100644 --- a/drivers/tty/serial/8250.c +++ b/drivers/tty/serial/8250.c @@ -3318,6 +3318,7 @@ void serial8250_unregister_port(int line) uart->port.flags &= ~UPF_BOOT_AUTOCONF; uart->port.type = PORT_UNKNOWN; uart->port.dev = &serial8250_isa_devs->dev; + uart->capabilities = uart_config[uart->port.type].flags; uart_add_one_port(&serial8250_reg, &uart->port); } else { uart->port.dev = NULL; diff --git a/drivers/tty/serial/8250_pci.c b/drivers/tty/serial/8250_pci.c index 4b4968a..f41b425 100644 --- a/drivers/tty/serial/8250_pci.c +++ b/drivers/tty/serial/8250_pci.c @@ -973,7 +973,7 @@ ce4100_serial_setup(struct serial_private *priv, static int pci_omegapci_setup(struct serial_private *priv, - struct pciserial_board *board, + const struct pciserial_board *board, struct uart_port *port, int idx) { return setup_port(priv, port, 2, idx * 8, 0); @@ -994,6 +994,15 @@ static int skip_tx_en_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } +static int pci_eg20t_init(struct pci_dev *dev) +{ +#if defined(CONFIG_SERIAL_PCH_UART) || defined(CONFIG_SERIAL_PCH_UART_MODULE) + return -ENODEV; +#else + return 0; +#endif +} + /* This should be in linux/pci_ids.h */ #define PCI_VENDOR_ID_SBSMODULARIO 0x124B #define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B @@ -1446,6 +1455,56 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .init = pci_oxsemi_tornado_init, .setup = pci_default_setup, }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x8811, + .init = pci_eg20t_init, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x8812, + .init = pci_eg20t_init, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x8813, + .init = pci_eg20t_init, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x8814, + .init = pci_eg20t_init, + }, + { + .vendor = 0x10DB, + .device = 0x8027, + .init = pci_eg20t_init, + }, + { + .vendor = 0x10DB, + .device = 0x8028, + .init = pci_eg20t_init, + }, + { + .vendor = 0x10DB, + .device = 0x8029, + .init = pci_eg20t_init, + }, + { + .vendor = 0x10DB, + .device = 0x800C, + .init = pci_eg20t_init, + }, + { + .vendor = 0x10DB, + .device = 0x800D, + .init = pci_eg20t_init, + }, + { + .vendor = 0x10DB, + .device = 0x800D, + .init = pci_eg20t_init, + }, /* * Cronyx Omega PCI (PLX-chip based) */ diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 8dc0541..f5f6831 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -50,6 +50,7 @@ #include <linux/dmaengine.h> #include <linux/dma-mapping.h> #include <linux/scatterlist.h> +#include <linux/delay.h> #include <asm/io.h> #include <asm/sizes.h> @@ -65,6 +66,30 @@ #define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) #define UART_DUMMY_DR_RX (1 << 16) + +#define UART_WA_SAVE_NR 14 + +static void pl011_lockup_wa(unsigned long data); +static const u32 uart_wa_reg[UART_WA_SAVE_NR] = { + ST_UART011_DMAWM, + ST_UART011_TIMEOUT, + ST_UART011_LCRH_RX, + UART011_IBRD, + UART011_FBRD, + ST_UART011_LCRH_TX, + UART011_IFLS, + ST_UART011_XFCR, + ST_UART011_XON1, + ST_UART011_XON2, + ST_UART011_XOFF1, + ST_UART011_XOFF2, + UART011_CR, + UART011_IMSC +}; + +static u32 uart_wa_regdata[UART_WA_SAVE_NR]; +static DECLARE_TASKLET(pl011_lockup_tlet, pl011_lockup_wa, 0); + /* There is by now at least one vendor with differing details, so handle it */ struct vendor_data { unsigned int ifls; @@ -72,6 +97,7 @@ struct vendor_data { unsigned int lcrh_tx; unsigned int lcrh_rx; bool oversampling; + bool interrupt_may_hang; /* vendor-specific */ bool dma_threshold; }; @@ -90,9 +116,12 @@ static struct vendor_data vendor_st = { .lcrh_tx = ST_UART011_LCRH_TX, .lcrh_rx = ST_UART011_LCRH_RX, .oversampling = true, + .interrupt_may_hang = true, .dma_threshold = true, }; +static struct uart_amba_port *amba_ports[UART_NR]; + /* Deals with DMA transactions */ struct pl011_sgbuf { @@ -132,6 +161,7 @@ struct uart_amba_port { unsigned int lcrh_rx; /* vendor-specific */ bool autorts; char type[12]; + bool interrupt_may_hang; /* vendor-specific */ #ifdef CONFIG_DMA_ENGINE /* DMA stuff */ bool using_tx_dma; @@ -1008,6 +1038,68 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap) #endif +/* + * pl011_lockup_wa + * This workaround aims to break the deadlock situation + * when after long transfer over uart in hardware flow + * control, uart interrupt registers cannot be cleared. + * Hence uart transfer gets blocked. + * + * It is seen that during such deadlock condition ICR + * don't get cleared even on multiple write. This leads + * pass_counter to decrease and finally reach zero. This + * can be taken as trigger point to run this UART_BT_WA. + * + */ +static void pl011_lockup_wa(unsigned long data) +{ + struct uart_amba_port *uap = amba_ports[0]; + void __iomem *base = uap->port.membase; + struct circ_buf *xmit = &uap->port.state->xmit; + struct tty_struct *tty = uap->port.state->port.tty; + int buf_empty_retries = 200; + int loop; + + /* Stop HCI layer from submitting data for tx */ + tty->hw_stopped = 1; + while (!uart_circ_empty(xmit)) { + if (buf_empty_retries-- == 0) + break; + udelay(100); + } + + /* Backup registers */ + for (loop = 0; loop < UART_WA_SAVE_NR; loop++) + uart_wa_regdata[loop] = readl(base + uart_wa_reg[loop]); + + /* Disable UART so that FIFO data is flushed out */ + writew(0x00, uap->port.membase + UART011_CR); + + /* Soft reset UART module */ + if (uap->port.dev->platform_data) { + struct amba_pl011_data *plat; + + plat = uap->port.dev->platform_data; + if (plat->reset) + plat->reset(); + } + + /* Restore registers */ + for (loop = 0; loop < UART_WA_SAVE_NR; loop++) + writew(uart_wa_regdata[loop] , + uap->port.membase + uart_wa_reg[loop]); + + /* Initialise the old status of the modem signals */ + uap->old_status = readw(uap->port.membase + UART01x_FR) & + UART01x_FR_MODEM_ANY; + + if (readl(base + UART011_MIS) & 0x2) + printk(KERN_EMERG "UART_BT_WA: ***FAILED***\n"); + + /* Start Tx/Rx */ + tty->hw_stopped = 0; +} + static void pl011_stop_tx(struct uart_port *port) { struct uart_amba_port *uap = (struct uart_amba_port *)port; @@ -1158,8 +1250,11 @@ static irqreturn_t pl011_int(int irq, void *dev_id) if (status & UART011_TXIS) pl011_tx_chars(uap); - if (pass_counter-- == 0) + if (pass_counter-- == 0) { + if (uap->interrupt_may_hang) + tasklet_schedule(&pl011_lockup_tlet); break; + } status = readw(uap->port.membase + UART011_MIS); } while (status != 0); @@ -1339,6 +1434,14 @@ static int pl011_startup(struct uart_port *port) writew(uap->im, uap->port.membase + UART011_IMSC); spin_unlock_irq(&uap->port.lock); + if (uap->port.dev->platform_data) { + struct amba_pl011_data *plat; + + plat = uap->port.dev->platform_data; + if (plat->init) + plat->init(); + } + return 0; clk_dis: @@ -1394,6 +1497,15 @@ static void pl011_shutdown(struct uart_port *port) * Shut down the clock producer */ clk_disable(uap->clk); + + if (uap->port.dev->platform_data) { + struct amba_pl011_data *plat; + + plat = uap->port.dev->platform_data; + if (plat->exit) + plat->exit(); + } + } static void @@ -1700,6 +1812,14 @@ static int __init pl011_console_setup(struct console *co, char *options) if (!uap) return -ENODEV; + if (uap->port.dev->platform_data) { + struct amba_pl011_data *plat; + + plat = uap->port.dev->platform_data; + if (plat->init) + plat->init(); + } + uap->port.uartclk = clk_get_rate(uap->clk); if (options) @@ -1774,6 +1894,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) uap->lcrh_rx = vendor->lcrh_rx; uap->lcrh_tx = vendor->lcrh_tx; uap->fifosize = vendor->fifosize; + uap->interrupt_may_hang = vendor->interrupt_may_hang; uap->port.dev = &dev->dev; uap->port.mapbase = dev->res.start; uap->port.membase = base; diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index a1a0e55..c0b68b9 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -250,6 +250,20 @@ static void bcm_uart_do_rx(struct uart_port *port) /* get overrun/fifo empty information from ier * register */ iestat = bcm_uart_readl(port, UART_IR_REG); + + if (unlikely(iestat & UART_IR_STAT(UART_IR_RXOVER))) { + unsigned int val; + + /* fifo reset is required to clear + * interrupt */ + val = bcm_uart_readl(port, UART_CTL_REG); + val |= UART_CTL_RSTRXFIFO_MASK; + bcm_uart_writel(port, val, UART_CTL_REG); + + port->icount.overrun++; + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + } + if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY))) break; @@ -284,10 +298,6 @@ static void bcm_uart_do_rx(struct uart_port *port) if (uart_handle_sysrq_char(port, c)) continue; - if (unlikely(iestat & UART_IR_STAT(UART_IR_RXOVER))) { - port->icount.overrun++; - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } if ((cstat & port->ignore_status_mask) == 0) tty_insert_flip_char(tty, c, flag); diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c index 18f5484..96da178 100644 --- a/drivers/tty/serial/jsm/jsm_driver.c +++ b/drivers/tty/serial/jsm/jsm_driver.c @@ -125,7 +125,7 @@ static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device brd->bd_uart_offset = 0x200; brd->bd_dividend = 921600; - brd->re_map_membase = ioremap(brd->membase, 0x1000); + brd->re_map_membase = ioremap(brd->membase, pci_resource_len(pdev, 0)); if (!brd->re_map_membase) { dev_err(&pdev->dev, "card has no PCI Memory resources, " diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c index 1bd2845..a764bf9 100644 --- a/drivers/tty/serial/mrst_max3110.c +++ b/drivers/tty/serial/mrst_max3110.c @@ -421,7 +421,6 @@ static int max3110_main_thread(void *_max) int ret = 0; struct circ_buf *xmit = &max->con_xmit; - init_waitqueue_head(wq); pr_info(PR_FMT "start main thread\n"); do { @@ -823,7 +822,7 @@ static int __devinit serial_m3110_probe(struct spi_device *spi) res = RC_TAG; ret = max3110_write_then_read(max, (u8 *)&res, (u8 *)&res, 2, 0); if (ret < 0 || res == 0 || res == 0xffff) { - printk(KERN_ERR "MAX3111 deemed not present (conf reg %04x)", + dev_dbg(&spi->dev, "MAX3111 deemed not present (conf reg %04x)", res); ret = -ENODEV; goto err_get_page; @@ -838,6 +837,8 @@ static int __devinit serial_m3110_probe(struct spi_device *spi) max->con_xmit.head = 0; max->con_xmit.tail = 0; + init_waitqueue_head(&max->wq); + max->main_thread = kthread_run(max3110_main_thread, max, "max3110_main"); if (IS_ERR(max->main_thread)) { diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index f2cb750..4652109 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1397,6 +1397,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, int fifosize, base_baud; int port_type; struct pch_uart_driver_data *board; + const char *board_name; board = &drv_dat[id->driver_data]; port_type = board->port_type; @@ -1412,7 +1413,8 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, base_baud = 1843200; /* 1.8432MHz */ /* quirk for CM-iTC board */ - if (strstr(dmi_get_system_info(DMI_BOARD_NAME), "CM-iTC")) + board_name = dmi_get_system_info(DMI_BOARD_NAME); + if (board_name && strstr(board_name, "CM-iTC")) base_baud = 192000000; /* 192.0MHz */ switch (port_type) { diff --git a/drivers/tty/serial/s5pv210.c b/drivers/tty/serial/s5pv210.c index fb2619f9..dd194dc 100644 --- a/drivers/tty/serial/s5pv210.c +++ b/drivers/tty/serial/s5pv210.c @@ -30,7 +30,7 @@ static int s5pv210_serial_setsource(struct uart_port *port, struct s3c2410_uartcfg *cfg = port->dev->platform_data; unsigned long ucon = rd_regl(port, S3C2410_UCON); - if ((cfg->clocks_size) == 1) + if (cfg->flags & NO_NEED_CHECK_CLKSRC) return 0; if (strcmp(clk->name, "pclk") == 0) @@ -55,7 +55,7 @@ static int s5pv210_serial_getsource(struct uart_port *port, clk->divisor = 1; - if ((cfg->clocks_size) == 1) + if (cfg->flags & NO_NEED_CHECK_CLKSRC) return 0; switch (ucon & S5PV210_UCON_CLKMASK) { diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 5d01d32..ef925d5 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -555,7 +555,7 @@ static void tty_ldisc_flush_works(struct tty_struct *tty) static int tty_ldisc_wait_idle(struct tty_struct *tty) { int ret; - ret = wait_event_interruptible_timeout(tty_ldisc_idle, + ret = wait_event_timeout(tty_ldisc_idle, atomic_read(&tty->ldisc->users) == 1, 5 * HZ); if (ret < 0) return ret; @@ -763,6 +763,8 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc) if (IS_ERR(ld)) return -1; + WARN_ON_ONCE(tty_ldisc_wait_idle(tty)); + tty_ldisc_close(tty, tty->ldisc); tty_ldisc_put(tty->ldisc); tty->ldisc = NULL; diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index e35a176..34e3da5 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -375,7 +375,7 @@ static int usb_unbind_interface(struct device *dev) * Just re-enable it without affecting the endpoint toggles. */ usb_enable_interface(udev, intf, false); - } else if (!error && !intf->dev.power.in_suspend) { + } else if (!error && !intf->dev.power.is_prepared) { r = usb_set_interface(udev, intf->altsetting[0]. desc.bInterfaceNumber, 0); if (r < 0) @@ -960,7 +960,7 @@ void usb_rebind_intf(struct usb_interface *intf) } /* Try to rebind the interface */ - if (!intf->dev.power.in_suspend) { + if (!intf->dev.power.is_prepared) { intf->needs_binding = 0; rc = device_attach(&intf->dev); if (rc < 0) @@ -1107,7 +1107,7 @@ static int usb_resume_interface(struct usb_device *udev, if (intf->condition == USB_INTERFACE_UNBOUND) { /* Carry out a deferred switch to altsetting 0 */ - if (intf->needs_altsetting0 && !intf->dev.power.in_suspend) { + if (intf->needs_altsetting0 && !intf->dev.power.is_prepared) { usb_set_interface(udev, intf->altsetting[0]. desc.bInterfaceNumber, 0); intf->needs_altsetting0 = 0; @@ -1187,13 +1187,22 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) for (i = n - 1; i >= 0; --i) { intf = udev->actconfig->interface[i]; status = usb_suspend_interface(udev, intf, msg); + + /* Ignore errors during system sleep transitions */ + if (!(msg.event & PM_EVENT_AUTO)) + status = 0; if (status != 0) break; } } - if (status == 0) + if (status == 0) { status = usb_suspend_device(udev, msg); + /* Again, ignore errors during system sleep transitions */ + if (!(msg.event & PM_EVENT_AUTO)) + status = 0; + } + /* If the suspend failed, resume interfaces that did get suspended */ if (status != 0) { msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 90ae175..a428aa0 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1634,6 +1634,7 @@ void usb_disconnect(struct usb_device **pdev) { struct usb_device *udev = *pdev; int i; + struct usb_hcd *hcd = bus_to_hcd(udev->bus); if (!udev) { pr_debug ("%s nodev\n", __func__); @@ -1661,7 +1662,9 @@ void usb_disconnect(struct usb_device **pdev) * so that the hardware is now fully quiesced. */ dev_dbg (&udev->dev, "unregistering device\n"); + mutex_lock(hcd->bandwidth_mutex); usb_disable_device(udev, 0); + mutex_unlock(hcd->bandwidth_mutex); usb_hcd_synchronize_unlinks(udev); usb_remove_ep_devs(&udev->ep0); @@ -2362,6 +2365,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); + + /* System sleep transitions should never fail */ + if (!(msg.event & PM_EVENT_AUTO)) + status = 0; } else { /* device has up to 10 msec to fully suspend */ dev_dbg(&udev->dev, "usb %ssuspend\n", @@ -2611,16 +2618,15 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) struct usb_device *hdev = hub->hdev; unsigned port1; - /* fail if children aren't already suspended */ + /* Warn if children aren't already suspended */ for (port1 = 1; port1 <= hdev->maxchild; port1++) { struct usb_device *udev; udev = hdev->children [port1-1]; if (udev && udev->can_submit) { - if (!(msg.event & PM_EVENT_AUTO)) - dev_dbg(&intf->dev, "port %d nyet suspended\n", - port1); - return -EBUSY; + dev_warn(&intf->dev, "port %d nyet suspended\n", port1); + if (msg.event & PM_EVENT_AUTO) + return -EBUSY; } } diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 5701e85..64c7ab4 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1135,10 +1135,13 @@ void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf, * Deallocates hcd/hardware state for the endpoints (nuking all or most * pending urbs) and usbcore state for the interfaces, so that usbcore * must usb_set_configuration() before any interfaces could be used. + * + * Must be called with hcd->bandwidth_mutex held. */ void usb_disable_device(struct usb_device *dev, int skip_ep0) { int i; + struct usb_hcd *hcd = bus_to_hcd(dev->bus); /* getting rid of interfaces will disconnect * any drivers bound to them (a key side effect) @@ -1172,6 +1175,16 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__, skip_ep0 ? "non-ep0" : "all"); + if (hcd->driver->check_bandwidth) { + /* First pass: Cancel URBs, leave endpoint pointers intact. */ + for (i = skip_ep0; i < 16; ++i) { + usb_disable_endpoint(dev, i, false); + usb_disable_endpoint(dev, i + USB_DIR_IN, false); + } + /* Remove endpoints from the host controller internal state */ + usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL); + /* Second pass: remove endpoint pointers */ + } for (i = skip_ep0; i < 16; ++i) { usb_disable_endpoint(dev, i, true); usb_disable_endpoint(dev, i + USB_DIR_IN, true); @@ -1727,6 +1740,7 @@ free_interfaces: /* if it's already configured, clear out old state first. * getting rid of old interfaces means unbinding their drivers. */ + mutex_lock(hcd->bandwidth_mutex); if (dev->state != USB_STATE_ADDRESS) usb_disable_device(dev, 1); /* Skip ep0 */ @@ -1739,7 +1753,6 @@ free_interfaces: * host controller will not allow submissions to dropped endpoints. If * this call fails, the device state is unchanged. */ - mutex_lock(hcd->bandwidth_mutex); ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL); if (ret < 0) { mutex_unlock(hcd->bandwidth_mutex); diff --git a/drivers/usb/host/ehci-ath79.c b/drivers/usb/host/ehci-ath79.c index 98cc8a1..aa248c2 100644 --- a/drivers/usb/host/ehci-ath79.c +++ b/drivers/usb/host/ehci-ath79.c @@ -44,7 +44,6 @@ static int ehci_ath79_init(struct usb_hcd *hcd) struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct platform_device *pdev = to_platform_device(hcd->self.controller); const struct platform_device_id *id; - int hclength; int ret; id = platform_get_device_id(pdev); @@ -53,20 +52,23 @@ static int ehci_ath79_init(struct usb_hcd *hcd) return -EINVAL; } - hclength = HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); switch (id->driver_data) { case EHCI_ATH79_IP_V1: ehci->has_synopsys_hc_bug = 1; ehci->caps = hcd->regs; - ehci->regs = hcd->regs + hclength; + ehci->regs = hcd->regs + + HC_LENGTH(ehci, + ehci_readl(ehci, &ehci->caps->hc_capbase)); break; case EHCI_ATH79_IP_V2: hcd->has_tt = 1; ehci->caps = hcd->regs + 0x100; - ehci->regs = hcd->regs + 0x100 + hclength; + ehci->regs = hcd->regs + 0x100 + + HC_LENGTH(ehci, + ehci_readl(ehci, &ehci->caps->hc_capbase)); break; default: diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index b435ed6..f8030ee 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1,4 +1,8 @@ /* + * Enhanced Host Controller Interface (EHCI) driver for USB. + * + * Maintainer: Alan Stern <stern@rowland.harvard.edu> + * * Copyright (c) 2000-2004 by David Brownell * * This program is free software; you can redistribute it and/or modify it diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index c9e6e45..55d3d58 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -1555,7 +1555,7 @@ static void kill_transfer(struct usb_hcd *hcd, struct urb *urb, /* We need to forcefully reclaim the slot since some transfers never return, e.g. interrupt transfers and NAKed bulk transfers. */ - if (usb_pipebulk(urb->pipe)) { + if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) { skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); skip_map |= (1 << qh->slot); reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 9aa10bd..f9cf3f0 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1,5 +1,7 @@ /* - * OHCI HCD (Host Controller Driver) for USB. + * Open Host Controller Interface (OHCI) driver for USB. + * + * Maintainer: Alan Stern <stern@rowland.harvard.edu> * * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> * (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net> diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index db6f8b9..4586369 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -2517,6 +2517,7 @@ static int __devinit r8a66597_probe(struct platform_device *pdev) INIT_LIST_HEAD(&r8a66597->child_device); hcd->rsrc_start = res->start; + hcd->has_tt = 1; ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | irq_trigger); if (ret != 0) { diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 0f8e1d2..fcb7f7e 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1215,8 +1215,6 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet)); /* dig out max burst from ep companion desc */ max_packet = ep->ss_ep_comp.bMaxBurst; - if (!max_packet) - xhci_warn(xhci, "WARN no SS endpoint bMaxBurst\n"); ep_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(max_packet)); break; case USB_SPEED_HIGH: diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 17541d0..cb16de2 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -29,6 +29,9 @@ #define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 #define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000 +#define PCI_VENDOR_ID_ETRON 0x1b6f +#define PCI_DEVICE_ID_ASROCK_P67 0x7023 + static const char hcd_name[] = "xhci_hcd"; /* called after powerup, by probe or system-pm "wakeup" */ @@ -134,6 +137,11 @@ static int xhci_pci_setup(struct usb_hcd *hcd) xhci->quirks |= XHCI_EP_LIMIT_QUIRK; xhci->limit_active_eps = 64; } + if (pdev->vendor == PCI_VENDOR_ID_ETRON && + pdev->device == PCI_DEVICE_ID_ASROCK_P67) { + xhci->quirks |= XHCI_RESET_ON_RESUME; + xhci_dbg(xhci, "QUIRK: Resetting on resume\n"); + } /* Make sure the HC is halted. */ retval = xhci_halt(xhci); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 800f417..70cacbb 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1733,6 +1733,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, frame->status = -EOVERFLOW; skip_td = true; break; + case COMP_DEV_ERR: case COMP_STALL: frame->status = -EPROTO; skip_td = true; @@ -1767,9 +1768,6 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, } } - if ((idx == urb_priv->length - 1) && *status == -EINPROGRESS) - *status = 0; - return finish_td(xhci, td, event_trb, event, ep, status, false); } @@ -1787,8 +1785,7 @@ static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, idx = urb_priv->td_cnt; frame = &td->urb->iso_frame_desc[idx]; - /* The transfer is partly done */ - *status = -EXDEV; + /* The transfer is partly done. */ frame->status = -EXDEV; /* calc actual length */ @@ -2016,6 +2013,10 @@ static int handle_tx_event(struct xhci_hcd *xhci, TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), ep_index); goto cleanup; + case COMP_DEV_ERR: + xhci_warn(xhci, "WARN: detect an incompatible device"); + status = -EPROTO; + break; case COMP_MISSED_INT: /* * When encounter missed service error, one or more isoc tds @@ -2063,6 +2064,20 @@ static int handle_tx_event(struct xhci_hcd *xhci, /* Is this a TRB in the currently executing TD? */ event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue, td->last_trb, event_dma); + + /* + * Skip the Force Stopped Event. The event_trb(event_dma) of FSE + * is not in the current TD pointed by ep_ring->dequeue because + * that the hardware dequeue pointer still at the previous TRB + * of the current TD. The previous TRB maybe a Link TD or the + * last TRB of the previous TD. The command completion handle + * will take care the rest. + */ + if (!event_seg && trb_comp_code == COMP_STOP_INVAL) { + ret = 0; + goto cleanup; + } + if (!event_seg) { if (!ep->skip || !usb_endpoint_xfer_isoc(&td->urb->ep->desc)) { @@ -2158,6 +2173,11 @@ cleanup: urb->transfer_buffer_length, status); spin_unlock(&xhci->lock); + /* EHCI, UHCI, and OHCI always unconditionally set the + * urb->status of an isochronous endpoint to 0. + */ + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) + status = 0; usb_hcd_giveback_urb(bus_to_hcd(urb->dev->bus), urb, status); spin_lock(&xhci->lock); } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 06e7023..f5fe1ac 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -759,6 +759,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) msleep(100); spin_lock_irq(&xhci->lock); + if (xhci->quirks & XHCI_RESET_ON_RESUME) + hibernated = true; if (!hibernated) { /* step 1: restore register */ @@ -1401,6 +1403,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, u32 added_ctxs; unsigned int last_ctx; u32 new_add_flags, new_drop_flags, new_slot_info; + struct xhci_virt_device *virt_dev; int ret = 0; ret = xhci_check_args(hcd, udev, ep, 1, true, __func__); @@ -1425,11 +1428,25 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, return 0; } - in_ctx = xhci->devs[udev->slot_id]->in_ctx; - out_ctx = xhci->devs[udev->slot_id]->out_ctx; + virt_dev = xhci->devs[udev->slot_id]; + in_ctx = virt_dev->in_ctx; + out_ctx = virt_dev->out_ctx; ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); ep_index = xhci_get_endpoint_index(&ep->desc); ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index); + + /* If this endpoint is already in use, and the upper layers are trying + * to add it again without dropping it, reject the addition. + */ + if (virt_dev->eps[ep_index].ring && + !(le32_to_cpu(ctrl_ctx->drop_flags) & + xhci_get_endpoint_flag(&ep->desc))) { + xhci_warn(xhci, "Trying to add endpoint 0x%x " + "without dropping it.\n", + (unsigned int) ep->desc.bEndpointAddress); + return -EINVAL; + } + /* If the HCD has already noted the endpoint is enabled, * ignore this request. */ @@ -1445,8 +1462,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, * process context, not interrupt context (or so documenation * for usb_set_interface() and usb_set_configuration() claim). */ - if (xhci_endpoint_init(xhci, xhci->devs[udev->slot_id], - udev, ep, GFP_NOIO) < 0) { + if (xhci_endpoint_init(xhci, virt_dev, udev, ep, GFP_NOIO) < 0) { dev_dbg(&udev->dev, "%s - could not initialize ep %#x\n", __func__, ep->desc.bEndpointAddress); return -ENOMEM; @@ -1537,6 +1553,11 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci, "and endpoint is not disabled.\n"); ret = -EINVAL; break; + case COMP_DEV_ERR: + dev_warn(&udev->dev, "ERROR: Incompatible device for endpoint " + "configure command.\n"); + ret = -ENODEV; + break; case COMP_SUCCESS: dev_dbg(&udev->dev, "Successful Endpoint Configure command\n"); ret = 0; @@ -1571,6 +1592,11 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci, xhci_dbg_ctx(xhci, virt_dev->out_ctx, 1); ret = -EINVAL; break; + case COMP_DEV_ERR: + dev_warn(&udev->dev, "ERROR: Incompatible device for evaluate " + "context command.\n"); + ret = -ENODEV; + break; case COMP_MEL_ERR: /* Max Exit Latency too large error */ dev_warn(&udev->dev, "WARN: Max Exit Latency too large\n"); @@ -2853,6 +2879,11 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) dev_warn(&udev->dev, "Device not responding to set address.\n"); ret = -EPROTO; break; + case COMP_DEV_ERR: + dev_warn(&udev->dev, "ERROR: Incompatible device for address " + "device command.\n"); + ret = -ENODEV; + break; case COMP_SUCCESS: xhci_dbg(xhci, "Successful Address Device command\n"); break; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 7d1ea3b..d8bbf5c 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -874,6 +874,8 @@ struct xhci_transfer_event { #define COMP_PING_ERR 20 /* Event Ring is full */ #define COMP_ER_FULL 21 +/* Incompatible Device Error */ +#define COMP_DEV_ERR 22 /* Missed Service Error - HC couldn't service an isoc ep within interval */ #define COMP_MISSED_INT 23 /* Successfully stopped command ring */ @@ -1308,6 +1310,7 @@ struct xhci_hcd { */ #define XHCI_EP_LIMIT_QUIRK (1 << 5) #define XHCI_BROKEN_MSI (1 << 6) +#define XHCI_RESET_ON_RESUME (1 << 7) unsigned int num_active_eps; unsigned int limit_active_eps; /* There are two roothubs to keep track of bus suspend info for */ diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 0a50a35..6aeb363 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1524,6 +1524,12 @@ static void musb_gadget_fifo_flush(struct usb_ep *ep) csr = musb_readw(epio, MUSB_TXCSR); if (csr & MUSB_TXCSR_FIFONOTEMPTY) { csr |= MUSB_TXCSR_FLUSHFIFO | MUSB_TXCSR_P_WZC_BITS; + /* + * Setting both TXPKTRDY and FLUSHFIFO makes controller + * to interrupt current FIFO loading, but not flushing + * the already loaded ones. + */ + csr &= ~MUSB_TXCSR_TXPKTRDY; musb_writew(epio, MUSB_TXCSR, csr); /* REVISIT may be inappropriate w/o FIFONOTEMPTY ... */ musb_writew(epio, MUSB_TXCSR, csr); diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 7295e31..8b2473f 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -1575,7 +1575,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) /* even if there was an error, we did the dma * for iso_frame_desc->length */ - if (d->status != EILSEQ && d->status != -EOVERFLOW) + if (d->status != -EILSEQ && d->status != -EOVERFLOW) d->status = 0; if (++qh->iso_idx >= urb->number_of_packets) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 1627289..2e06b90 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -179,6 +179,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_232RL_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, { USB_DEVICE(FTDI_VID, FTDI_4232H_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_232H_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) }, @@ -848,7 +849,8 @@ static const char *ftdi_chip_name[] = { [FT2232C] = "FT2232C", [FT232RL] = "FT232RL", [FT2232H] = "FT2232H", - [FT4232H] = "FT4232H" + [FT4232H] = "FT4232H", + [FT232H] = "FT232H" }; @@ -1168,6 +1170,7 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, break; case FT2232H: /* FT2232H chip */ case FT4232H: /* FT4232H chip */ + case FT232H: /* FT232H chip */ if ((baud <= 12000000) & (baud >= 1200)) { div_value = ftdi_2232h_baud_to_divisor(baud); } else if (baud < 1200) { @@ -1429,9 +1432,12 @@ static void ftdi_determine_type(struct usb_serial_port *port) } else if (version < 0x600) { /* Assume it's an FT232BM (or FT245BM) */ priv->chip_type = FT232BM; - } else { - /* Assume it's an FT232R */ + } else if (version < 0x900) { + /* Assume it's an FT232RL */ priv->chip_type = FT232RL; + } else { + /* Assume it's an FT232H */ + priv->chip_type = FT232H; } dev_info(&udev->dev, "Detected %s\n", ftdi_chip_name[priv->chip_type]); } @@ -1559,7 +1565,8 @@ static int create_sysfs_attrs(struct usb_serial_port *port) priv->chip_type == FT2232C || priv->chip_type == FT232RL || priv->chip_type == FT2232H || - priv->chip_type == FT4232H)) { + priv->chip_type == FT4232H || + priv->chip_type == FT232H)) { retval = device_create_file(&port->dev, &dev_attr_latency_timer); } @@ -1580,7 +1587,8 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) priv->chip_type == FT2232C || priv->chip_type == FT232RL || priv->chip_type == FT2232H || - priv->chip_type == FT4232H) { + priv->chip_type == FT4232H || + priv->chip_type == FT232H) { device_remove_file(&port->dev, &dev_attr_latency_timer); } } @@ -2212,6 +2220,7 @@ static int ftdi_tiocmget(struct tty_struct *tty) case FT232RL: case FT2232H: case FT4232H: + case FT232H: len = 2; break; default: diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 213fe3d..19584fa 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -156,7 +156,8 @@ enum ftdi_chip_type { FT2232C = 4, FT232RL = 5, FT2232H = 6, - FT4232H = 7 + FT4232H = 7, + FT232H = 8 }; enum ftdi_sio_baudrate { diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index ab1fcdf..19156d1 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -22,6 +22,7 @@ #define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */ #define FTDI_8U2232C_PID 0x6010 /* Dual channel device */ #define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */ +#define FTDI_232H_PID 0x6014 /* Single channel hi-speed device */ #define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ #define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */ diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index c6d92a5..ea84456 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -1745,6 +1745,7 @@ static int ti_download_firmware(struct ti_device *tdev) } if (fw_p->size > TI_FIRMWARE_BUF_SIZE) { dev_err(&dev->dev, "%s - firmware too large %zu\n", __func__, fw_p->size); + release_firmware(fw_p); return -ENOENT; } diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index ebb893c..d7aaec5 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -248,10 +248,6 @@ static int atyfb_sync(struct fb_info *info); static int aty_init(struct fb_info *info); -#ifdef CONFIG_ATARI -static int store_video_par(char *videopar, unsigned char m64_num); -#endif - static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc); static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc); @@ -2268,11 +2264,13 @@ error: return; } +#ifdef CONFIG_PCI static void aty_bl_exit(struct backlight_device *bd) { backlight_device_unregister(bd); printk("aty: Backlight unloaded\n"); } +#endif /* CONFIG_PCI */ #endif /* CONFIG_FB_ATY_BACKLIGHT */ @@ -2789,7 +2787,7 @@ aty_init_exit: return ret; } -#ifdef CONFIG_ATARI +#if defined(CONFIG_ATARI) && !defined(MODULE) static int __devinit store_video_par(char *video_str, unsigned char m64_num) { char *p; @@ -2818,7 +2816,7 @@ static int __devinit store_video_par(char *video_str, unsigned char m64_num) phys_vmembase[m64_num] = 0; return -1; } -#endif /* CONFIG_ATARI */ +#endif /* CONFIG_ATARI && !MODULE */ /* * Blank the display. diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 0c9373b..2d93c8d 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -302,6 +302,18 @@ config BACKLIGHT_ADP8860 To compile this driver as a module, choose M here: the module will be called adp8860_bl. +config BACKLIGHT_ADP8870 + tristate "Backlight Driver for ADP8870 using WLED" + depends on BACKLIGHT_CLASS_DEVICE && I2C + select NEW_LEDS + select LEDS_CLASS + help + If you have a LCD backlight connected to the ADP8870, + say Y here to enable this driver. + + To compile this driver as a module, choose M here: the module will + be called adp8870_bl. + config BACKLIGHT_88PM860X tristate "Backlight Driver for 88PM8606 using WLED" depends on MFD_88PM860X diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index b9ca849..ee72adb 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o obj-$(CONFIG_BACKLIGHT_ADX) += adx_bl.o obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o obj-$(CONFIG_BACKLIGHT_ADP8860) += adp8860_bl.o +obj-$(CONFIG_BACKLIGHT_ADP8870) += adp8870_bl.o obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c new file mode 100644 index 0000000..05a8832 --- /dev/null +++ b/drivers/video/backlight/adp8870_bl.c @@ -0,0 +1,1012 @@ +/* + * Backlight driver for Analog Devices ADP8870 Backlight Devices + * + * Copyright 2009-2011 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/module.h> +#include <linux/version.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/pm.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/fb.h> +#include <linux/backlight.h> +#include <linux/leds.h> +#include <linux/workqueue.h> +#include <linux/slab.h> + +#include <linux/i2c/adp8870.h> +#define ADP8870_EXT_FEATURES +#define ADP8870_USE_LEDS + + +#define ADP8870_MFDVID 0x00 /* Manufacturer and device ID */ +#define ADP8870_MDCR 0x01 /* Device mode and status */ +#define ADP8870_INT_STAT 0x02 /* Interrupts status */ +#define ADP8870_INT_EN 0x03 /* Interrupts enable */ +#define ADP8870_CFGR 0x04 /* Configuration register */ +#define ADP8870_BLSEL 0x05 /* Sink enable backlight or independent */ +#define ADP8870_PWMLED 0x06 /* PWM Enable Selection Register */ +#define ADP8870_BLOFF 0x07 /* Backlight off timeout */ +#define ADP8870_BLDIM 0x08 /* Backlight dim timeout */ +#define ADP8870_BLFR 0x09 /* Backlight fade in and out rates */ +#define ADP8870_BLMX1 0x0A /* Backlight (Brightness Level 1-daylight) maximum current */ +#define ADP8870_BLDM1 0x0B /* Backlight (Brightness Level 1-daylight) dim current */ +#define ADP8870_BLMX2 0x0C /* Backlight (Brightness Level 2-bright) maximum current */ +#define ADP8870_BLDM2 0x0D /* Backlight (Brightness Level 2-bright) dim current */ +#define ADP8870_BLMX3 0x0E /* Backlight (Brightness Level 3-office) maximum current */ +#define ADP8870_BLDM3 0x0F /* Backlight (Brightness Level 3-office) dim current */ +#define ADP8870_BLMX4 0x10 /* Backlight (Brightness Level 4-indoor) maximum current */ +#define ADP8870_BLDM4 0x11 /* Backlight (Brightness Level 4-indoor) dim current */ +#define ADP8870_BLMX5 0x12 /* Backlight (Brightness Level 5-dark) maximum current */ +#define ADP8870_BLDM5 0x13 /* Backlight (Brightness Level 5-dark) dim current */ +#define ADP8870_ISCLAW 0x1A /* Independent sink current fade law register */ +#define ADP8870_ISCC 0x1B /* Independent sink current control register */ +#define ADP8870_ISCT1 0x1C /* Independent Sink Current Timer Register LED[7:5] */ +#define ADP8870_ISCT2 0x1D /* Independent Sink Current Timer Register LED[4:1] */ +#define ADP8870_ISCF 0x1E /* Independent sink current fade register */ +#define ADP8870_ISC1 0x1F /* Independent Sink Current LED1 */ +#define ADP8870_ISC2 0x20 /* Independent Sink Current LED2 */ +#define ADP8870_ISC3 0x21 /* Independent Sink Current LED3 */ +#define ADP8870_ISC4 0x22 /* Independent Sink Current LED4 */ +#define ADP8870_ISC5 0x23 /* Independent Sink Current LED5 */ +#define ADP8870_ISC6 0x24 /* Independent Sink Current LED6 */ +#define ADP8870_ISC7 0x25 /* Independent Sink Current LED7 (Brightness Level 1-daylight) */ +#define ADP8870_ISC7_L2 0x26 /* Independent Sink Current LED7 (Brightness Level 2-bright) */ +#define ADP8870_ISC7_L3 0x27 /* Independent Sink Current LED7 (Brightness Level 3-office) */ +#define ADP8870_ISC7_L4 0x28 /* Independent Sink Current LED7 (Brightness Level 4-indoor) */ +#define ADP8870_ISC7_L5 0x29 /* Independent Sink Current LED7 (Brightness Level 5-dark) */ +#define ADP8870_CMP_CTL 0x2D /* ALS Comparator Control Register */ +#define ADP8870_ALS1_EN 0x2E /* Main ALS comparator level enable */ +#define ADP8870_ALS2_EN 0x2F /* Second ALS comparator level enable */ +#define ADP8870_ALS1_STAT 0x30 /* Main ALS Comparator Status Register */ +#define ADP8870_ALS2_STAT 0x31 /* Second ALS Comparator Status Register */ +#define ADP8870_L2TRP 0x32 /* L2 comparator reference */ +#define ADP8870_L2HYS 0x33 /* L2 hysteresis */ +#define ADP8870_L3TRP 0x34 /* L3 comparator reference */ +#define ADP8870_L3HYS 0x35 /* L3 hysteresis */ +#define ADP8870_L4TRP 0x36 /* L4 comparator reference */ +#define ADP8870_L4HYS 0x37 /* L4 hysteresis */ +#define ADP8870_L5TRP 0x38 /* L5 comparator reference */ +#define ADP8870_L5HYS 0x39 /* L5 hysteresis */ +#define ADP8870_PH1LEVL 0x40 /* First phototransistor ambient light level-low byte register */ +#define ADP8870_PH1LEVH 0x41 /* First phototransistor ambient light level-high byte register */ +#define ADP8870_PH2LEVL 0x42 /* Second phototransistor ambient light level-low byte register */ +#define ADP8870_PH2LEVH 0x43 /* Second phototransistor ambient light level-high byte register */ + +#define ADP8870_MANUFID 0x3 /* Analog Devices AD8870 Manufacturer and device ID */ +#define ADP8870_DEVID(x) ((x) & 0xF) +#define ADP8870_MANID(x) ((x) >> 4) + +/* MDCR Device mode and status */ +#define D7ALSEN (1 << 7) +#define INT_CFG (1 << 6) +#define NSTBY (1 << 5) +#define DIM_EN (1 << 4) +#define GDWN_DIS (1 << 3) +#define SIS_EN (1 << 2) +#define CMP_AUTOEN (1 << 1) +#define BLEN (1 << 0) + +/* ADP8870_ALS1_EN Main ALS comparator level enable */ +#define L5_EN (1 << 3) +#define L4_EN (1 << 2) +#define L3_EN (1 << 1) +#define L2_EN (1 << 0) + +#define CFGR_BLV_SHIFT 3 +#define CFGR_BLV_MASK 0x7 +#define ADP8870_FLAG_LED_MASK 0xFF + +#define FADE_VAL(in, out) ((0xF & (in)) | ((0xF & (out)) << 4)) +#define BL_CFGR_VAL(law, blv) ((((blv) & CFGR_BLV_MASK) << CFGR_BLV_SHIFT) | ((0x3 & (law)) << 1)) +#define ALS_CMPR_CFG_VAL(filt) ((0x7 & (filt)) << 1) + +struct adp8870_bl { + struct i2c_client *client; + struct backlight_device *bl; + struct adp8870_led *led; + struct adp8870_backlight_platform_data *pdata; + struct mutex lock; + unsigned long cached_daylight_max; + int id; + int revid; + int current_brightness; +}; + +struct adp8870_led { + struct led_classdev cdev; + struct work_struct work; + struct i2c_client *client; + enum led_brightness new_brightness; + int id; + int flags; +}; + +static int adp8870_read(struct i2c_client *client, int reg, uint8_t *val) +{ + int ret; + + ret = i2c_smbus_read_byte_data(client, reg); + if (ret < 0) { + dev_err(&client->dev, "failed reading at 0x%02x\n", reg); + return ret; + } + + *val = ret; + return 0; +} + + +static int adp8870_write(struct i2c_client *client, u8 reg, u8 val) +{ + int ret = i2c_smbus_write_byte_data(client, reg, val); + if (ret) + dev_err(&client->dev, "failed to write\n"); + + return ret; +} + +static int adp8870_set_bits(struct i2c_client *client, int reg, uint8_t bit_mask) +{ + struct adp8870_bl *data = i2c_get_clientdata(client); + uint8_t reg_val; + int ret; + + mutex_lock(&data->lock); + + ret = adp8870_read(client, reg, ®_val); + + if (!ret && ((reg_val & bit_mask) == 0)) { + reg_val |= bit_mask; + ret = adp8870_write(client, reg, reg_val); + } + + mutex_unlock(&data->lock); + return ret; +} + +static int adp8870_clr_bits(struct i2c_client *client, int reg, uint8_t bit_mask) +{ + struct adp8870_bl *data = i2c_get_clientdata(client); + uint8_t reg_val; + int ret; + + mutex_lock(&data->lock); + + ret = adp8870_read(client, reg, ®_val); + + if (!ret && (reg_val & bit_mask)) { + reg_val &= ~bit_mask; + ret = adp8870_write(client, reg, reg_val); + } + + mutex_unlock(&data->lock); + return ret; +} + +/* + * Independent sink / LED + */ +#if defined(ADP8870_USE_LEDS) +static void adp8870_led_work(struct work_struct *work) +{ + struct adp8870_led *led = container_of(work, struct adp8870_led, work); + adp8870_write(led->client, ADP8870_ISC1 + led->id - 1, + led->new_brightness >> 1); +} + +static void adp8870_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct adp8870_led *led; + + led = container_of(led_cdev, struct adp8870_led, cdev); + led->new_brightness = value; + /* + * Use workqueue for IO since I2C operations can sleep. + */ + schedule_work(&led->work); +} + +static int adp8870_led_setup(struct adp8870_led *led) +{ + struct i2c_client *client = led->client; + int ret = 0; + + ret = adp8870_write(client, ADP8870_ISC1 + led->id - 1, 0); + if (ret) + return ret; + + ret = adp8870_set_bits(client, ADP8870_ISCC, 1 << (led->id - 1)); + if (ret) + return ret; + + if (led->id > 4) + ret = adp8870_set_bits(client, ADP8870_ISCT1, + (led->flags & 0x3) << ((led->id - 5) * 2)); + else + ret = adp8870_set_bits(client, ADP8870_ISCT2, + (led->flags & 0x3) << ((led->id - 1) * 2)); + + return ret; +} + +static int __devinit adp8870_led_probe(struct i2c_client *client) +{ + struct adp8870_backlight_platform_data *pdata = + client->dev.platform_data; + struct adp8870_bl *data = i2c_get_clientdata(client); + struct adp8870_led *led, *led_dat; + struct led_info *cur_led; + int ret, i; + + + led = kcalloc(pdata->num_leds, sizeof(*led), GFP_KERNEL); + if (led == NULL) { + dev_err(&client->dev, "failed to alloc memory\n"); + return -ENOMEM; + } + + ret = adp8870_write(client, ADP8870_ISCLAW, pdata->led_fade_law); + if (ret) + goto err_free; + + ret = adp8870_write(client, ADP8870_ISCT1, + (pdata->led_on_time & 0x3) << 6); + if (ret) + goto err_free; + + ret = adp8870_write(client, ADP8870_ISCF, + FADE_VAL(pdata->led_fade_in, pdata->led_fade_out)); + if (ret) + goto err_free; + + for (i = 0; i < pdata->num_leds; ++i) { + cur_led = &pdata->leds[i]; + led_dat = &led[i]; + + led_dat->id = cur_led->flags & ADP8870_FLAG_LED_MASK; + + if (led_dat->id > 7 || led_dat->id < 1) { + dev_err(&client->dev, "Invalid LED ID %d\n", + led_dat->id); + goto err; + } + + if (pdata->bl_led_assign & (1 << (led_dat->id - 1))) { + dev_err(&client->dev, "LED %d used by Backlight\n", + led_dat->id); + goto err; + } + + led_dat->cdev.name = cur_led->name; + led_dat->cdev.default_trigger = cur_led->default_trigger; + led_dat->cdev.brightness_set = adp8870_led_set; + led_dat->cdev.brightness = LED_OFF; + led_dat->flags = cur_led->flags >> FLAG_OFFT_SHIFT; + led_dat->client = client; + led_dat->new_brightness = LED_OFF; + INIT_WORK(&led_dat->work, adp8870_led_work); + + ret = led_classdev_register(&client->dev, &led_dat->cdev); + if (ret) { + dev_err(&client->dev, "failed to register LED %d\n", + led_dat->id); + goto err; + } + + ret = adp8870_led_setup(led_dat); + if (ret) { + dev_err(&client->dev, "failed to write\n"); + i++; + goto err; + } + } + + data->led = led; + + return 0; + + err: + for (i = i - 1; i >= 0; --i) { + led_classdev_unregister(&led[i].cdev); + cancel_work_sync(&led[i].work); + } + + err_free: + kfree(led); + + return ret; +} + +static int __devexit adp8870_led_remove(struct i2c_client *client) +{ + struct adp8870_backlight_platform_data *pdata = + client->dev.platform_data; + struct adp8870_bl *data = i2c_get_clientdata(client); + int i; + + for (i = 0; i < pdata->num_leds; i++) { + led_classdev_unregister(&data->led[i].cdev); + cancel_work_sync(&data->led[i].work); + } + + kfree(data->led); + return 0; +} +#else +static int __devinit adp8870_led_probe(struct i2c_client *client) +{ + return 0; +} + +static int __devexit adp8870_led_remove(struct i2c_client *client) +{ + return 0; +} +#endif + +static int adp8870_bl_set(struct backlight_device *bl, int brightness) +{ + struct adp8870_bl *data = bl_get_data(bl); + struct i2c_client *client = data->client; + int ret = 0; + + if (data->pdata->en_ambl_sens) { + if ((brightness > 0) && (brightness < ADP8870_MAX_BRIGHTNESS)) { + /* Disable Ambient Light auto adjust */ + ret = adp8870_clr_bits(client, ADP8870_MDCR, + CMP_AUTOEN); + if (ret) + return ret; + ret = adp8870_write(client, ADP8870_BLMX1, brightness); + if (ret) + return ret; + } else { + /* + * MAX_BRIGHTNESS -> Enable Ambient Light auto adjust + * restore daylight l1 sysfs brightness + */ + ret = adp8870_write(client, ADP8870_BLMX1, + data->cached_daylight_max); + if (ret) + return ret; + + ret = adp8870_set_bits(client, ADP8870_MDCR, + CMP_AUTOEN); + if (ret) + return ret; + } + } else { + ret = adp8870_write(client, ADP8870_BLMX1, brightness); + if (ret) + return ret; + } + + if (data->current_brightness && brightness == 0) + ret = adp8870_set_bits(client, + ADP8870_MDCR, DIM_EN); + else if (data->current_brightness == 0 && brightness) + ret = adp8870_clr_bits(client, + ADP8870_MDCR, DIM_EN); + + if (!ret) + data->current_brightness = brightness; + + return ret; +} + +static int adp8870_bl_update_status(struct backlight_device *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; + + return adp8870_bl_set(bl, brightness); +} + +static int adp8870_bl_get_brightness(struct backlight_device *bl) +{ + struct adp8870_bl *data = bl_get_data(bl); + + return data->current_brightness; +} + +static const struct backlight_ops adp8870_bl_ops = { + .update_status = adp8870_bl_update_status, + .get_brightness = adp8870_bl_get_brightness, +}; + +static int adp8870_bl_setup(struct backlight_device *bl) +{ + struct adp8870_bl *data = bl_get_data(bl); + struct i2c_client *client = data->client; + struct adp8870_backlight_platform_data *pdata = data->pdata; + int ret = 0; + + ret = adp8870_write(client, ADP8870_BLSEL, ~pdata->bl_led_assign); + if (ret) + return ret; + + ret = adp8870_write(client, ADP8870_PWMLED, pdata->pwm_assign); + if (ret) + return ret; + + ret = adp8870_write(client, ADP8870_BLMX1, pdata->l1_daylight_max); + if (ret) + return ret; + + ret = adp8870_write(client, ADP8870_BLDM1, pdata->l1_daylight_dim); + if (ret) + return ret; + + if (pdata->en_ambl_sens) { + data->cached_daylight_max = pdata->l1_daylight_max; + ret = adp8870_write(client, ADP8870_BLMX2, + pdata->l2_bright_max); + if (ret) + return ret; + ret = adp8870_write(client, ADP8870_BLDM2, + pdata->l2_bright_dim); + if (ret) + return ret; + + ret = adp8870_write(client, ADP8870_BLMX3, + pdata->l3_office_max); + if (ret) + return ret; + ret = adp8870_write(client, ADP8870_BLDM3, + pdata->l3_office_dim); + if (ret) + return ret; + + ret = adp8870_write(client, ADP8870_BLMX4, + pdata->l4_indoor_max); + if (ret) + return ret; + + ret = adp8870_write(client, ADP8870_BLDM4, + pdata->l4_indor_dim); + if (ret) + return ret; + + ret = adp8870_write(client, ADP8870_BLMX5, + pdata->l5_dark_max); + if (ret) + return ret; + + ret = adp8870_write(client, ADP8870_BLDM5, + pdata->l5_dark_dim); + if (ret) + return ret; + + ret = adp8870_write(client, ADP8870_L2TRP, pdata->l2_trip); + if (ret) + return ret; + + ret = adp8870_write(client, ADP8870_L2HYS, pdata->l2_hyst); + if (ret) + return ret; + + ret = adp8870_write(client, ADP8870_L3TRP, pdata->l3_trip); + if (ret) + return ret; + + ret = adp8870_write(client, ADP8870_L3HYS, pdata->l3_hyst); + if (ret) + return ret; + + ret = adp8870_write(client, ADP8870_L4TRP, pdata->l4_trip); + if (ret) + return ret; + + ret = adp8870_write(client, ADP8870_L4HYS, pdata->l4_hyst); + if (ret) + return ret; + + ret = adp8870_write(client, ADP8870_L5TRP, pdata->l5_trip); + if (ret) + return ret; + + ret = adp8870_write(client, ADP8870_L5HYS, pdata->l5_hyst); + if (ret) + return ret; + + ret = adp8870_write(client, ADP8870_ALS1_EN, L5_EN | L4_EN | + L3_EN | L2_EN); + if (ret) + return ret; + + ret = adp8870_write(client, ADP8870_CMP_CTL, + ALS_CMPR_CFG_VAL(pdata->abml_filt)); + if (ret) + return ret; + } + + ret = adp8870_write(client, ADP8870_CFGR, + BL_CFGR_VAL(pdata->bl_fade_law, 0)); + if (ret) + return ret; + + ret = adp8870_write(client, ADP8870_BLFR, FADE_VAL(pdata->bl_fade_in, + pdata->bl_fade_out)); + if (ret) + return ret; + /* + * ADP8870 Rev0 requires GDWN_DIS bit set + */ + + ret = adp8870_set_bits(client, ADP8870_MDCR, BLEN | DIM_EN | NSTBY | + (data->revid == 0 ? GDWN_DIS : 0)); + + return ret; +} + +static ssize_t adp8870_show(struct device *dev, char *buf, int reg) +{ + struct adp8870_bl *data = dev_get_drvdata(dev); + int error; + uint8_t reg_val; + + mutex_lock(&data->lock); + error = adp8870_read(data->client, reg, ®_val); + mutex_unlock(&data->lock); + + if (error < 0) + return error; + + return sprintf(buf, "%u\n", reg_val); +} + +static ssize_t adp8870_store(struct device *dev, const char *buf, + size_t count, int reg) +{ + struct adp8870_bl *data = dev_get_drvdata(dev); + unsigned long val; + int ret; + + ret = strict_strtoul(buf, 10, &val); + if (ret) + return ret; + + mutex_lock(&data->lock); + adp8870_write(data->client, reg, val); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t adp8870_bl_l5_dark_max_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8870_show(dev, buf, ADP8870_BLMX5); +} + +static ssize_t adp8870_bl_l5_dark_max_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return adp8870_store(dev, buf, count, ADP8870_BLMX5); +} +static DEVICE_ATTR(l5_dark_max, 0664, adp8870_bl_l5_dark_max_show, + adp8870_bl_l5_dark_max_store); + + +static ssize_t adp8870_bl_l4_indoor_max_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8870_show(dev, buf, ADP8870_BLMX4); +} + +static ssize_t adp8870_bl_l4_indoor_max_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return adp8870_store(dev, buf, count, ADP8870_BLMX4); +} +static DEVICE_ATTR(l4_indoor_max, 0664, adp8870_bl_l4_indoor_max_show, + adp8870_bl_l4_indoor_max_store); + + +static ssize_t adp8870_bl_l3_office_max_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8870_show(dev, buf, ADP8870_BLMX3); +} + +static ssize_t adp8870_bl_l3_office_max_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return adp8870_store(dev, buf, count, ADP8870_BLMX3); +} + +static DEVICE_ATTR(l3_office_max, 0664, adp8870_bl_l3_office_max_show, + adp8870_bl_l3_office_max_store); + +static ssize_t adp8870_bl_l2_bright_max_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8870_show(dev, buf, ADP8870_BLMX2); +} + +static ssize_t adp8870_bl_l2_bright_max_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return adp8870_store(dev, buf, count, ADP8870_BLMX2); +} +static DEVICE_ATTR(l2_bright_max, 0664, adp8870_bl_l2_bright_max_show, + adp8870_bl_l2_bright_max_store); + +static ssize_t adp8870_bl_l1_daylight_max_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8870_show(dev, buf, ADP8870_BLMX1); +} + +static ssize_t adp8870_bl_l1_daylight_max_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct adp8870_bl *data = dev_get_drvdata(dev); + int ret = strict_strtoul(buf, 10, &data->cached_daylight_max); + if (ret) + return ret; + + return adp8870_store(dev, buf, count, ADP8870_BLMX1); +} +static DEVICE_ATTR(l1_daylight_max, 0664, adp8870_bl_l1_daylight_max_show, + adp8870_bl_l1_daylight_max_store); + +static ssize_t adp8870_bl_l5_dark_dim_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8870_show(dev, buf, ADP8870_BLDM5); +} + +static ssize_t adp8870_bl_l5_dark_dim_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return adp8870_store(dev, buf, count, ADP8870_BLDM5); +} +static DEVICE_ATTR(l5_dark_dim, 0664, adp8870_bl_l5_dark_dim_show, + adp8870_bl_l5_dark_dim_store); + +static ssize_t adp8870_bl_l4_indoor_dim_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8870_show(dev, buf, ADP8870_BLDM4); +} + +static ssize_t adp8870_bl_l4_indoor_dim_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return adp8870_store(dev, buf, count, ADP8870_BLDM4); +} +static DEVICE_ATTR(l4_indoor_dim, 0664, adp8870_bl_l4_indoor_dim_show, + adp8870_bl_l4_indoor_dim_store); + + +static ssize_t adp8870_bl_l3_office_dim_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8870_show(dev, buf, ADP8870_BLDM3); +} + +static ssize_t adp8870_bl_l3_office_dim_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return adp8870_store(dev, buf, count, ADP8870_BLDM3); +} +static DEVICE_ATTR(l3_office_dim, 0664, adp8870_bl_l3_office_dim_show, + adp8870_bl_l3_office_dim_store); + +static ssize_t adp8870_bl_l2_bright_dim_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8870_show(dev, buf, ADP8870_BLDM2); +} + +static ssize_t adp8870_bl_l2_bright_dim_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return adp8870_store(dev, buf, count, ADP8870_BLDM2); +} +static DEVICE_ATTR(l2_bright_dim, 0664, adp8870_bl_l2_bright_dim_show, + adp8870_bl_l2_bright_dim_store); + +static ssize_t adp8870_bl_l1_daylight_dim_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8870_show(dev, buf, ADP8870_BLDM1); +} + +static ssize_t adp8870_bl_l1_daylight_dim_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return adp8870_store(dev, buf, count, ADP8870_BLDM1); +} +static DEVICE_ATTR(l1_daylight_dim, 0664, adp8870_bl_l1_daylight_dim_show, + adp8870_bl_l1_daylight_dim_store); + +#ifdef ADP8870_EXT_FEATURES +static ssize_t adp8870_bl_ambient_light_level_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adp8870_bl *data = dev_get_drvdata(dev); + int error; + uint8_t reg_val; + uint16_t ret_val; + + mutex_lock(&data->lock); + error = adp8870_read(data->client, ADP8870_PH1LEVL, ®_val); + if (error < 0) { + mutex_unlock(&data->lock); + return error; + } + ret_val = reg_val; + error = adp8870_read(data->client, ADP8870_PH1LEVH, ®_val); + mutex_unlock(&data->lock); + + if (error < 0) + return error; + + /* Return 13-bit conversion value for the first light sensor */ + ret_val += (reg_val & 0x1F) << 8; + + return sprintf(buf, "%u\n", ret_val); +} +static DEVICE_ATTR(ambient_light_level, 0444, + adp8870_bl_ambient_light_level_show, NULL); + +static ssize_t adp8870_bl_ambient_light_zone_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adp8870_bl *data = dev_get_drvdata(dev); + int error; + uint8_t reg_val; + + mutex_lock(&data->lock); + error = adp8870_read(data->client, ADP8870_CFGR, ®_val); + mutex_unlock(&data->lock); + + if (error < 0) + return error; + + return sprintf(buf, "%u\n", + ((reg_val >> CFGR_BLV_SHIFT) & CFGR_BLV_MASK) + 1); +} + +static ssize_t adp8870_bl_ambient_light_zone_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adp8870_bl *data = dev_get_drvdata(dev); + unsigned long val; + uint8_t reg_val; + int ret; + + ret = strict_strtoul(buf, 10, &val); + if (ret) + return ret; + + if (val == 0) { + /* Enable automatic ambient light sensing */ + adp8870_set_bits(data->client, ADP8870_MDCR, CMP_AUTOEN); + } else if ((val > 0) && (val < 6)) { + /* Disable automatic ambient light sensing */ + adp8870_clr_bits(data->client, ADP8870_MDCR, CMP_AUTOEN); + + /* Set user supplied ambient light zone */ + mutex_lock(&data->lock); + adp8870_read(data->client, ADP8870_CFGR, ®_val); + reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT); + reg_val |= (val - 1) << CFGR_BLV_SHIFT; + adp8870_write(data->client, ADP8870_CFGR, reg_val); + mutex_unlock(&data->lock); + } + + return count; +} +static DEVICE_ATTR(ambient_light_zone, 0664, + adp8870_bl_ambient_light_zone_show, + adp8870_bl_ambient_light_zone_store); +#endif + +static struct attribute *adp8870_bl_attributes[] = { + &dev_attr_l5_dark_max.attr, + &dev_attr_l5_dark_dim.attr, + &dev_attr_l4_indoor_max.attr, + &dev_attr_l4_indoor_dim.attr, + &dev_attr_l3_office_max.attr, + &dev_attr_l3_office_dim.attr, + &dev_attr_l2_bright_max.attr, + &dev_attr_l2_bright_dim.attr, + &dev_attr_l1_daylight_max.attr, + &dev_attr_l1_daylight_dim.attr, +#ifdef ADP8870_EXT_FEATURES + &dev_attr_ambient_light_level.attr, + &dev_attr_ambient_light_zone.attr, +#endif + NULL +}; + +static const struct attribute_group adp8870_bl_attr_group = { + .attrs = adp8870_bl_attributes, +}; + +static int __devinit adp8870_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct backlight_properties props; + struct backlight_device *bl; + struct adp8870_bl *data; + struct adp8870_backlight_platform_data *pdata = + client->dev.platform_data; + uint8_t reg_val; + int ret; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "SMBUS Byte Data not Supported\n"); + return -EIO; + } + + if (!pdata) { + dev_err(&client->dev, "no platform data?\n"); + return -EINVAL; + } + + ret = adp8870_read(client, ADP8870_MFDVID, ®_val); + if (ret < 0) + return -EIO; + + if (ADP8870_MANID(reg_val) != ADP8870_MANUFID) { + dev_err(&client->dev, "failed to probe\n"); + return -ENODEV; + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + + data->revid = ADP8870_DEVID(reg_val); + data->client = client; + data->pdata = pdata; + data->id = id->driver_data; + data->current_brightness = 0; + i2c_set_clientdata(client, data); + + mutex_init(&data->lock); + + memset(&props, 0, sizeof(props)); + props.type = BACKLIGHT_RAW; + props.max_brightness = props.brightness = ADP8870_MAX_BRIGHTNESS; + bl = backlight_device_register(dev_driver_string(&client->dev), + &client->dev, data, &adp8870_bl_ops, &props); + if (IS_ERR(bl)) { + dev_err(&client->dev, "failed to register backlight\n"); + ret = PTR_ERR(bl); + goto out2; + } + + data->bl = bl; + + if (pdata->en_ambl_sens) + ret = sysfs_create_group(&bl->dev.kobj, + &adp8870_bl_attr_group); + + if (ret) { + dev_err(&client->dev, "failed to register sysfs\n"); + goto out1; + } + + ret = adp8870_bl_setup(bl); + if (ret) { + ret = -EIO; + goto out; + } + + backlight_update_status(bl); + + dev_info(&client->dev, "Rev.%d Backlight\n", data->revid); + + if (pdata->num_leds) + adp8870_led_probe(client); + + return 0; + +out: + if (data->pdata->en_ambl_sens) + sysfs_remove_group(&data->bl->dev.kobj, + &adp8870_bl_attr_group); +out1: + backlight_device_unregister(bl); +out2: + i2c_set_clientdata(client, NULL); + kfree(data); + + return ret; +} + +static int __devexit adp8870_remove(struct i2c_client *client) +{ + struct adp8870_bl *data = i2c_get_clientdata(client); + + adp8870_clr_bits(client, ADP8870_MDCR, NSTBY); + + if (data->led) + adp8870_led_remove(client); + + if (data->pdata->en_ambl_sens) + sysfs_remove_group(&data->bl->dev.kobj, + &adp8870_bl_attr_group); + + backlight_device_unregister(data->bl); + i2c_set_clientdata(client, NULL); + kfree(data); + + return 0; +} + +#ifdef CONFIG_PM +static int adp8870_i2c_suspend(struct i2c_client *client, pm_message_t message) +{ + adp8870_clr_bits(client, ADP8870_MDCR, NSTBY); + + return 0; +} + +static int adp8870_i2c_resume(struct i2c_client *client) +{ + adp8870_set_bits(client, ADP8870_MDCR, NSTBY); + + return 0; +} +#else +#define adp8870_i2c_suspend NULL +#define adp8870_i2c_resume NULL +#endif + +static const struct i2c_device_id adp8870_id[] = { + { "adp8870", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adp8870_id); + +static struct i2c_driver adp8870_driver = { + .driver = { + .name = KBUILD_MODNAME, + }, + .probe = adp8870_probe, + .remove = __devexit_p(adp8870_remove), + .suspend = adp8870_i2c_suspend, + .resume = adp8870_i2c_resume, + .id_table = adp8870_id, +}; + +static int __init adp8870_init(void) +{ + return i2c_add_driver(&adp8870_driver); +} +module_init(adp8870_init); + +static void __exit adp8870_exit(void) +{ + i2c_del_driver(&adp8870_driver); +} +module_exit(adp8870_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_DESCRIPTION("ADP8870 Backlight driver"); +MODULE_ALIAS("platform:adp8870-backlight"); diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index 69c49df..784139a 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c @@ -541,7 +541,7 @@ static int __init efifb_init(void) */ ret = platform_driver_probe(&efifb_driver, efifb_probe); if (ret) { - platform_device_unregister(&efifb_driver); + platform_device_unregister(&efifb_device); return ret; } diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 0352afa..4aecf21 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -235,13 +235,12 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct s3c_fb_win *win = info->par; - struct s3c_fb_pd_win *windata = win->windata; struct s3c_fb *sfb = win->parent; dev_dbg(sfb->dev, "checking parameters\n"); - var->xres_virtual = max((unsigned int)windata->virtual_x, var->xres); - var->yres_virtual = max((unsigned int)windata->virtual_y, var->yres); + var->xres_virtual = max(var->xres_virtual, var->xres); + var->yres_virtual = max(var->yres_virtual, var->yres); if (!s3c_fb_validate_win_bpp(win, var->bits_per_pixel)) { dev_dbg(sfb->dev, "win %d: unsupported bpp %d\n", @@ -558,6 +557,13 @@ static int s3c_fb_set_par(struct fb_info *info) vidosd_set_alpha(win, alpha); vidosd_set_size(win, data); + /* Enable DMA channel for this window */ + if (sfb->variant.has_shadowcon) { + data = readl(sfb->regs + SHADOWCON); + data |= SHADOWCON_CHx_ENABLE(win_no); + writel(data, sfb->regs + SHADOWCON); + } + data = WINCONx_ENWIN; /* note, since we have to round up the bits-per-pixel, we end up @@ -637,13 +643,6 @@ static int s3c_fb_set_par(struct fb_info *info) writel(data, regs + sfb->variant.wincon + (win_no * 4)); writel(0x0, regs + sfb->variant.winmap + (win_no * 4)); - /* Enable DMA channel for this window */ - if (sfb->variant.has_shadowcon) { - data = readl(sfb->regs + SHADOWCON); - data |= SHADOWCON_CHx_ENABLE(win_no); - writel(data, sfb->regs + SHADOWCON); - } - shadow_protect_win(win, 0); return 0; @@ -1487,11 +1486,10 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev) release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res)); - kfree(sfb); - pm_runtime_put_sync(sfb->dev); pm_runtime_disable(sfb->dev); + kfree(sfb); return 0; } diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index 6ae40b6..7d54e2c 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -1127,23 +1127,16 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) struct fb_info *info = hdmi->info; unsigned long parent_rate = 0, hdmi_rate; - /* A device has been plugged in */ - pm_runtime_get_sync(hdmi->dev); - ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate); - if (ret < 0) { - pm_runtime_put(hdmi->dev); + if (ret < 0) goto out; - } hdmi->hp_state = HDMI_HOTPLUG_EDID_DONE; /* Reconfigure the clock */ ret = sh_hdmi_clk_configure(hdmi, hdmi_rate, parent_rate); - if (ret < 0) { - pm_runtime_put(hdmi->dev); + if (ret < 0) goto out; - } msleep(10); sh_hdmi_configure(hdmi); @@ -1191,7 +1184,6 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) fb_set_suspend(hdmi->info, 1); console_unlock(); - pm_runtime_put(hdmi->dev); } out: @@ -1312,7 +1304,7 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&hdmi->edid_work, sh_hdmi_edid_work_fn); pm_runtime_enable(&pdev->dev); - pm_runtime_resume(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); /* Product and revision IDs are 0 in sh-mobile version */ dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n", @@ -1340,7 +1332,7 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) ecodec: free_irq(irq, hdmi); ereqirq: - pm_runtime_suspend(&pdev->dev); + pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); iounmap(hdmi->base); emap: @@ -1377,7 +1369,7 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev) free_irq(irq, hdmi); /* Wait for already scheduled work */ cancel_delayed_work_sync(&hdmi->edid_work); - pm_runtime_suspend(&pdev->dev); + pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); clk_disable(hdmi->hdmi_clk); clk_put(hdmi->hdmi_clk); diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index 00d615d..979d6ee 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig @@ -42,7 +42,7 @@ config W1_MASTER_MXC config W1_MASTER_DS1WM tristate "Maxim DS1WM 1-wire busmaster" - depends on W1 + depends on W1 && GENERIC_HARDIRQS help Say Y here to enable the DS1WM 1-wire driver, such as that in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 553da68..30df85d 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -395,9 +395,9 @@ static void unmask_evtchn(int port) static void xen_irq_init(unsigned irq) { struct irq_info *info; +#ifdef CONFIG_SMP struct irq_desc *desc = irq_to_desc(irq); -#ifdef CONFIG_SMP /* By default all event channels notify CPU#0. */ cpumask_copy(desc->irq_data.affinity, cpumask_of(0)); #endif diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 65ea21a..6e8c15a 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -147,9 +147,15 @@ void __init xen_swiotlb_init(int verbose) { unsigned long bytes; int rc; - - xen_io_tlb_nslabs = (64 * 1024 * 1024 >> IO_TLB_SHIFT); - xen_io_tlb_nslabs = ALIGN(xen_io_tlb_nslabs, IO_TLB_SEGSIZE); + unsigned long nr_tbl; + + nr_tbl = swioltb_nr_tbl(); + if (nr_tbl) + xen_io_tlb_nslabs = nr_tbl; + else { + xen_io_tlb_nslabs = (64 * 1024 * 1024 >> IO_TLB_SHIFT); + xen_io_tlb_nslabs = ALIGN(xen_io_tlb_nslabs, IO_TLB_SEGSIZE); + } bytes = xen_io_tlb_nslabs << IO_TLB_SHIFT; |